Skip to content

Commit e031120

Browse files
committed
refactor: update security checks in publish command and add tests
Replaced the previous security check implementation with a subprocess call to 'ruff' for better error handling and output. Added tests to verify behavior on security violations, missing 'ruff' installation, and successful publishing with a token. This enhances the reliability and maintainability of the publish process.
1 parent cc38cc8 commit e031120

File tree

2 files changed

+95
-24
lines changed

2 files changed

+95
-24
lines changed

comfy_cli/command/custom_nodes/command.py

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88

99
import typer
1010
from rich import print
11-
from ruff import ConfigurationError
12-
from ruff.__main__ import find_ruff_python_files
13-
from ruff.linter import lint_file
1411
from typing_extensions import Annotated, List
1512

1613
from comfy_cli import logging, tracking, ui, utils
@@ -712,31 +709,21 @@ def publish(
712709
# Run security checks first
713710
typer.echo("Running security checks...")
714711
try:
715-
files = find_ruff_python_files(["."])
716-
settings = {
717-
"select": ["S102", "S307"],
718-
"ignore": [],
719-
"line-length": 88,
720-
}
721-
722-
has_violations = False
723-
for python_file in files:
724-
violations = lint_file(python_file, settings=settings)
725-
if violations:
726-
has_violations = True
727-
for violation in violations:
728-
print(f"[red]{violation}[/red]")
729-
730-
if has_violations:
731-
print("[red]Security issues found. Please fix them before publishing.[/red]")
712+
# Run ruff check with security rules
713+
cmd = ["ruff", "check", ".", "--select", "S102,S307"]
714+
result = subprocess.run(cmd, capture_output=True, text=True)
715+
716+
if result.returncode != 0:
717+
print("[red]Security issues found:[/red]")
718+
print(result.stdout)
732719
raise typer.Exit(code=1)
733720

734-
except ConfigurationError as e:
735-
print(f"[red]Configuration error during security check: {e}[/red]")
736-
# raise typer.Exit(code=1)
721+
except FileNotFoundError:
722+
print("[red]Ruff is not installed. Please install it with 'pip install ruff'[/red]")
723+
raise typer.Exit(code=1)
737724
except Exception as e:
738725
print(f"[red]Error running security check: {e}[/red]")
739-
# raise typer.Exit(code=1)
726+
raise typer.Exit(code=1)
740727

741728
# Prompt for API Key
742729
if not token:
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from unittest.mock import MagicMock, patch
2+
3+
from typer.testing import CliRunner
4+
5+
from comfy_cli.command.custom_nodes.command import app
6+
7+
runner = CliRunner()
8+
9+
10+
def test_publish_fails_on_security_violations():
11+
# Mock subprocess.run to simulate security violations
12+
mock_result = MagicMock()
13+
mock_result.returncode = 1
14+
mock_result.stdout = "S102 Use of exec() detected"
15+
16+
with patch("subprocess.run", return_value=mock_result):
17+
result = runner.invoke(app, ["publish"])
18+
19+
assert result.exit_code == 1
20+
assert "Security issues found" in result.stdout
21+
22+
23+
def test_publish_continues_on_no_security_violations():
24+
# Mock subprocess.run to simulate no violations
25+
mock_result = MagicMock()
26+
mock_result.returncode = 0
27+
mock_result.stdout = ""
28+
29+
with (
30+
patch("subprocess.run", return_value=mock_result),
31+
patch("comfy_cli.command.custom_nodes.command.extract_node_configuration") as mock_extract,
32+
patch("typer.prompt") as mock_prompt,
33+
patch("comfy_cli.command.custom_nodes.command.registry_api.publish_node_version") as mock_publish,
34+
patch("comfy_cli.command.custom_nodes.command.zip_files") as mock_zip,
35+
patch("comfy_cli.command.custom_nodes.command.upload_file_to_signed_url") as mock_upload,
36+
):
37+
# Setup the mocks
38+
mock_extract.return_value = {"name": "test-node"}
39+
mock_prompt.return_value = "test-token"
40+
mock_publish.return_value = MagicMock(signedUrl="https://test.url")
41+
42+
# Run the publish command
43+
_result = runner.invoke(app, ["publish"])
44+
45+
# Verify the publish flow continued
46+
assert mock_extract.called
47+
assert mock_publish.called
48+
assert mock_zip.called
49+
assert mock_upload.called
50+
51+
52+
def test_publish_handles_missing_ruff():
53+
with patch("subprocess.run", side_effect=FileNotFoundError()):
54+
result = runner.invoke(app, ["publish"])
55+
56+
assert result.exit_code == 1
57+
assert "Ruff is not installed" in result.stdout
58+
59+
60+
def test_publish_with_token_option():
61+
# Mock subprocess.run to simulate no violations
62+
mock_result = MagicMock()
63+
mock_result.returncode = 0
64+
mock_result.stdout = ""
65+
66+
with (
67+
patch("subprocess.run", return_value=mock_result),
68+
patch("comfy_cli.command.custom_nodes.command.extract_node_configuration") as mock_extract,
69+
patch("comfy_cli.command.custom_nodes.command.registry_api.publish_node_version") as mock_publish,
70+
patch("comfy_cli.command.custom_nodes.command.zip_files") as mock_zip,
71+
patch("comfy_cli.command.custom_nodes.command.upload_file_to_signed_url") as mock_upload,
72+
):
73+
# Setup the mocks
74+
mock_extract.return_value = {"name": "test-node"}
75+
mock_publish.return_value = MagicMock(signedUrl="https://test.url")
76+
77+
# Run the publish command with token
78+
_result = runner.invoke(app, ["publish", "--token", "test-token"])
79+
80+
# Verify the publish flow worked with provided token
81+
assert mock_extract.called
82+
assert mock_publish.called
83+
assert mock_zip.called
84+
assert mock_upload.called

0 commit comments

Comments
 (0)