diff --git a/README.md b/README.md index 95f9e309..06d12822 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,7 @@ Perform the following steps to install the pre-commit hook: ```yaml repos: - repo: https://github.com/cycodehq/cycode-cli - rev: v3.2.0 + rev: v3.4.2 hooks: - id: cycode stages: @@ -245,7 +245,7 @@ Perform the following steps to install the pre-commit hook: ```yaml repos: - repo: https://github.com/cycodehq/cycode-cli - rev: v3.2.0 + rev: v3.4.2 hooks: - id: cycode stages: diff --git a/cycode/cli/apps/scan/commit_range_scanner.py b/cycode/cli/apps/scan/commit_range_scanner.py index 390d03a5..3abd2940 100644 --- a/cycode/cli/apps/scan/commit_range_scanner.py +++ b/cycode/cli/apps/scan/commit_range_scanner.py @@ -282,7 +282,11 @@ def _scan_secret_pre_commit(ctx: typer.Context, repo_path: str) -> None: for diff in diff_index: progress_bar.update(ScanProgressBarSection.PREPARE_LOCAL_FILES) documents_to_scan.append( - Document(get_path_by_os(get_diff_file_path(diff)), get_diff_file_content(diff), is_git_diff_format=True) + Document( + get_path_by_os(get_diff_file_path(diff, repo=repo)), + get_diff_file_content(diff), + is_git_diff_format=True, + ) ) documents_to_scan = excluder.exclude_irrelevant_documents_to_scan(consts.SECRET_SCAN_TYPE, documents_to_scan) diff --git a/cycode/cli/files_collector/commit_range_documents.py b/cycode/cli/files_collector/commit_range_documents.py index fa7af193..572d0cc2 100644 --- a/cycode/cli/files_collector/commit_range_documents.py +++ b/cycode/cli/files_collector/commit_range_documents.py @@ -87,7 +87,7 @@ def collect_commit_range_diff_documents( for diff in diff_index: commit_documents_to_scan.append( Document( - path=get_path_by_os(get_diff_file_path(diff)), + path=get_path_by_os(get_diff_file_path(diff, repo=repo)), content=get_diff_file_content(diff), is_git_diff_format=True, unique_id=commit_id, @@ -166,7 +166,7 @@ def get_commit_range_modified_documents( for diff in modified_files_diff: progress_bar.update(progress_bar_section) - file_path = get_path_by_os(get_diff_file_path(diff)) + file_path = get_path_by_os(get_diff_file_path(diff, repo=repo)) diff_documents.append( Document( @@ -211,16 +211,24 @@ def parse_pre_receive_input() -> str: return pre_receive_input.splitlines()[0] -def get_diff_file_path(diff: 'Diff', relative: bool = False) -> Optional[str]: +def get_diff_file_path(diff: 'Diff', relative: bool = False, repo: Optional['Repo'] = None) -> Optional[str]: if relative: # relative to the repository root return diff.b_path if diff.b_path else diff.a_path + # Try blob-based paths first (most reliable when available) if diff.b_blob: return diff.b_blob.abspath if diff.a_blob: return diff.a_blob.abspath + # Fallback: construct an absolute path from a relative path + # This handles renames and other cases where blobs might be None + if repo and repo.working_tree_dir: + target_path = diff.b_path if diff.b_path else diff.a_path + if target_path: + return os.path.abspath(os.path.join(repo.working_tree_dir, target_path)) + return None @@ -244,7 +252,7 @@ def get_pre_commit_modified_documents( for diff in diff_index: progress_bar.update(progress_bar_section) - file_path = get_path_by_os(get_diff_file_path(diff)) + file_path = get_path_by_os(get_diff_file_path(diff, repo=repo)) diff_documents.append( Document( diff --git a/tests/cli/files_collector/test_commit_range_documents.py b/tests/cli/files_collector/test_commit_range_documents.py index 9bf2474f..c51db5ad 100644 --- a/tests/cli/files_collector/test_commit_range_documents.py +++ b/tests/cli/files_collector/test_commit_range_documents.py @@ -6,7 +6,11 @@ from git import Repo from cycode.cli import consts -from cycode.cli.files_collector.commit_range_documents import get_safe_head_reference_for_diff +from cycode.cli.files_collector.commit_range_documents import ( + get_diff_file_path, + get_safe_head_reference_for_diff, +) +from cycode.cli.utils.path_utils import get_path_by_os @contextmanager @@ -128,3 +132,26 @@ def test_sequential_operations_on_same_repository(self) -> None: assert head_ref_after == consts.GIT_HEAD_COMMIT_REV assert len(diff_after) == 1 assert diff_after[0].b_path == 'new.py' + + +def test_git_mv_pre_commit_scan() -> None: + with temporary_git_repository() as (temp_dir, repo): + newfile_path = os.path.join(temp_dir, 'NEWFILE.txt') + with open(newfile_path, 'w') as f: + f.write('test content') + + repo.index.add(['NEWFILE.txt']) + repo.index.commit('init') + + # Rename file but don't commit (this is the pre-commit scenario) + renamed_path = os.path.join(temp_dir, 'RENAMED.txt') + os.rename(newfile_path, renamed_path) + repo.index.remove(['NEWFILE.txt']) + repo.index.add(['RENAMED.txt']) + + head_ref = get_safe_head_reference_for_diff(repo) + diff_index = repo.index.diff(head_ref, create_patch=True, R=True) + + for diff in diff_index: + file_path = get_path_by_os(get_diff_file_path(diff, repo=repo)) + assert file_path == renamed_path