Repository navigation
After npm install <pkg>@<other version> moves a vendored npm package off its patched version, scan --prune, vendor --revert, remove and rollback all drift-keep it, so vendor --check stays red and every remedy it names loops #1155
Description
Activity
- addedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:npmnpmnpm
on Oct 8, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Triaged as
priority:p1(npm). This is the re-resolved sibling of the removal cases in #1132 (bun.lockb), #1140 (uv) and #1142 (Pipenv). Those are being fixed in the open PR #1147, which maps a lock entry that left the graph tovendor_lock_entry_removedinstead of drift. #1147 doesn't cover npm, and doesn't cover a live entry whose version changed:npm_lock.rsrevert_one_recordstill warnsvendor_lock_entry_driftedwheneverresolvedleaves the uuid dir, without checking the version. So this needs its own change, ideally reusing the in-use verdict thatvendor --checkalready uses (Discovery::vendor_entry_in_use) so the npm and Bun reverts agree with the check. No open PR addresses it yet; it is eligible to be claimed.
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (shared root cause: the npm-family vendored reverts treat a lock entry that now resolves a different version as drift instead of "the dependency left the graph"). Branch: agent/fix-vendored-reresolved-version-drift. Claim-ID: 2026-10-08T22:21:20Z-6f5c80
Generated by Claude Code
- added a commit that references this issue
on Oct 8, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Draft PR: #1187 (npm and Bun text-lock reverts;
bun.lockbis left for a follow-up after #1147 lands).
Generated by Claude Code
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Re-check from the npm bug-hunt routine (ledger #302): still reproduces on main
16106b1(Linux, npm 10.9.4), and one more shape for #1187 to cover.When the new version also has a patch (mock offers
ms@2.1.2andms@2.1.3): vendoredms@2.1.2, thennpm install ms@2.1.3, thenscan --mode vendored --prune --yes. The scan vendors and wiresms@2.1.3(npm ciinstalls the patched 2.1.3), but it still printsGC: kept 1 drifted vendored entryfor 2.1.2. Its artifact.socket/vendor/npm/<2.1.2 uuid>/and its ledger entry stay, andvendor --checkkeeps exiting 1 withpkg:npm/ms@2.1.2: dependency removed … run socket-patch scan --mode vendored --prune. So upgrading to a version that has its own patch, which is the normal upgrade path, also loops.
Generated by Claude Code
- added a commit that references this issue
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Bun re-check from the Bun bug-hunt routine (ledger #306), main
793edd4, Linux, real Bun, local mock of the patch API (minimist@1.2.2 + left-pad@1.3.0 vendored, thenbun add minimist@1.2.8, thenscan --mode vendored --prune --yes):Bun lock after the upgrade: prune vendor --check1.4.2 bun.lockbGC: reverted 1 vendored entry, minimist uuid dir removedexit 0 1.4.2 text bun.lock(v2)GC: kept 1 drifted vendored entry;vendor --revertalso saysKept 1 drifted package(exit 0)exit 1 ("dependency removed … run scan --mode vendored --prune")So after #1147 the binary
bun.lockbbackend already handles the re-resolved case (its revert now reads an entry that left the graph as removed), and the "bun.lockb follow-up" that #1187 mentions may not be needed. Bun's text-lock backend still loops, as #1187 expects.
Generated by Claude Code
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] pnpm re-check from the pnpm bug-hunt routine (ledger #303). The pnpm vendored backends have the same loop, and draft PR #1187 doesn't touch them (it changes
npm_lock.rs/bun_lock.rsonly).Main
f3c6313, Linux, Node 22, real pnpm installs, local mock of the patch API servingleft-pad@1.3.0. Steps: vendorleft-pad@1.3.0(scan --mode vendored),pnpm install, thenpnpm add -E left-pad@1.2.0(-won the 9.x workspace scaffold), thenrm -rf node_modules && pnpm installso #1197's orphaned.pnpmdir can't interfere, then each command in turn:pnpm lock vendor --checkscan --mode vendored --prunevendor --revertremove pkg:npm/left-pad@1.3.0vendor --checkafter all8.15.9 6.0 (legacy backend) 1 0, gc.keptVendoredEntries0, kept 1 ( partialFailure)1 9.15.9 9.0 1 0, kept 0, kept 1 1 10.34.6 9.0 1 0, kept 0, kept 1 1 11.28.5 9.0 1 0, kept 0, kept 1 1 12.10.1 9.0 1 0, kept (2×) 0, kept 1 1 The ledger entry and
.socket/vendor/npm/<uuid>/stay in every row. A plainscan --mode vendoredkeeps warningvendor_ledger_entry_unwired("runsocket-patch scan --pruneto revert it") on every run.vendor --reverton 12.10.1:vendor_lock_entry_removed | snapshots entry `left-pad@file:.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz` no longer exists; nothing to restore vendor_lock_entry_removed | packages entry `left-pad@file:.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz` no longer exists; nothing to restore vendor_lock_entry_drifted | importer dep `.|left-pad` was re-resolved since vendoring (1.2.0); left alone vendor_revert_kept | lock entries drifted since vendoring; artifacts and ledger entry kept — undo the drift and re-run `vendor --revert` to finishThe
packages/snapshotsentries are already read as removed. Only the importer dependency (.|left-padnow1.2.0) counts as drift, and that alone keeps the entry. Same for the legacy backend's root dependency.One more side effect: the pruning scan still removes the dead
left-pad@1.3.0override frompackage.json, the lock'soverrides:andpnpm-workspace.yaml(deleting the scaffold file), yet reports the entry as kept. The ledger's recorded wiring then no longer matches the files.Suspect code (the same "version changed means drift" check as
npm_lock.rsrevert_one_record):crates/socket-patch-core/src/vendor/pnpm_lock.rs:3107(importer dep) and:3261(snapshot ref)crates/socket-patch-core/src/vendor/pnpm_lock_legacy.rs:1069(root dep) and:1236(dep ref), for pnpm 7/8
A fix for #1155 should cover these too, ideally through the same
vendor_entry_in_useverdict. Not a regression I could bisect (4.0.0 doesn't speak the v5 mock contract). Not probed on macOS/Windows; the logic isn't path-dependent.
Generated by Claude Code
- addedv5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.uxCLI commands, help, diagnostics, output consistency, or actionable recovery instructions.CLI commands, help, diagnostics, output consistency, or actionable recovery instructions.compatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.Public CLI/JSON, saved state, upgrades, or package-manager compatibility.
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actionsv5 release blocker (P1). Normal npm dependency upgrades must not leave vendor --check permanently red with a cleanup command that cannot work. This is ordinary package maintenance, not a stress loop; PR #1187 is pending.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
- added a commit that references this issue
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] The fix PR #1187 is blocked on something outside it. Its own checks pass (build, clippy, unit tests and the other e2e suites). The only red jobs are hosted-e2e, e2e_safety_pnpm and the Bun native compat legs. They fail on every PR because production stopped publishing the free
minimist@1.2.2patch those suites are pinned to (#1293).What a human needs to do:
- Either republish that patch, or repin the live-service suites to another free npm patch, following
docs/testing/hosted-production-e2e.md§ "If a required patch is withdrawn". The agent sandbox can't reachpatches-api.socket.dev, so it can't pick a replacement itself. - Re-approve Fix vendored npm/Bun revert treating an upgrade as drift (#1155) #1187. The existing approval was given on
264b6ff, and four commits landed after it.
Generated by Claude Code
- Either republish that patch, or repin the live-service suites to another free npm patch, following
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions
[agent] Found by the scheduled npm bug-hunt routine (ledger #302).
Summary
Vendor a package, then upgrade or downgrade it with npm (
npm install ms@2.1.3over a vendoredms@2.1.2). The lock entrynode_modules/msnow resolves the new version from the registry, and nothing references.socket/vendor/npm/<uuid>/any more. After that:vendor --checkexits 1:dependency removed: no lockfile resolves pkg:npm/ms@2.1.2 any more (it was upgraded or uninstalled) … run socket-patch scan --mode vendored --prune to revert the vendored entry.scan --mode vendored --pruneexits 0 and reverts nothing.--jsonshowsgc.keptVendoredEntries: ["pkg:npm/ms@2.1.2"]. The human output just says "No patches available" (that's the Humanscan --mode vendored --prunesilently skips the vendored GC when no remaining package has a patch, so annpm uninstalled vendored entry is never reverted (exit 0), while--jsonreverts it andvendor --checkkeeps pointing at that same command #1127 gap; with another patched package still installed it prints the "kept 1 drifted vendored entry … undo the drift" line instead).vendor --revertexits 0:lock entry node_modules/ms was re-resolved since vendoring (now resolved to https://registry.npmjs.org/ms/-/ms-2.1.3.tgz); left aloneandKept 1 drifted package … undo the drift and re-run vendor --revert to finish.remove pkg:npm/ms@2.1.2exits 1:1 matching entry was drift-kept …; re-run scan --mode vendored to normalize, then remove again. Re-running the scan changes nothing.rollback pkg:npm/ms@2.1.2exits 1:Kept vendored state … lockfile wiring drifted.vendor --checkis still 1."Undo the drift" would mean downgrading back to the vulnerable version. The only way out is deleting
.socket/vendor/npm/<uuid>/and editing.socket/vendor/state.jsonby hand.The Bun routine found this first and handed it to the npm ledger. Bun's text and binary locks behave the same. #1132 (Bun
bun.lockbremoval), #1140 (uv) and #1142 (Pipenv) are the per-backend removal variants. On npm, a plainnpm uninstallis reverted correctly (thevendor_lock_entry_removedarm from #665/#689). Only the re-resolved case loops.Impact
Any project that upgrades a vendored dependency (the normal way to drop a patch once upstream ships a fix, and something Dependabot or Renovate does by itself) is left with a committed orphan tarball and a ledger entry.
vendor --checkthen fails CI permanently, and none of the remedies socket-patch suggests can clear it. Nothing is installed unpatched (the new version installs from the registry), so this is a stuck-state / CI-gate bug, not a silent unpatching.Repro (Linux, real npm, local mock of the public patch proxy serving a free patch for ms@2.1.2)
A downgrade (
left-pad1.3.0 →npm install left-pad@1.2.0) behaves the same.Expected vs actual
scan --pruneleg (b) reverts "EVERY ledger entry whose dependency is no longer in the lockfile graph".pkg:npm/ms@2.1.2is no longer in the graph.vendor --check(and the doc comment onunwired_check_failure,crates/socket-patch-cli/src/commands/vendor.rs:396) names "upgraded or uninstalled" andscan --pruneas the fix. So prune, and alsovendor --revert/remove/rollback, should drop the ledger entry and the artifact, leaving the user's upgraded lock entry alone.vendor_lock_entry_drifted, sooutcome.drift_skipped()keeps the artifact and ledger entry. Every command reports "kept", andvendor --checkkeeps sending you to the same prune.Matrix (main
c4235a2, Linux, Node 22.22 / Node 24.21 for npm 12)npm uninstall(control)--jsonprune, this run)(On npm 8 the pre-upgrade
vendor --checkis already red because of #879. That's unrelated.) macOS and Windows weren't probed: the code path is platform-independent lock JSON handling.Not bisected: main's history is grafted, so commit bisects aren't possible. The "upgraded or uninstalled …
--prune" check text came with #970/#1050.Suspect code
crates/socket-patch-core/src/vendor/npm_lock.rs:1209-1231(revert_one_record): when the live entry exists but itsresolvedno longer points into our uuid dir, it always warnsvendor_lock_entry_driftedand returns. It doesn't check whether the live entry still names the vendored version. An entry whoseversiondiffers fromrec.original/rec.new(or, more generally, one thatDiscovery::vendor_entry_in_usealready callsSome(false)) is the same "dependency left the graph" case as the removed arm above it (lines 1189-1197), and should be handled likeLOCK_ENTRY_REMOVED_CODE: nothing to restore, artifact releasable.crates/socket-patch-cli/src/commands/vendor.rsrun_vendor_gc(~4202) then lists the entry underkept, disagreeing with the in-use verdict thatvendor --checkuses.