Skip to content

Bun lockfile-only checkouts can't see hosted pins: hosted re-runs never pick up a superseding patch and scan --mode vendored skips the takeover, both reporting success with 0 packages #720

Description

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

Summary

Once a Bun project's lock carries hosted pins (bun.lock URL 3-tuples, or the rewritten bun.lockb records), lockfile-only discovery no longer inventories those packages. In a checkout without node_modules (the usual CI shape, and the one bun-compatibility.md calls lockfile-only), every later scan sees scannedPackages: 0 for them and exits 0 with status: "success":

  • Hosted re-run: when a superseding patch (new uuid) is published, scan --mode hosted reports redirected: 0, updates: 0 and leaves the lock pinned to the old uuid. With node_modules present, the same re-run upgrades (updates: 1). The npm package-lock.json lockfile-only re-run also upgrades.
  • Hosted → vendored takeover: scan --mode vendored reports success with 0 packages and writes nothing, so the project silently stays hosted. socket-patch vendor on the same checkout does take it over (applied 3), and so does scan --mode vendored with node_modules present.

Vendored pins aren't affected: a lockfile-only vendored re-run upgrades to the new uuid through the vendor ledger.

Impact

CI jobs that run socket-patch scan --mode hosted on a fresh checkout (no install) never pick up a superseding patch for a package that is already hosted-pinned. Until somebody runs the scan in a tree with node_modules, the project keeps the superseded patch, and the JSON envelope gives no hint: success, 0 scanned, no warning. The same goes for a requested hosted → vendored migration. Nothing unpatched gets attested, because vex still correctly verifies the old patch, so this is a silent no-op rather than a false attestation.

Repro (Linux, Bun 1.4.2; mock patch API at SOCKET_PROXY_URL / SOCKET_PATCH_SERVER_URL)

mkdir t && cd t
echo '{"name":"t","version":"1.0.0","dependencies":{"left-pad":"1.3.0","is-odd":"3.0.1"}}' > package.json
bun install && rm -rf node_modules            # lockfile-only checkout
socket-patch scan --mode hosted --json        # scannedPackages 3, redirected 3  (ok)
socket-patch scan --mode hosted --json        # scannedPackages 0, redirected 0  (was 3)
# publish a superseding patch for left-pad@1.3.0 (new uuid) on the API, then:
socket-patch scan --mode hosted --json        # success, scanned 0, updates 0; lock still pins the old uuid
socket-patch scan --mode vendored --json      # success, scanned 0; bun.lock unchanged (still hosted)
socket-patch vendor --json                    # applied 3: the takeover works through this path

Control: bun install (populating node_modules), then the same hosted re-run → scanned 3, updates 1, the lock moves to the new uuid, and a fresh frozen install has the new patch's bytes.

Expected vs actual

  • Expected: docs/ecosystems.md says Bun locks are patched "in hosted and vendored modes, including lockfile-only discovery". docs/testing/bun-compatibility.md ("Mode conversion") says scan / get --mode vendored over a hosted bun.lock restores the hosted line and vendors. A re-run should rediscover the hosted pins, as npm lockfile-only does and as Bun does with node_modules.
  • Actual: hosted-pinned packages are invisible to lockfile-only discovery, the run reports success with 0 packages, and the upgrade or takeover silently doesn't happen.

Matrix (Linux, main 045d7ec)

Lock Bun writer Lockfile-only hosted re-run (superseding patch) Lockfile-only scan --mode vendored over hosted Same with node_modules
text v2 1.4.2 fail (0 scanned, old uuid kept) fail (0 scanned, still hosted) pass
text v1 workspace 1.3.14 fail not run not run
bun.lockb 1.1.45 fail fail not run
npm package-lock.json (control) npm pass (updates: 1) pass (vendor applied 3) pass
vendored text lock (control) 1.4.2 pass (lockfile-only vendored re-run upgrades) n/a n/a

Reproduced several times on main and on the published 4.0.0 binary. 3.3.0 predates --mode, so the first bad release is 4.0.0, the first release with hosted mode. It isn't a regression. macOS/Windows weren't probed (the bug is in platform-independent lock parsing).

Suspect code

  • crates/socket-patch-core/src/vendor/lock_inventory/bun.rs:94: text bun.lock inventory keeps only registry 4-tuples. The hosted pin is the URL 3-tuple ["name@http…/name-ver.tgz", {deps}, "sha512-…"], so it is skipped (and its spec "version" is a URL anyway, line 107).
  • crates/socket-patch-core/src/vendor/lock_inventory/bun.rs:61-65: bun.lockb inventory drops records whose version isn't a registry version, which covers the rewritten hosted records.
  • The npm inventory still sees hosted entries because package-lock.json keeps version next to the hosted resolved URL. A Bun hosted 3-tuple could be recognised as a Socket hosted URL and mapped back to name@version (the version is in the URL path), the way vendored tuples are recovered from their ledger.

No probe runs: the sandbox can't delete probe branches yet (see ledger #306), so this is Linux-only evidence.

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