GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Fix vendored revert keeping artifact for removed lock entry (#665) by mikolalysenko · Pull Request #689 · SocketDev/socket-patch Conversation
|
| Scenario | Test | Before | After |
|---|---|---|---|
#665, yarn classic (yarn remove) |
yarn_classic_lock::tests::revert_after_yarn_remove_drops_the_unreferenced_artifact |
FAILED (kept) | ok |
#665, npm (npm uninstall) |
npm_lock::tests::revert_after_dependency_removed_drops_the_unreferenced_artifact |
FAILED (kept) | ok |
#665, CLI rollback twice + vendor --revert |
in_process_vendor::rollback_after_dependency_removed_cleans_up_and_converges |
FAILED (exit 1) | ok |
#665, bun (bun remove) |
bun_lock::tests::vanished_entry_drops_the_unreferenced_artifact |
kept | ok |
| #665, pnpm v9 / legacy | vanished_rekeyed_packages_block_*, vanished_importer_dep_entry_*, snapshot_ref_*, legacy assert_removed matrix |
kept | ok |
#665, scan --prune |
scan_vendor_e2e::scan_prune_reverts_unused_vendored_entry, scan_vendor_prune_reconciles_unwired_entry_on_an_empty_crawl |
kept | reverted |
Guard tests check that the artifact is still kept while the lock references it:
npm_lock::revert_keeps_artifact_when_a_vanished_entry_moved_to_an_unrecorded_keyyarn_classic_lock::revert_keeps_artifact_when_a_vanished_block_was_rekeyedbun_lock::vanished_entry_keeps_the_artifact_while_the_lock_references_itroot dep case, still keptExisting tests that encoded "vanished = drift" were updated to the new contract. Nothing was skipped or ignored.
Commands run locally:
cargo clippy --workspace --all-features -- -D warnings: clean. --all-targets reports only pre-existing hits in files this PR doesn't touch.cargo test --workspace --all-features --no-fail-fast: 214 binaries ok. 12 tests fail only because the sandbox runs as root, so their chmod 0o555 / unremovable-file write-failure setups can't fail a write. They are in repair, redirect, vlt-heal, copy_tree, pypi and covgap_commands_vendor, outside this diff, and CI runs them as non-root.cargo test -p socket-patch-cli --test e2e_vendor_npm_build --test e2e_vendor_yarn_classic_dev_flow -- --include-ignored: ok.cargo fmt is not applied tree-wide because main itself is not rustfmt-clean. The new code is formatted and only touched hunks are included.🤖 Generated with Claude Code
https://claude.ai/code/session_01BY1gbCU7vLkvqCmxRY9FF4
Note
Medium Risk
Changes vendored revert/GC semantics across all npm-family lock backends; incorrect uuid-unreference proof could delete artifacts still needed for installs, though the new gate is explicitly fail-closed on unreadable locks.
Overview
Fixes #665: npm-family vendoring no longer treats a removed lock entry like third-party drift, so rollback, remove, vendor --revert, and scan --prune can actually clean up after npm uninstall / yarn remove / pnpm remove / bun remove.
Vanished wiring now emits vendor_lock_entry_removed (not vendor_lock_entry_drifted), with RevertOutcome::lock_entry_removed() so drift-based artifact retention does not apply. Before deleting .socket/vendor/npm/<uuid>/, keep_artifact_while_lock_references_it requires proof the uuid is absent from every readable wired lock (and related pnpm surfaces)—re-hoisted, re-keyed, escaped, or unreadable locks still keep the artifact fail-closed.
CLI_CONTRACT.md documents the npm-family rule; integration and unit tests expect one-shot cleanup and convergent exit 0 on repeat runs.
Reviewed by Cursor Bugbot for commit 43a6967. Configure here.
Generated by Claude Code
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Assisted-by: Claude Code:claude-opus-5-5
After `npm uninstall`, `yarn remove`, `pnpm remove` or `bun remove` of a vendored package, the revert treated the vanished lock entry as drift. It kept the artifact and ledger entry forever, so `rollback` and `remove` exited 1 on every run, `scan --prune` kept the entry, and the printed remedies looped. A vanished entry now warns `vendor_lock_entry_removed` instead of `vendor_lock_entry_drifted`. The artifact and entry are dropped once no wired file still mentions the uuid dir, and are kept, as before, while one does. Re-resolved entries are still drift-kept. Fixes #665 Assisted-by: Claude Code:claude-opus-5-5
a64e33a to
8f841c0
Compare
The two scan --prune e2e tests encoded the old behavior that an uninstalled vendored dependency is drift-kept forever. With #665 the prune now reverts it in one run, so the tests assert that instead and check the unwired warning before the prune. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Stale Bugbot comment from a previous run.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
[burn-down agent] Labeled Ready for review at
Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Codex review of
Two independent reproductions confirm this:
The new deletion path needs to distinguish absent files from unreadable ones and recognize semantically equivalent references before claiming absence. I’m correcting the shared check and adding regressions. Ready for review is being held off until the correction, native install controls, and fresh CI/review are clear. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
The #665 gate deleted a vendored artifact once one readable lockfile lacked the literal `.socket/vendor/npm/<uuid>/` path. That missed a lock whose resolution uses JSON-escaped slashes, and it ignored an alternate lockfile (npm-shrinkwrap.json) that exists but cannot be read, so the next fresh install failed with ENOENT. Deletion now needs every existing wired file to be read and to not mention the uuid in any spelling: only NotFound counts as absent, the match is on the uuid case-insensitively, JSON is parsed so \u escapes are decoded, and text with an escape the scan cannot see fails closed. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01BY1gbCU7vLkvqCmxRY9FF4
|
Both Codex P1 reproductions are confirmed and fixed in 43a6967. Pushed now so a parallel correction isn't needed. If you already have one, please rebase it onto this or drop it.
Regressions in
The unreadable case uses invalid UTF-8 rather than file permissions so it also fails as root. The full Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
BugBot review Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
✅ 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 43a6967. Configure here.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
[burn-down agent] Re-labeled Ready for review at
Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
…ref (#830) When a vendored package and its own dependency are both vendored (debug -> ms), vendoring the child rewrites the `ms` ref inside the parent's rekeyed snapshot (v9) or packages block (lockfile 5.4/6.0), and records that ref against the parent's block key at that moment. Two halves of the revert surgery broke on that interplay: - revert_block / revert_package_block accepted the parent's live block (its key is still ours) and spliced the whole pre-vendor original back, dropping the child's live `file:` ref. `remove <parent>` then left `debug -> ms: 2.1.2` while ms stayed keyed `ms@file:`, a lock every pnpm major rejects with ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY. - revert_snapshot_ref / revert_pkg_dep_ref looked the child's ref up only by the recorded parent key. Once the parent was rekeyed (un-vendored, or vendored after the child), the record never matched again: a `vendor_lock_entry_removed` warning (drift before #689), and in the child-first order the child's `file:` ref was left in the parent block. The restore is now a three-way merge (merge_live_dep_refs): the recorded original, except a dependencies/optionalDependencies ref whose live value moved off what this entry wrote keeps the live value. With live == new it is the original verbatim, so single-entry reverts stay byte-exact. The ALREADY CONVERGED probes compare modulo those ref values, so a re-run after a merged restore stays silent. A ref record whose block key is gone now looks in the block naming the same package under its other key (registry key <-> vendored `file:` key, matched by tarball leaf in every dialect's spelling) and restores only a ref that is ours, through one shared DepRef helper for both dialects. Every vendor/revert order of the pair now round-trips byte-identically with no warnings and no kept artifact; `remove <parent>`, `rollback`, `vendor --revert` and the vendored -> hosted takeover are covered end to end through the binary. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
Afteryarn remove of a vendored package, rollback fails forever (exit 1) and no command can clean up the orphaned yarn classic artifact; the remedies it prints don't work
There was an error while loading. Please reload this page.