Skip to content

After bun remove of a vendored package in a bun.lockb project, scan --prune, vendor --revert and remove keep it as "drifted", so vendor --check stays red and its remedy loops #1132

Description

[agent] Found by the scheduled Bun bug-hunt routine (ledger #306).

Summary

In a vendored project that uses a binary bun.lockb, run bun remove <pkg> on a vendored package. No socket-patch command can then clean up its vendored entry:

  • vendor --check exits 1 with dependency removed: no lockfile resolves pkg:npm/minimist@1.2.2 any more … run socket-patch scan --mode vendored --prune to revert the vendored entry (the Fix vendor --check unwired cause and remedy (#900) #970 / Decide vendored-entry liveness through one discovery verdict #1050 message).
  • scan --mode vendored --prune exits 0 but keeps the entry: GC: kept 1 drifted vendored entry: lock entries were re-resolved since vendoring … undo the drift and re-run vendor --revert to finish (keptVendoredEntries: ["pkg:npm/minimist@1.2.2"]).
  • vendor --revert exits 0 with Kept 1 drifted package (vendor_lock_entry_drifted: binary package resolution has drifted).
  • remove pkg:npm/minimist@1.2.2 exits 1 with 1 matching entry was drift-kept …; re-run scan --mode vendored to normalize, then remove again. That re-run changes nothing.

The .socket/vendor/npm/<uuid>/ tarball and its ledger entry stay committed, and vendor --check stays red in CI for good. Only hand-deleting the uuid dir and editing .socket/vendor/state.json gets you out.

On a text bun.lock, and on npm's package-lock.json, the same removal is reverted cleanly: prune prints GC: reverted 1 vendored entry and vendor --check goes back to exit 0. So the defect is specific to the binary lockb backend.

Expected (CLI_CONTRACT.md, vendor --revert, lines 803–807)

in the npm family (npm, yarn classic and berry, pnpm, bun) a recorded lock entry that no longer exists at all — the user removed the dependency — is not drift: it warns vendor_lock_entry_removed … so rollback / remove / scan --prune clean up after npm uninstall / yarn remove / pnpm remove / bun remove

The scan --prune paragraph (line 137, leg (b)) also says: "EVERY ledger entry whose dependency is no longer in the lockfile graph is reverted".

Actual

crates/socket-patch-core/src/vendor/bun_binary.rs:520-527 (revert): when the lock contains neither the rewritten snapshot nor the original for the recorded package ID, the record is reported as vendor_lock_entry_drifted ("binary package resolution has drifted"). There's no "entry no longer exists → vendor_lock_entry_removed, nothing to restore" arm like the one the text backend has (bun_lock.rs, the test around line 3600) and npm has (npm_lock.rs ~3350). outcome.drift_skipped() then keeps the artifact, so run_vendor_gc (commands/vendor.rs ~4290) lists it under kept. Meanwhile Discovery::vendor_entry_in_use correctly returns Some(false), which is why vendor --check sends you to --prune.

Repro (Linux, real Bun, local mock of the patch API with a minimist@1.2.2 patch)

# usage: repro.sh <bun-binary>
BUN=$1; D=$(mktemp -d); cd "$D"; git init -q; echo node_modules/ > .gitignore
printf '[install]\nsaveTextLockfile = false\nlinker = "hoisted"\n' > bunfig.toml
echo '{"name":"proj","version":"1.0.0","dependencies":{"minimist":"1.2.2","left-pad":"1.3.0"}}' > package.json
"$BUN" install && git add -A && git commit -qm init
socket-patch scan --mode vendored            # exit 0, both packages vendored into bun.lockb
"$BUN" install --frozen-lockfile && git add -A && git commit -qm vendored
"$BUN" remove minimist && git add -A && git commit -qm "drop minimist"
socket-patch vendor --check; echo $?         # 1: "dependency removed … run scan --mode vendored --prune"
socket-patch scan --mode vendored --prune    # exit 0: "GC: kept 1 drifted vendored entry …"
socket-patch vendor --check; echo $?         # still 1
socket-patch vendor --revert                 # exit 0: "Kept 1 drifted package"
socket-patch remove pkg:npm/minimist@1.2.2; echo $?   # 1: "drift-kept … re-run scan … then remove again"
ls .socket/vendor/npm/                       # 11111111-… (minimist) still there

(left-pad keeps a patched package in the project, so the scan's GC runs. See #1127 for the case where no patched package remains.)

Matrix (main 9472be4, Linux)

Bun lock shape bun remove → prune / revert / remove vendor --check afterwards
1.1.39 bun.lockb single kept as drifted exit 1
1.2.23 bun.lockb single, workspace member kept as drifted exit 1
1.3.9 bun.lockb single (hoisted + isolated), workspace kept as drifted exit 1
1.4.2 bun.lockb single (hoisted + isolated), workspace (hoisted + isolated) kept as drifted exit 1
1.2.23 / 1.3.9 / 1.4.2 text bun.lock single, workspace (1.4.2) reverted exit 0
npm 10 package-lock.json single reverted exit 0

It reproduced in two separate runs of each lockb cell. macOS and Windows weren't tested: the backend is platform-independent, and no probe branch was available this run.

Related, but not Bun-specific, so it's being handed to the npm routine rather than filed here: when the dependency is upgraded off the patched version (bun add minimist@1.2.8, npm install minimist@1.2.8), every backend (text bun.lock on 1.1.39–1.4.2, bun.lockb, package-lock.json) gives the same loop. vendor --check says "dependency removed … run --prune", and prune keeps the entry as "drifted".

First bad: not bisected. Release 4.0.0 can't vendor against the local mock. The --prune remedy text came with #970 and the shared in-use verdict with #1050, but the lockb revert arm was already there before them.

Suspect code: crates/socket-patch-core/src/vendor/bun_binary.rs:526.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions