Repository navigation
Keep the commit id in archive names for Windows drive paths - #554
Conversation
omer-roth
left a comment
There was a problem hiding this comment.
Reviewed the branch and ran the touched tests locally — 18 passed. The diagnosis in the description is right, and stripping the drive before joining does restore the commit id. The remaining concern is that the fix is still expressed in terms of the host's path rules, so on a real Windows machine the archive entry keeps backslashes and the server would again fail to read the commit id off the first component. Inline suggestions replace the ntpath helper with one that picks a pathlib pure flavor from the running OS and emits POSIX components — that covers the separator problem, the lost UNC share, and the colon-in-a-POSIX-name false positive in one place.
Four things that have no diff line to hang off:
1. The shared OS constant the suggestions import. There are ~8 ad-hoc platform.system() / sys.platform checks scattered around the codebase today (host_info.py, ides/cursor.py, cycode_client_base.py, …). One constant in cycode/cli/consts.py, which has no imports of its own and is already imported by cyclient:
class OperatingSystem(str, Enum):
WINDOWS = 'windows'
MACOS = 'macos'
LINUX = 'linux'
def _detect_operating_system() -> OperatingSystem:
if sys.platform == 'win32':
return OperatingSystem.WINDOWS
if sys.platform == 'darwin':
return OperatingSystem.MACOS
return OperatingSystem.LINUX
OPERATING_SYSTEM = _detect_operating_system()Migrating the existing call sites onto it is out of scope for this PR.
2. get_path_by_os in cycode/cli/apps/scan/scan_result.py:45 becomes dead weight. It flips the server's / to os.sep immediately before normalize_file_path splits the path apart again. Harmless but confusing once both sides normalize to POSIX — worth dropping the call.
3. The Windows box in the test plan is still unchecked. Given the separator point above, that is the box that decides whether the ticket is actually fixed. The suggested tests exercise the Windows rules on Linux CI by passing the flavor explicitly, which is the gap that let this reach a customer in the first place — but one manual run on Windows is still worth doing before merge.
4. Tests for path_utils now live in two places. concat_unique_id is covered in tests/test_zip_file.py while the new normalization cases sit in tests/cli/utils/test_path_utils_normalize.py. Both sets now exercise the same helper, so one home for them would be easier to keep in sync.
One style note on the suggestions themselves: the docstrings in the diff narrate the incident (used to archive the file as 'C:/repo/file', the server then reported 'C:'). That reads well today and badly in a year — the suggestions keep one line on the contract and leave the story to the commit message.
On Windows the file path of a commit-range document is absolute by drive letter (C:\repo\file), not by a leading separator, so os.path.join(commit_id, path) threw the commit id away. The archive entry became C:/repo/file, the server reported "C:" as the commit id and a drive-less file path, the same file changed in several commits collided in the archive (zipfile "Duplicate name" warning), and the text printer could not match the finding to a document. Strip the drive and the leading separators with ntpath.splitdrive on every OS before joining, and apply the same normalisation when matching the server's file names back to local documents. Reported in support ticket #8417. Co-Authored-By: Claude Fable 5.1 <[email protected]>
Address review: pick the pathlib pure flavor from the running OS instead of running ntpath.splitdrive everywhere, and emit forward-slash components. This keeps the UNC server and share in the entry name so two shares don't collide, stops a colon in a POSIX file name from being read as a drive, and makes the archive naming and the result matching agree without relying on zipfile's separator rewrite or get_path_by_os. Introduce a shared OPERATING_SYSTEM constant in consts (the other platform checks in the codebase are left for a follow-up), and move all path_utils tests into tests/cli/utils/test_path_utils.py, with the Windows cases exercised on POSIX CI by passing the flavor explicitly. Co-Authored-By: Claude Fable 5.1 <[email protected]>
df6065b to
c65958f
Compare
|
Thanks for the thorough review. Applied all five suggestions in c65958f:
One note on the backslash point: Commits are re-signed with GPG. Could you approve the Actions run so the Windows job in |
On Windows, normalize_file_path uses the Windows flavor, where 'x:y/creds.txt' is a drive-relative path and the drive is correctly stripped. Pass the Linux flavor explicitly so the case asserts the same thing on every CI runner. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
Comments resolved |
Summary
Fixes support ticket #8417 (on-prem customer, CLI 3.24.2 on Windows): the pre-push secret scan reported
"commit_id": "C:"with a drive-lessfile_path, and the text output crashed with'NoneType' object has no attribute 'path'.On Windows a commit-range document's path is absolute by drive letter (
C:\repo\file) rather than by a leading separator, soos.path.join(commit_id, path)inconcat_unique_idthrew the commit id away. The archive entry becameC:/repo/file, and from there:C:as the commit id and reported the path without the drive;UserWarning: Duplicate name);mainalready keeps a placeholder document since CM-73654, but still misreports the commit id and path).Changes
path_utils.py: new_strip_path_anchordrops the drive (incl. UNC) and leading separators viantpath.splitdrive, used on every OS.concat_unique_idandnormalize_file_pathboth go through it, so archive naming and result matching agree.test_zip_file.py,test_scan_result.py, and a newtest_path_utils_normalize.py.Test plan
pytest testspasses (one pre-existing, environment-dependent failure intest_codex.py::test_email_from_auth_returns_email, unrelated)ruff check/ruff format --checkcleanInMemoryZip.appendwithC:\Users\...\secret-test.txtfor two commits yields<sha>/Users/.../secret-test.txtentries with no collision-o textand-o json🤖 Generated with Claude Code