Skip to content

Hosted and vendored Bun rewiring silently discards the project's own bun patch (patchedDependencies): fresh frozen installs drop the user's patch with exit 0 #367

Description

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

Summary

Bun has its own patching feature, bun patch <pkg> + bun patch --commit. It records "patchedDependencies": { "left-pad@1.3.0": "patches/left-pad@1.3.0.patch" } in package.json and bun.lock, and applies the patch on every install. When socket-patch rewires that same package (scan --mode hosted, which writes a URL 3-tuple, or scan --mode vendored, which writes a .socket/vendor/... local tarball tuple), Bun stops applying the user's patch. The name@version key no longer matches the non-registry resolution. The command reports success with no warning, the next bun install --frozen-lockfile exits 0, and the installed package carries Socket's patch but not the project's own committed patch.

socket-patch has no handling for patchedDependencies at all: grep -rn patchedDependencies over crates/ and docs/ returns nothing. It doesn't refuse, warn or preserve.

Impact

A project-authored fix, which may be a security fix or a functional one, silently disappears from every fresh install and from CI. Nothing in the envelope, the lock or the install output signals it. Only rollback brings it back: I verified that after rollback --yes a fresh frozen install re-applies the user patch.

Repro (Linux, bun 1.4.2, main f6b7fb9)

mkdir bp && cd bp
printf '{"name":"app","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}\n' > package.json
bun install
bun patch left-pad
echo "// USER-BUN-PATCH" >> node_modules/left-pad/index.js
bun patch --commit node_modules/left-pad        # writes patches/left-pad@1.3.0.patch + patchedDependencies

# control: a fresh frozen install keeps the user patch
#   -> node_modules/left-pad/index.js ends with "// USER-BUN-PATCH"

socket-patch scan --mode hosted --json --yes --api-url <mock> --org test-org --api-token fake   # or --mode vendored
# status "success", redirect.redirected 1, redirect.warnings []

mkdir ../fresh && cp -a package.json bun.lock patches .socket ../fresh/ && cd ../fresh
bun install --frozen-lockfile; echo $?          # 0
grep -c SOCKET-PATCHED node_modules/left-pad/index.js    # 1
grep -c USER-BUN-PATCH node_modules/left-pad/index.js    # 0  <- user's patch gone

bun.lock after the rewrite still lists "patchedDependencies": { "left-pad@1.3.0": "patches/left-pad@1.3.0.patch" }, but the package entry is now ["left-pad@http://…/left-pad-1.3.0.tgz", {}, "sha512-…"] (hosted) or ["left-pad@.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz", {}, "sha512-…"] (vendored). Bun applies neither the patch nor an error.

Binary bun.lockb (saveTextLockfile = false) behaves the same in both modes.

Expected vs actual

  • Expected: rewiring must not silently change what gets installed beyond Socket's patch. Either refuse loudly the way other unsupported lock shapes are refused (for comparison, pnpm's vendored backend refuses a target with patchedDependencies as vendor_lock_entry_unsupported), or carry the user patch forward (re-key patchedDependencies, or fold the patch into the served/vendored tarball) and say so. docs/testing/bun-compatibility.md's claim that the rewrite keeps the meta object and version line verbatim doesn't cover this. It's an unmeasured shape.
  • Actual: success, no warning, user patch dropped on every fresh install.

OS × version (hosted and vendored, text lock)

OS Bun 1.2.23 Bun 1.3.9 Bun 1.3.14 Bun 1.4.2
Linux fail fail fail fail (also bun.lockb)
macOS (macos-latest) fail — fail fail
Windows (windows-latest) fail — fail fail

Releases: 4.0.0 and 3.3.0 behave the same, so it isn't a regression.

Suspect code

  • crates/socket-patch-core/src/patch/redirect/mod.rs:4329 (rewrite_bun_lock) and patch/redirect/bun_binary.rs:19 (rewrite_bun_binary) rewrite the package entry without consulting patchedDependencies.
  • The vendored bun backend under crates/socket-patch-core/src/vendor/bun_lock.rs (classify, check_workspace_compatibility) has no gate for it either.

Probe run (3 OS × bun 1.2.23 / 1.3.14 / 1.4.2, main built on each runner; cases bunpatch-hosted / bunpatch-vendored): https://github.com/SocketDev/socket-patch/actions/runs/36765789215

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