From 0b316edc87316bbcca66bd95f5492ed640b419d3 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 5 Oct 2026 08:41:30 +0300 Subject: [PATCH 1/3] Honor --stop-on-error on cycode scan The scan command stored stop_on_error in the context, then called apply_sca_restore_options_to_context without it. The helper's parameter defaults to False and overwrites ctx.obj['stop_on_error'], so the flag never took effect on `cycode scan`. Pass it through, as `cycode report sbom path` already does, and drop the redundant assignment. Co-Authored-By: Claude Opus 5.5 --- cycode/cli/apps/scan/scan_command.py | 3 +-- tests/cli/commands/scan/test_scan_command.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cycode/cli/apps/scan/scan_command.py b/cycode/cli/apps/scan/scan_command.py index 48c425b9..747cfc69 100644 --- a/cycode/cli/apps/scan/scan_command.py +++ b/cycode/cli/apps/scan/scan_command.py @@ -161,13 +161,12 @@ def scan_command( ctx.obj['show_secret'] = show_secret ctx.obj['soft_fail'] = soft_fail - ctx.obj['stop_on_error'] = stop_on_error ctx.obj['scan_type'] = scan_type ctx.obj['sync'] = sync ctx.obj['severity_threshold'] = severity_threshold ctx.obj['monitor'] = monitor ctx.obj['report'] = report - apply_sca_restore_options_to_context(ctx, no_restore, gradle_all_sub_projects, maven_settings_file) + apply_sca_restore_options_to_context(ctx, no_restore, gradle_all_sub_projects, maven_settings_file, stop_on_error) scan_client = get_scan_cycode_client(ctx) ctx.obj['client'] = scan_client diff --git a/tests/cli/commands/scan/test_scan_command.py b/tests/cli/commands/scan/test_scan_command.py index bb5f363d..9be2bf1b 100644 --- a/tests/cli/commands/scan/test_scan_command.py +++ b/tests/cli/commands/scan/test_scan_command.py @@ -1,4 +1,5 @@ import re +from unittest.mock import patch import click import pytest @@ -47,6 +48,19 @@ def test_single_scan_type_accepted(self) -> None: assert result.exit_code == 0 assert 'Error' not in result.output + @pytest.mark.parametrize(('args', 'expected'), [(['--stop-on-error'], True), ([], False)]) + def test_stop_on_error_kept_in_context(self, args: list, expected: bool) -> None: + captured = {} + + def _capture_ctx_and_stop(ctx: typer.Context) -> None: + captured.update(ctx.obj) + raise typer.Exit(0) + + with patch('cycode.cli.apps.scan.scan_command.get_scan_cycode_client', side_effect=_capture_ctx_and_stop): + CliRunner().invoke(app, ['scan', '-t', 'sca', *args, 'path', '.']) + + assert captured['stop_on_error'] is expected + class TestScanCommandResultCallback: def test_no_issues_no_errors_exits_zero(self) -> None: From 3954cd873ab9922d0f8901d9c4c178926e17ecdb Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 5 Oct 2026 08:48:18 +0300 Subject: [PATCH 2/3] Fix stop-on-error regression test on Python 3.9 The scan package re-exports a scan_command function that shadows the submodule. Python 3.9's mock.patch resolves dotted targets with getattr, so it found the function instead of the module. Patch the module object fetched with importlib.import_module instead. Co-Authored-By: Claude Opus 5.5 --- tests/cli/commands/scan/test_scan_command.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/cli/commands/scan/test_scan_command.py b/tests/cli/commands/scan/test_scan_command.py index 9be2bf1b..879ba462 100644 --- a/tests/cli/commands/scan/test_scan_command.py +++ b/tests/cli/commands/scan/test_scan_command.py @@ -1,3 +1,4 @@ +import importlib import re from unittest.mock import patch @@ -10,6 +11,9 @@ from cycode.cli.apps.scan.scan_command import scan_command_result_callback from cycode.cli.consts import ISSUE_DETECTED_STATUS_CODE, NO_ISSUES_STATUS_CODE, SCAN_ERROR_STATUS_CODE +# The scan package re-exports a function named scan_command, which shadows the submodule on attribute lookup +_scan_command_module = importlib.import_module('cycode.cli.apps.scan.scan_command') + def _strip_ansi(text: str) -> str: return re.sub(r'\x1b\[[0-9;]*[mGKHF]', '', text) @@ -56,7 +60,7 @@ def _capture_ctx_and_stop(ctx: typer.Context) -> None: captured.update(ctx.obj) raise typer.Exit(0) - with patch('cycode.cli.apps.scan.scan_command.get_scan_cycode_client', side_effect=_capture_ctx_and_stop): + with patch.object(_scan_command_module, 'get_scan_cycode_client', side_effect=_capture_ctx_and_stop): CliRunner().invoke(app, ['scan', '-t', 'sca', *args, 'path', '.']) assert captured['stop_on_error'] is expected From c34baf65c2e6bcf91302a8043a2ed7d6096467ae Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 5 Oct 2026 08:57:31 +0300 Subject: [PATCH 3/3] Drop the shadowing comment from the scan command test Co-Authored-By: Claude Opus 5.5 --- tests/cli/commands/scan/test_scan_command.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/cli/commands/scan/test_scan_command.py b/tests/cli/commands/scan/test_scan_command.py index 879ba462..e4df3f37 100644 --- a/tests/cli/commands/scan/test_scan_command.py +++ b/tests/cli/commands/scan/test_scan_command.py @@ -11,7 +11,6 @@ from cycode.cli.apps.scan.scan_command import scan_command_result_callback from cycode.cli.consts import ISSUE_DETECTED_STATUS_CODE, NO_ISSUES_STATUS_CODE, SCAN_ERROR_STATUS_CODE -# The scan package re-exports a function named scan_command, which shadows the submodule on attribute lookup _scan_command_module = importlib.import_module('cycode.cli.apps.scan.scan_command')