Skip to content

Commit 89ec2e4

Browse files
authored
CM-52765 - Fix git mv handling for commit range scans (#343)
1 parent bc03b57 commit 89ec2e4

File tree

4 files changed

+47
-8
lines changed

4 files changed

+47
-8
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ Perform the following steps to install the pre-commit hook:
233233
```yaml
234234
repos:
235235
- repo: https://github.com/cycodehq/cycode-cli
236-
rev: v3.2.0
236+
rev: v3.4.2
237237
hooks:
238238
- id: cycode
239239
stages:
@@ -245,7 +245,7 @@ Perform the following steps to install the pre-commit hook:
245245
```yaml
246246
repos:
247247
- repo: https://github.com/cycodehq/cycode-cli
248-
rev: v3.2.0
248+
rev: v3.4.2
249249
hooks:
250250
- id: cycode
251251
stages:

cycode/cli/apps/scan/commit_range_scanner.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,11 @@ def _scan_secret_pre_commit(ctx: typer.Context, repo_path: str) -> None:
282282
for diff in diff_index:
283283
progress_bar.update(ScanProgressBarSection.PREPARE_LOCAL_FILES)
284284
documents_to_scan.append(
285-
Document(get_path_by_os(get_diff_file_path(diff)), get_diff_file_content(diff), is_git_diff_format=True)
285+
Document(
286+
get_path_by_os(get_diff_file_path(diff, repo=repo)),
287+
get_diff_file_content(diff),
288+
is_git_diff_format=True,
289+
)
286290
)
287291
documents_to_scan = excluder.exclude_irrelevant_documents_to_scan(consts.SECRET_SCAN_TYPE, documents_to_scan)
288292

cycode/cli/files_collector/commit_range_documents.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def collect_commit_range_diff_documents(
8787
for diff in diff_index:
8888
commit_documents_to_scan.append(
8989
Document(
90-
path=get_path_by_os(get_diff_file_path(diff)),
90+
path=get_path_by_os(get_diff_file_path(diff, repo=repo)),
9191
content=get_diff_file_content(diff),
9292
is_git_diff_format=True,
9393
unique_id=commit_id,
@@ -166,7 +166,7 @@ def get_commit_range_modified_documents(
166166
for diff in modified_files_diff:
167167
progress_bar.update(progress_bar_section)
168168

169-
file_path = get_path_by_os(get_diff_file_path(diff))
169+
file_path = get_path_by_os(get_diff_file_path(diff, repo=repo))
170170

171171
diff_documents.append(
172172
Document(
@@ -211,16 +211,24 @@ def parse_pre_receive_input() -> str:
211211
return pre_receive_input.splitlines()[0]
212212

213213

214-
def get_diff_file_path(diff: 'Diff', relative: bool = False) -> Optional[str]:
214+
def get_diff_file_path(diff: 'Diff', relative: bool = False, repo: Optional['Repo'] = None) -> Optional[str]:
215215
if relative:
216216
# relative to the repository root
217217
return diff.b_path if diff.b_path else diff.a_path
218218

219+
# Try blob-based paths first (most reliable when available)
219220
if diff.b_blob:
220221
return diff.b_blob.abspath
221222
if diff.a_blob:
222223
return diff.a_blob.abspath
223224

225+
# Fallback: construct an absolute path from a relative path
226+
# This handles renames and other cases where blobs might be None
227+
if repo and repo.working_tree_dir:
228+
target_path = diff.b_path if diff.b_path else diff.a_path
229+
if target_path:
230+
return os.path.abspath(os.path.join(repo.working_tree_dir, target_path))
231+
224232
return None
225233

226234

@@ -244,7 +252,7 @@ def get_pre_commit_modified_documents(
244252
for diff in diff_index:
245253
progress_bar.update(progress_bar_section)
246254

247-
file_path = get_path_by_os(get_diff_file_path(diff))
255+
file_path = get_path_by_os(get_diff_file_path(diff, repo=repo))
248256

249257
diff_documents.append(
250258
Document(

tests/cli/files_collector/test_commit_range_documents.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
from git import Repo
77

88
from cycode.cli import consts
9-
from cycode.cli.files_collector.commit_range_documents import get_safe_head_reference_for_diff
9+
from cycode.cli.files_collector.commit_range_documents import (
10+
get_diff_file_path,
11+
get_safe_head_reference_for_diff,
12+
)
13+
from cycode.cli.utils.path_utils import get_path_by_os
1014

1115

1216
@contextmanager
@@ -128,3 +132,26 @@ def test_sequential_operations_on_same_repository(self) -> None:
128132
assert head_ref_after == consts.GIT_HEAD_COMMIT_REV
129133
assert len(diff_after) == 1
130134
assert diff_after[0].b_path == 'new.py'
135+
136+
137+
def test_git_mv_pre_commit_scan() -> None:
138+
with temporary_git_repository() as (temp_dir, repo):
139+
newfile_path = os.path.join(temp_dir, 'NEWFILE.txt')
140+
with open(newfile_path, 'w') as f:
141+
f.write('test content')
142+
143+
repo.index.add(['NEWFILE.txt'])
144+
repo.index.commit('init')
145+
146+
# Rename file but don't commit (this is the pre-commit scenario)
147+
renamed_path = os.path.join(temp_dir, 'RENAMED.txt')
148+
os.rename(newfile_path, renamed_path)
149+
repo.index.remove(['NEWFILE.txt'])
150+
repo.index.add(['RENAMED.txt'])
151+
152+
head_ref = get_safe_head_reference_for_diff(repo)
153+
diff_index = repo.index.diff(head_ref, create_patch=True, R=True)
154+
155+
for diff in diff_index:
156+
file_path = get_path_by_os(get_diff_file_path(diff, repo=repo))
157+
assert file_path == renamed_path

0 commit comments

Comments
 (0)