Skip to content

Lock inventory ignores a bun.lockb that Bun installs from when bun.lock is a dangling symlink #735

Description

[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.

Kind: bug (the structural fix is one shared predicate). Source: review Part 4.4 ("Is a bun lock present"), register E17.

Problem

socket-patch asks "is the text bun.lock the live lock?" in seven places. They give three different answers for the same tree:

Semantics Sites A dangling bun.lock symlink is
lstat (exists_no_follow) lock inventory lock_inventory/bun.rs#L30-L41, used by [`npm_family.rs#L153-L159`](https://github.com/SocketDev/socket-patch/blob/045d7ec783d788bf3c5a1310724b51e09fb6505d/crates/socket-patch-core/src/vendor/lock_inventory/npm_family.rs#L153-L159)`` and the GC in-use probe npm_flavor.rs#L608-L611; VEX discovery vex/discover/bun.rs#L103 via DiscoverCtx::exists present
Path::exists (follows links) hosted hosted/engine.rs#L255-L263; vendored routing bun_lock.rs#L635-L641; bun_workspace.rs#L17-L23; CLI repair / orphan sweep [`repair.rs#L44`](https://github.com/SocketDev/socket-patch/blob/045d7ec783d788bf3c5a1310724b51e09fb6505d/crates/socket-patch-cli/src/commands/vendored_backend/repair.rs#L44``) absent
is_file (follows, regular files only) package-manager detection pkg_managers.rs#L139 absent

Bun itself follows the link. With Bun 1.3.14, I created a project with only a bun.lockb (saveTextLockfile = false), added bun.lock -> missing-target, removed node_modules and ran bun install --frozen-lockfile: it succeeded from bun.lockb and installed is-number@7.0.0.

socket-patch on the same tree (a unit probe at 045d7ec, run twice, not committed):

inventory_project_diagnosed  entries=[]  unsupported=[]
bun_lock::binary_lock_drives = true     (vendored writes bun.lockb)
hosted::engine::bun_lock_present = false (hosted rewrites bun.lockb)
lock_inventory::bun_text_lock_present = true

Control: with the symlink removed, the inventory returns [("is-number", "7.0.0")].

So the inventory silently loses every package of the lock that Bun actually installs from, with no unsupported diagnostic. Vendored and hosted mode still wire bun.lockb. The consumers that use the inventory then disagree with the writers: scan's lockfile supplement, the in-memory hosted engine's purl set, and VEX ledger liveness. The GC probe vendored_entry_in_use reads the dangling bun.lock, gets None and keeps the entry, which is safe but never resolves.

Symptoms

None filed. The review flagged this as drift (Part 4.4).

Impact

Low likelihood: a dangling bun.lock symlink is rare. But this is the systemic shape the review describes. Each new Bun-aware path picks its own presence predicate, and every one of them is a single exists() call that looks right on its own.

Proposed change

  • Add one predicate, formats::npm::bun_text_lock_drives(view: &ProjectView) -> bool, with Bun's semantics: a bun.lock that resolves to a readable file. Document what a dangling link or a directory means.
  • Route all seven sites through it.
  • Delete bun_text_lock_present{,_in}, hosted::engine::bun_lock_present and bun_lock::binary_lock_drives, and replace the inline join("bun.lock").exists() calls in bun_workspace.rs and repair.rs.
  • VEX discovery may keep lstat for diagnostics, but it must pick the lock through the shared predicate.

Size and scope

About 7 files and under 150 changed production lines. Out of scope: the bun.lockb support tier (E47) and the vlt/bun sibling-lock rules in redirect/vlt.rs.

Acceptance criteria

  • One predicate decides text-vs-binary Bun lock; grep -rn 'join("bun.lock").exists()\|join(BUN_LOCK).exists()' crates/*/src finds no production hit.
  • Regression test: a dangling bun.lock symlink beside a valid bun.lockb, where the inventory, the hosted engine, vendored routing and the GC probe all choose bun.lockb.
  • Regression test: a bun.lock that is a directory is treated the same way.
  • Existing lock_inventory, npm_flavor, bun_lock, bun_binary and hosted::engine tests stay green.

Dependencies

None. Doesn't overlap open #722 (bun inventory of hosted pins) beyond lock_inventory/bun.rs.

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

    agent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)bugSomething isn't workingpm:bunBunpriority:p1

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions