Skip to content

On Bun ≥ 1.3.5, hosted and vendored rewiring drops Bun's default trust, so install scripts of patched packages (better-sqlite3, esbuild, sharp…) are silently blocked #371

Description

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

Summary

Bun runs dependency lifecycle scripts only for packages in trustedDependencies, plus Bun's built-in default-trusted list (better-sqlite3, esbuild, sharp, bcrypt, @prisma/client, electron, cypress, …). From Bun 1.3.5 on, the default list only applies to packages resolved from the npm registry. When socket-patch rewires one of these packages to a hosted URL tuple (scan --mode hosted) or a .socket/vendor/... local tarball (scan --mode vendored), Bun no longer trusts it. The package's install / postinstall script is skipped, and bun pm untrusted now lists it.

socket-patch reports success with no warning, and bun install --frozen-lockfile exits 0. But the installed package is broken at runtime whenever it needs its install script: native bindings aren't built or downloaded, binaries aren't fetched, and so on.

Impact

  • better-sqlite3@11.10.0: after rewiring, require('better-sqlite3') throws Could not locate the bindings file. The control (same lock, unrewired, fresh frozen install) loads fine.
  • Any default-trusted package whose install script does real work breaks the same way. Nothing in the envelope, the lock or the frozen install's exit code signals it. It shows up only as a runtime crash, typically in CI or production after a fresh install.

Repro (Linux, main f6b7fb9, bun 1.4.2)

mkdir tr && cd tr
printf '{"name":"app","version":"1.0.0","dependencies":{"better-sqlite3":"11.10.0"}}\n' > package.json
bun install
node -e 'require("better-sqlite3")(":memory:");console.log("LOADS")'      # LOADS
socket-patch scan --mode hosted --json --yes --api-url <mock> --org test-org --api-token fake   # or --mode vendored
# status "success", redirect.warnings []
mkdir ../fresh && cp -a package.json bun.lock .socket ../fresh/ && cd ../fresh
bun install --frozen-lockfile; echo $?                                   # 0
node -e 'require("better-sqlite3")(":memory:")'                          # Error: Could not locate the bindings file
bun pm untrusted
#  ./node_modules/better-sqlite3 @http://…/better-sqlite3-11.10.0.tgz
#   » [install]: prebuild-install || node-gyp rebuild --release

The mock serves a patched copy of the real registry tarball: the same files, with a marker prepended to lib/index.js, and the same scripts.

Workaround, which I verified: adding "trustedDependencies": ["better-sqlite3"] to package.json makes the fresh frozen install run the script again, and the module loads.

Expected vs actual

  • Expected: rewiring changes the bytes of the patched package and nothing else. The docs (docs/testing/bun-compatibility.md, "Formats and rewrite behavior") describe the rewrite as keeping the meta object verbatim so the install behaves the same. A package that was trusted before the rewrite should stay trusted, for example by adding it to trustedDependencies (and rollback removing it). At minimum the run should warn that the package's lifecycle scripts will now be blocked.
  • Actual: trust is silently lost and the install scripts don't run.

OS × version (hosted and vendored behave identically)

OS Bun 1.1.45 Bun 1.2.23 Bun 1.3.0 / 1.3.2 / 1.3.4 Bun 1.3.5 Bun 1.3.6 / 1.3.9 / 1.3.14 Bun 1.4.2
Linux (sandbox) pass pass pass fail fail fail
ubuntu-latest — — pass (1.3.4) fail — fail
macos-latest — — pass (1.3.4) fail — fail
windows-latest — — pass (1.3.4) fail — fail

First bad Bun release: 1.3.5 (1.3.4 passes, bisected on Linux and confirmed on all three runner OSes). This is an upstream Bun behaviour change that socket-patch doesn't compensate for. socket-patch release 4.0.0 behaves the same as main.

Suspect code

  • The hosted text and binary rewriters, crates/socket-patch-core/src/patch/redirect/mod.rs:4329 (rewrite_bun_lock) and patch/redirect/bun_binary.rs:19, plus the vendored bun backend (crates/socket-patch-core/src/vendor/bun_lock.rs). None of them looks at the package's scripts or at Bun's default-trust status, or touches trustedDependencies.
  • The real-Bun matrix (scripts/backtest-bun.py) uses --ignore-scripts for every measurement (docs/testing/bun-compatibility.md, "Installer boundaries"), so it can't observe this.

Probe run: https://github.com/SocketDev/socket-patch/actions/runs/36766578001 (3 OS × bun 1.3.4 / 1.3.5 / 1.4.2, main built on each runner).

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