Repository navigation
Fix PyPI revert deleting still-referenced wheel (#996, #867) - #997
Mikola Lysenko (mikolalysenko) wants to merge 10 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Add failing regression tests for a vendored PyPI revert that deletes the vendored wheel while another project file still installs it: - #996: a `uv export`-ed requirements.txt or pylock.toml after a uv project revert, and the same export after a script-lock revert. - #867: a vendored requirements line moved into a `-r` include, or into a sibling requirements file the root does not include. Assisted-by: Claude Code:claude-opus-5-5
A vendored Python revert restored the files it recorded and then deleted .socket/vendor/pypi/<uuid>/ without checking whether any other project file still installs the wheel. A uv-exported requirements.txt or pylock.toml (#996), or a vendor line moved into a -r include or sibling requirements file (#867), was left pointing at a deleted wheel, so every later install failed while the revert reported success. Every wired PyPI revert now runs the same reference probe the unwired guard uses (root requirements.txt and its includes, uv.lock, pylock and script locks, pyproject/hatch/Pipfile and now every root-level *.txt) before deleting. A remaining reference keeps the wheel and the ledger entry with vendor_revert_residual_reference naming the file, and the dry run previews the same keep. Re-running vendor --revert once the file is fixed finishes the cleanup. Assisted-by: Claude Code:claude-opus-5-5
82a409e to
66d2396
Compare
Run the real uv toolchain: vendor six, `uv export` a requirements.txt that names the vendored wheel, and check `vendor --revert` restores the uv pair but keeps the wheel and ledger entry while the export still installs from it. After re-exporting from the restored lock, a second revert removes the artifact (#996). Assisted-by: Claude Code:claude-opus-5-5
main has failed socket-patch-core's lib tests since Gradle support (#646) and the digest helpers (#865) both landed. The guard test production_digests_go_through_the_helpers flags three files #646 added that still hash inline: crawlers/gradle_cache.rs, patch/jvm_jar.rs and patch/sidecars/maven.rs. That breaks test, test-release and coverage on every open PR. Each inline sha1/sha256 call now goes through sha1_hex_of or sha256_hex_of, which compute the same lowercase hex. Behaviour is unchanged. Assisted-by: Claude Code:claude-opus-5-5 (cherry picked from commit 65112a8)
|
BugBot review Generated by Claude Code |
|
[agent] CI note: Generated by Claude Code |
|
[agent] Ready for review at
Generated by Claude Code |
|
bugbot run |
|
[agent] CI note on a4026cc: CodeQL Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit a4026cc. Configure here.
|
[agent] Ready for review at
Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #996
Fixes #867
Summary
A vendored Python
vendor --revert,removeorrollbackrestored the files its ledger entry recorded, then deleted.socket/vendor/pypi/<uuid>/. It never checked whether another project file still installs that wheel. Any such file was left pointing at a deleted wheel, so every later install failed, while the revert reportedsuccessand exit 0.vendor --revert/remove/rollbackdelete the vendored wheel while auv export-ed requirements.txt or pylock.toml still points at it (exit 0), so installs from the exported file fail #996: auv export-edrequirements.txtorpylock.toml(uv project lane and PEP 723 script lane).vendor --revert/removedelete the vendored wheel while a-rinclude still points at it (exit 0), so every laterpip install -r requirements.txtfails #867: a vendored requirements line the user moved into a-rinclude, or into a sibling file such asrequirements-dev.txtthat the root doesn't include.Root cause
revert_pypi_opts(crates/socket-patch-core/src/vendor/pypi.rs) already has a probe for this,unwired_pypi_reference_clause. It reads every Python project file for the uuid dir: the rootrequirements.txtplus its-rincludes,uv.lock,pylock*.toml,*.py.lockwith their scripts, andpyproject.toml,hatch.toml,Pipfile*,poetry.lockandpdm.lock. But it only ran for ledger entries with no wiring. Every wired flavor went straight to deletion:Fix
pypi_reference_clause). It now also reads every root-level*.txt, which covers auv export -otarget and Vendored requirements.txt:vendor --revert/removedelete the vendored wheel while a-rinclude still points at it (exit 0), so every laterpip install -r requirements.txtfails #867's non-included sibling.kept_artifact, so the CLI reportsvendor_revert_kept). It addsvendor_revert_residual_referencenaming the file and the way out: point it back at the registry release or re-export it, then re-runvendor --revert.--dry-runpreviews the same warning. It skips the files the flavor would restore, and per the existingkept_artifactcontract the keep flag itself stays wet-only.revert_keeps_wiring. It refuses a takeover that would also have broken that file.Ported fix: this PR cherry-picks 65112a8 from #878 (route the Gradle digests through
utils::digest). Without it,production_digests_go_through_the_helpersfails onmainand turnstestred on every PR. The commit no-ops once #878 lands.Test evidence
New tests (red on
mainat 3ac5183, green with the fix at 66d2396):vendor::pypi::tests::uv_revert_keeps_artifact_while_export_references_it[])uv export --script)vendor::pypi::tests::script_lock_revert_keeps_artifact_while_export_references_itno residual warning: []-rinclude and non-included siblingvendor::pypi::tests::requirements_revert_keeps_artifact_for_moved_vendor_linevendor_revert_line_drifted, wheel deletede2e_vendor_pypi_build::uv_vendor_revert_keeps_wheel_while_export_references_it(realuv export, two-step revert)Commands run locally:
cargo clippy --workspace --all-features -- -D warnings: clean.rustfmt --checkon the touched files: clean. CI doesn't runcargo fmt, andmainisn't fmt-clean workspace-wide, so I formatted only the touched files.cargo test --workspace --all-features --no-fail-fast: all pass except 12 tests that inject failures withchmod 0o555/read-only dirs (*_write_failure_*,*unremovable*,relax_loop_must_not_traverse_symlinked_root, ...). They fail here only because the sandbox runs as uid 0, which bypasses file permissions. None of them touch the revert path changed here.cargo test -p socket-patch-cli --all-features --test e2e_vendor_pypi_build -- --include-ignored(uv 0.x local): 36 passed, 0 failed.Checklist
vendor --revert/remove/rollbackdelete the vendored wheel while auv export-ed requirements.txt or pylock.toml still points at it (exit 0), so installs from the exported file fail #996:uv_revert_keeps_artifact_while_export_references_it,script_lock_revert_keeps_artifact_while_export_references_it,uv_vendor_revert_keeps_wheel_while_export_references_it(e2e)vendor --revert/removedelete the vendored wheel while a-rinclude still points at it (exit 0), so every laterpip install -r requirements.txtfails #867:requirements_revert_keeps_artifact_for_moved_vendor_line(both the include and the sibling variant)Follow-ups
vendor_artifact_kept/vendor_revert_kepttexts still say "lock entries drifted". The newvendor_revert_residual_referencewarning next to them gives the real reason. Rewording those shared messages is left out to keep this PR focused.requirements/dev.txtthat no-rline reaches) aren't probed.🤖 Generated with Claude Code
https://claude.ai/code/session_016w5DTe9ejKmm3mvdbi8VXE
Note
Medium Risk
Changes shared PyPI revert deletion logic for all flavors; incorrect probing could leave stale vendor dirs or delete wheels still in use, though behavior is fail-closed with explicit warnings.
Overview
PyPI
vendor --revertno longer deletes the vendored wheel when another project file still installs from.socket/vendor/pypi/<uuid>/. After wiring is restored, a shared probe scans locks,requirements.txtand-rincludes, and root-level*.txt(e.g.uv export -o requirements.txtor a sibling likerequirements-dev.txt). If anything still references the uuid path, revert succeeds but keeps the wheel and ledger and emitsvendor_revert_residual_referencenaming the blocking file; a second revert after re-export or fixing that file completes cleanup.The former unwired-only probe is generalized as
pypi_reference_clause(with optionalskipfor dry-run previews).--dry-runsurfaces the same warning without settingkept_artifact. Coverage spans all wired PyPI flavors viarevert_pypi_opts.New unit tests (#996 uv/pylock/script export, #867 moved requirements lines) and an e2e test with real
uv exportand a two-step revert.Reviewed by Cursor Bugbot for commit a4026cc. Configure here.
Generated by Claude Code