Skip to content

Commit 692c2b8

Browse files
committed
fix: include branch information in scan parameters for repository scans
- Store branch name in context when provided via --branch flag - Include branch in scan_parameters dict sent to backend API - Add test coverage for branch parameter in scan_parameters - Fixes issue where branch_name and branch_id were null in JSON export This ensures that when scanning a specific branch with 'cycode scan repository --branch <branch>', the branch information is properly sent to the backend API so it can populate branch_name and branch_id fields in the detection details.
1 parent 63d06ff commit 692c2b8

File tree

3 files changed

+127
-0
lines changed

3 files changed

+127
-0
lines changed

cycode/cli/apps/scan/repository/repository_command.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ def repository_command(
6767

6868
add_sca_dependencies_tree_documents_if_needed(ctx, scan_type, documents_to_scan)
6969

70+
# Store branch in context so it can be included in scan parameters
71+
if branch:
72+
ctx.obj['branch'] = branch
73+
7074
logger.debug('Found all relevant files for scanning %s', {'path': path, 'branch': branch})
7175
scan_documents(ctx, documents_to_scan, get_scan_parameters(ctx, (str(path),)))
7276
except Exception as e:

cycode/cli/apps/scan/scan_parameters.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,9 @@ def get_scan_parameters(ctx: typer.Context, paths: Optional[tuple[str, ...]] = N
3333
ctx.obj['remote_url'] = remote_url
3434
scan_parameters['remote_url'] = remote_url
3535

36+
# Include branch information if available (for repository scans)
37+
branch = ctx.obj.get('branch')
38+
if branch:
39+
scan_parameters['branch'] = branch
40+
3641
return scan_parameters
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
from unittest.mock import MagicMock, patch
2+
3+
import pytest
4+
5+
from cycode.cli.apps.scan.scan_parameters import _get_default_scan_parameters, get_scan_parameters
6+
7+
8+
@pytest.fixture
9+
def mock_context() -> MagicMock:
10+
"""Create a mock typer.Context for testing."""
11+
ctx = MagicMock()
12+
ctx.obj = {
13+
'monitor': False,
14+
'report': False,
15+
'package-vulnerabilities': True,
16+
'license-compliance': True,
17+
}
18+
ctx.info_name = 'test-command'
19+
return ctx
20+
21+
22+
def test_get_default_scan_parameters(mock_context: MagicMock) -> None:
23+
"""Test that default scan parameters are correctly extracted from context."""
24+
params = _get_default_scan_parameters(mock_context)
25+
26+
assert params['monitor'] is False
27+
assert params['report'] is False
28+
assert params['package_vulnerabilities'] is True
29+
assert params['license_compliance'] is True
30+
assert params['command_type'] == 'test_command' # hyphens replaced with underscores
31+
assert 'aggregation_id' in params
32+
33+
34+
def test_get_scan_parameters_without_paths(mock_context: MagicMock) -> None:
35+
"""Test get_scan_parameters returns only default params when no paths provided."""
36+
params = get_scan_parameters(mock_context)
37+
38+
assert 'paths' not in params
39+
assert 'remote_url' not in params
40+
assert 'branch' not in params
41+
assert params['monitor'] is False
42+
43+
44+
@patch('cycode.cli.apps.scan.scan_parameters.get_remote_url_scan_parameter')
45+
def test_get_scan_parameters_with_paths(mock_get_remote_url: MagicMock, mock_context: MagicMock) -> None:
46+
"""Test get_scan_parameters includes paths and remote_url when paths provided."""
47+
mock_get_remote_url.return_value = 'https://github.com/example/repo.git'
48+
paths = ('/path/to/repo',)
49+
50+
params = get_scan_parameters(mock_context, paths)
51+
52+
assert params['paths'] == paths
53+
assert params['remote_url'] == 'https://github.com/example/repo.git'
54+
assert mock_context.obj['remote_url'] == 'https://github.com/example/repo.git'
55+
56+
57+
@patch('cycode.cli.apps.scan.scan_parameters.get_remote_url_scan_parameter')
58+
def test_get_scan_parameters_includes_branch_when_set(mock_get_remote_url: MagicMock, mock_context: MagicMock) -> None:
59+
"""Test that branch is included in scan_parameters when set in context."""
60+
mock_get_remote_url.return_value = None
61+
mock_context.obj['branch'] = 'feature-branch'
62+
paths = ('/path/to/repo',)
63+
64+
params = get_scan_parameters(mock_context, paths)
65+
66+
assert params['branch'] == 'feature-branch'
67+
68+
69+
@patch('cycode.cli.apps.scan.scan_parameters.get_remote_url_scan_parameter')
70+
def test_get_scan_parameters_excludes_branch_when_not_set(
71+
mock_get_remote_url: MagicMock, mock_context: MagicMock
72+
) -> None:
73+
"""Test that branch is not included in scan_parameters when not set in context."""
74+
mock_get_remote_url.return_value = None
75+
# Ensure branch is not in context
76+
mock_context.obj.pop('branch', None)
77+
paths = ('/path/to/repo',)
78+
79+
params = get_scan_parameters(mock_context, paths)
80+
81+
assert 'branch' not in params
82+
83+
84+
@patch('cycode.cli.apps.scan.scan_parameters.get_remote_url_scan_parameter')
85+
def test_get_scan_parameters_excludes_branch_when_none(mock_get_remote_url: MagicMock, mock_context: MagicMock) -> None:
86+
"""Test that branch is not included when explicitly set to None."""
87+
mock_get_remote_url.return_value = None
88+
mock_context.obj['branch'] = None
89+
paths = ('/path/to/repo',)
90+
91+
params = get_scan_parameters(mock_context, paths)
92+
93+
assert 'branch' not in params
94+
95+
96+
@patch('cycode.cli.apps.scan.scan_parameters.get_remote_url_scan_parameter')
97+
def test_get_scan_parameters_branch_with_various_names(
98+
mock_get_remote_url: MagicMock, mock_context: MagicMock
99+
) -> None:
100+
"""Test branch parameter works with various branch naming conventions."""
101+
mock_get_remote_url.return_value = None
102+
paths = ('/path/to/repo',)
103+
104+
# Test main branch
105+
mock_context.obj['branch'] = 'main'
106+
params = get_scan_parameters(mock_context, paths)
107+
assert params['branch'] == 'main'
108+
109+
# Test feature branch with slashes
110+
mock_context.obj['branch'] = 'feature/add-new-functionality'
111+
params = get_scan_parameters(mock_context, paths)
112+
assert params['branch'] == 'feature/add-new-functionality'
113+
114+
# Test branch with special characters
115+
mock_context.obj['branch'] = 'release-v1.0.0'
116+
params = get_scan_parameters(mock_context, paths)
117+
assert params['branch'] == 'release-v1.0.0'
118+

0 commit comments

Comments
 (0)