diff --git a/cycode/cli/apps/scan/code_scanner.py b/cycode/cli/apps/scan/code_scanner.py index 724009a5..d3e325f3 100644 --- a/cycode/cli/apps/scan/code_scanner.py +++ b/cycode/cli/apps/scan/code_scanner.py @@ -56,18 +56,19 @@ def scan_disk_files(ctx: typer.Context, paths: tuple[str, ...]) -> None: is_cycodeignore_allowed=is_cycodeignore_allowed_by_scan_config(ctx), ) - # Add entrypoint.cycode file at root path to mark the scan root (only for single path) + # Add entrypoint.cycode file at root path to mark the scan root (only for single path that is a directory) if len(paths) == 1: root_path = paths[0] absolute_root_path = get_absolute_path(root_path) - entrypoint_path = get_path_by_os(os.path.join(absolute_root_path, consts.CYCODE_ENTRYPOINT_FILENAME)) - entrypoint_document = Document( - entrypoint_path, - '', # Empty file content - is_git_diff_format=False, - absolute_path=entrypoint_path, - ) - documents.append(entrypoint_document) + if os.path.isdir(absolute_root_path): + entrypoint_path = get_path_by_os(os.path.join(absolute_root_path, consts.CYCODE_ENTRYPOINT_FILENAME)) + entrypoint_document = Document( + entrypoint_path, + '', # Empty file content + is_git_diff_format=False, + absolute_path=entrypoint_path, + ) + documents.append(entrypoint_document) add_sca_dependencies_tree_documents_if_needed(ctx, scan_type, documents) scan_documents(ctx, documents, get_scan_parameters(ctx, paths)) diff --git a/tests/cli/commands/scan/test_code_scanner.py b/tests/cli/commands/scan/test_code_scanner.py index 0a43f1c1..8a9f60b7 100644 --- a/tests/cli/commands/scan/test_code_scanner.py +++ b/tests/cli/commands/scan/test_code_scanner.py @@ -80,7 +80,9 @@ def test_generate_document() -> None: @patch('cycode.cli.apps.scan.code_scanner.get_relevant_documents') @patch('cycode.cli.apps.scan.code_scanner.scan_documents') @patch('cycode.cli.apps.scan.code_scanner.get_scan_parameters') +@patch('cycode.cli.apps.scan.code_scanner.os.path.isdir') def test_entrypoint_cycode_added_to_documents( + mock_isdir: Mock, mock_get_scan_parameters: Mock, mock_scan_documents: Mock, mock_get_relevant_documents: Mock, @@ -93,6 +95,7 @@ def test_entrypoint_cycode_added_to_documents( 'progress_bar': MagicMock(), } mock_get_scan_parameters.return_value = {} + mock_isdir.return_value = True # Path is a directory mock_documents = [ Document('/test/path/file1.py', 'content1', is_git_diff_format=False), @@ -119,3 +122,43 @@ def test_entrypoint_cycode_added_to_documents( assert entrypoint_doc.content == '' assert entrypoint_doc.is_git_diff_format is False assert normpath(entrypoint_doc.absolute_path) == normpath(entrypoint_doc.path) + + +@patch('cycode.cli.apps.scan.code_scanner.get_relevant_documents') +@patch('cycode.cli.apps.scan.code_scanner.scan_documents') +@patch('cycode.cli.apps.scan.code_scanner.get_scan_parameters') +@patch('cycode.cli.apps.scan.code_scanner.os.path.isdir') +def test_entrypoint_cycode_not_added_for_single_file( + mock_isdir: Mock, + mock_get_scan_parameters: Mock, + mock_scan_documents: Mock, + mock_get_relevant_documents: Mock, +) -> None: + """Test that entrypoint.cycode file is NOT added when path is a single file.""" + # Arrange + mock_ctx = MagicMock() + mock_ctx.obj = { + 'scan_type': consts.SAST_SCAN_TYPE, + 'progress_bar': MagicMock(), + } + mock_get_scan_parameters.return_value = {} + mock_isdir.return_value = False # Path is a file, not a directory + + mock_documents = [ + Document('/test/path/file1.py', 'content1', is_git_diff_format=False), + ] + mock_get_relevant_documents.return_value = mock_documents.copy() + test_path = '/Users/test/file.py' + + # Act + scan_disk_files(mock_ctx, (test_path,)) + + # Assert + call_args = mock_scan_documents.call_args + documents_passed = call_args[0][1] + + # Verify entrypoint document was NOT added + entrypoint_docs = [doc for doc in documents_passed if doc.path.endswith(consts.CYCODE_ENTRYPOINT_FILENAME)] + assert len(entrypoint_docs) == 0 + # Verify only the original documents are present + assert len(documents_passed) == len(mock_documents)