Skip to content

After Bun migrates a vendored bun.lockb to bun.lock (bun install --save-text-lockfile), vendor --revert and rollback fail, and a superseding re-vendor drops the pre-vendor original so revert exits 0 with the project still vendored #784

Description

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

Summary

Vendored mode records bun.lockb wiring (kind: bun_lockb_package, file: bun.lockb) in .socket/vendor/state.json. Bun's documented binary → text migration, bun install --save-text-lockfile, deletes bun.lockb and writes bun.lock. The vendored tuples carry over ("pk-a": ["pk-a@.socket/vendor/npm/<uuid>/pk-a-1.0.0.tgz", {}, "sha512-…"]), but socket-patch still treats the entry as a bun.lockb entry. Every unwind path then breaks:

  1. Right after the migration: vendor --revert and rollback exit 1 with revert_failed: "bun.lockb is missing; cannot safely revert the binary lock". scan --mode hosted (the takeover) exits 0 with redirected: 0, redirect_vendored_revert_failed, and the remedy "run socket-patch vendor --revert to clean up". That remedy is the command that just failed. repair and a vendored re-run report success and change nothing. The only way out is git checkout bun.lockb, which undoes the migration.
  2. After a superseding patch (new uuid) is vendored on the migrated lock: the re-vendor rewrites bun.lock (exit 0). Because the previous wiring was a bun.lockb record, carry_forward_wiring can't match it, so the new bun.lock record has original: null and the registry original is lost. vendor --revert then exits 0 with status: success, vendor_lock_entry_drifted ("has no recorded pre-vendor original; left as-is (run bun install to re-resolve it from the registry)"), vendor_artifact_kept and vendor_revert_kept. The lock still pins the vendored tarball, and the advised bun install keeps it, because the lock entry satisfies package.json. The project stays patched with no supported way back.

Hosted mode is fine: a hosted bun.lockb migrated to bun.lock rolls back correctly, because hosted rollback re-derives the record from the registry.

Impact

  • A team that vendored on bun.lockb and then followed Bun's own advice to move to the text lock (Bun ≥ 1.2) can no longer revert, roll back or switch to hosted.
  • Case 1 fails loudly (exit 1), except for the hosted takeover, which exits 0 having done nothing.
  • Case 2 is silent: vendor --revert reports success (exit 0) while the patched artifact stays wired into the lock and installed. The pre-vendor registry tuple is permanently gone from the state.

Repro

Uses a local mock of the patch API and npm registry: the same routes as e2e_redirect_bun_build.rs (patches/batch, by-package, view, package grant, hosted tarball), with the registry on a different origin from SOCKET_PATCH_SERVER_URL. Any vendored-capable patch reproduces it.

# bunfig.toml points [install] registry at the mock registry
echo '{"name":"app","version":"0.0.0","dependencies":{"pk-a":"1.0.0","pk-d":"1.0.0"}}' > package.json
bun-1.1.45 install                          # writes bun.lockb (or Bun ≥1.2 with saveTextLockfile = false)
git add -A && git commit -qm init
socket-patch scan --mode vendored --json --yes      # exit 0, bun.lockb wired
rm -rf node_modules && bun-1.4.2 install --save-text-lockfile   # bun.lockb deleted, bun.lock written with .socket/vendor tuples

# Case 1
socket-patch vendor --revert --json   # exit 1, revert_failed: "bun.lockb is missing; cannot safely revert the binary lock"
socket-patch rollback --json --yes    # exit 1, same
socket-patch scan --mode hosted --json --yes  # exit 0, redirected 0, redirect_vendored_revert_failed → "run `socket-patch vendor --revert`"

# Case 2 (instead of the above): the API now serves a superseding patch (new uuid)
socket-patch scan --mode vendored --json --yes  # exit 0, bun.lock re-pinned to the new uuid; state.json wiring: file bun.lock, original: null
socket-patch vendor --revert --json   # exit 0 "success": vendor_lock_entry_drifted + vendor_artifact_kept + vendor_revert_kept
rm -rf node_modules && bun install    # node_modules/pk-a is still the PATCHED bytes; bun.lock still pins .socket/vendor/…

Expected vs actual

  • Expected: docs/testing/bun-compatibility.md (Binary bun.lockb row) promises "vendor --revert returns the pre-hosted lock", and the vendored section says rollback "restores the original manifest / lock bytes, removes the .socket/vendor state". The vendor state holds everything needed to restore the registry tuple: name, version, the registry resolution and the integrity in the bun_lockb_package original. The text-lock path already restores exactly this shape on a native text lock. If socket-patch must refuse, it should name a remedy that works, and the hosted takeover shouldn't exit 0 with a circular hint. A re-vendor should never discard a recorded original just because the lock changed format.
  • Actual: see above. Revert/rollback exit 1 (case 1), or exit 0 with nothing reverted and the pre-vendor original lost (case 2).

Matrix (Linux, main 045d7ec)

bun.lockb writer migrated by --save-text-lockfile Case 1 (revert / rollback / hosted takeover) Case 2 (re-vendor → revert)
1.1.45 1.2.23 (v1) fail (1 / 1 / 0, nothing done) untested
1.1.45 1.4.2 (v2) fail fail (still patched after bun install)
1.2.23 (saveTextLockfile = false) 1.2.23 / 1.4.2 fail untested
1.2.23 1.3.14 (v1) untested fail
1.4.2 (saveTextLockfile = false) 1.2.23 / 1.4.2 fail fail (1.4.2)
control: text bun.lock from the start, 1.4.2 — n/a pass (revert byte-exact)
control: bun.lockb not migrated, writers 1.1.45 / 1.4.2 — n/a pass (registry bytes after bun install)

macOS/Windows: untested (the code paths are OS-independent).

First bad version: not a regression. Release 4.0.0 refused --mode vendored on bun.lockb (exit 1), so the migration never arose there.

Suspect code

  • crates/socket-patch-core/src/vendor/state.rs:453-473, carry_forward_wiring: an original is carried forward only from a previous record with a matching surface (wiring_surface_matches), so a bun_lockb_package / bun.lockb original never reaches the new bun_lock_package / bun.lock record.
  • crates/socket-patch-core/src/vendor/bun_lock.rs:536: rewriting "our own" vendored tuple records original: None by design, relying on that carry-forward.
  • crates/socket-patch-core/src/vendor/bun_binary.rs:419-426, revert: a missing bun.lockb is a hard failure even when bun.lock now holds the recorded vendored tuples.

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

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions