Repository navigation
Vendored bun.lockb workspaces write the member-relative tarball mirrors with no .gitignore check, so a *.tgz rule drops them from the commit and fresh frozen installs fail (Bun 1.1.39–1.2.23) or hang (1.3.9) #1116
Description
[agent] Found by the scheduled Bun bug-hunt routine (ledger #306).
Summary
On a bun.lockb workspace, scan --mode vendored commits the patched tarball twice: once at the canonical root artifact .socket/vendor/npm/<uuid>/<name>-<ver>.tgz, and once as a member-relative mirror at packages/<member>/.socket/vendor/npm/<uuid>/<name>-<ver>.tgz (bun_binary.rs:141-144: "Bun 0.5.9–1.3 resolves workspace local tarballs relative to the declaring member").
The #831 fix (#837) protects only the root artifact. It probes git check-ignore on the root uuid dir and writes a <uuid>/.gitignore containing !* there. The member mirrors get neither treatment. So with GitHub's stock Node .gitignore rule *.tgz (or a member-local .gitignore with *.tgz or .socket/), the scan exits 0 with status: success and no warning, but git ignores the mirror (!! packages/a/.socket/) and it never gets committed.
Impact
In every fresh checkout of the committed state, when the member resolves its own copy of the patched package (for example, the root depends on left-pad@1.2.0 and member a on left-pad@1.3.0):
- Bun 1.1.39 / 1.1.45 / 1.2.23:
bun install --frozen-lockfilefails witherror: ENOENT extracting tarball from left-pad. - Bun 1.3.9:
bun install --frozen-lockfilehangs. It was still running after 20 minutes, and it was killed by a 40 stimeouton the re-run. - Bun 1.4.2: the install succeeds, because 1.4 resolves root-relative. But in the clone,
vendor --checkexits 1 (vendor_check_failed,Corrupt { reason: "vendor_workspace_artifact_missing" }) andvexrefuses the patch (vendor_workspace_artifact_missing, exit 1). So the CI gate stays red on every clone.repairrebuilds the mirror, but the mirror is still ignored, so it can never be committed withoutgit add -f.
This affects the same population as #831: the *.tgz rule ships in GitHub's Node.gitignore.
Repro (Linux)
I used a local mock of the patch proxy (SOCKET_PROXY_URL / SOCKET_PATCH_SERVER_URL) that serves left-pad@1.3.0 with /* SOCKET-PATCHED-A */ prepended to index.js.
mkdir -p ws/packages/a && cd ws && git init -q
echo '{"name":"root","private":true,"workspaces":["packages/*"],"dependencies":{"left-pad":"1.2.0"}}' > package.json
echo '{"name":"a","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}' > packages/a/package.json
printf '[install]\nsaveTextLockfile = false\n' > bunfig.toml # bun.lockb (the default on 1.1.x)
printf 'node_modules\n*.tgz\n' > .gitignore
bun install && git add -A && git commit -qm init
socket-patch scan --mode vendored --json # exit 0, status success, no ignore warning
git status --short --ignored # M bun.lockb / ?? .socket/ / !! packages/a/.socket/
git add -A && git commit -qm vendored # the mirror packages/a/.socket/... is not committed
git clone -q . ../fresh && cd ../fresh
bun install --frozen-lockfile # 1.1.39-1.2.23: ENOENT extracting tarball; 1.3.9: hangs
socket-patch vendor --check # (1.4.2) exit 1, vendor_workspace_artifact_missingControl: the same steps without the *.tgz line commit packages/a/.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz, and every version's fresh frozen install gets the patched bytes.
Expected vs actual
- Expected: the same treatment Fix vendored npm-family tarballs dropped by .gitignore (#831) #837 gives the root artifact (CLI_CONTRACT.md
vendor_artifact_gitignored). Where a nested rule can override the ignore (*.tgz), each mirror's<uuid>/dir should get its own!*.gitignore. Where it can't (for example, a member-local.socket/rule), the scan should refuse before any write.vendoris documented as producing a committable.socket/vendor/. - Actual: exit 0 with no warning. The mirror is git-ignored, and fresh checkouts fail, hang, or fail
vendor --check.
Matrix
Linux, main 829d0af. Nested shape: root left-pad@1.2.0, member left-pad@1.3.0, root .gitignore *.tgz. Each cell shows the scan exit / the fresh clone's bun install --frozen-lockfile.
| Bun | *.tgz ignored |
Control (no ignore) |
|---|---|---|
| 1.1.39 | 0 / ENOENT, exit 1 | 0 / patched |
| 1.1.45 | 0 / ENOENT, exit 1 | 0 / patched |
| 1.2.23 | 0 / ENOENT, exit 1 (×2) | 0 / patched |
| 1.3.9 | 0 / hangs (×2) | 0 / patched |
| 1.4.2 | 0 / patched, but vendor --check and vex fail in the clone |
0 / patched, --check ok |
Other ignore shapes on 1.4.2, with a deduped member and a plain workspace:
- Member-local
packages/a/.gitignorewith*.tgzor with.socket/: same result. The scan succeeds, the mirror is ignored, andvendor --checkfails in the clone. - Root
vendor/: correctly refused (the root probe catches it). - In the deduped shape (root and member on the same version), Bun 1.1.39–1.4.2 install fine without the mirror. Only
vendor --check/vexbreak there. - Text
bun.lockworkspaces write no mirror, so they're unaffected.
I haven't run macOS or Windows (git's ignore semantics are the same there). This isn't a regression in the usual sense: release 4.0.0 refused vendored bun.lockb entirely, and the mirrors predate the #837 fix, which simply didn't cover them.
Suspect code
crates/socket-patch-core/src/vendor/bun_binary.rs:141-205: the mirror loop writesroot.join(rel)withatomic_write_bytes_preserving_modeand never asks git whetherrelis ignored. It also writes no<uuid>/.gitignorebeside the mirror.crates/socket-patch-core/src/vendor/npm_common.rs:185-220: thenpm_dir::gitignoredprobe and theUUID_GITIGNOREwrite cover onlycoords.uuid_dir_rel(the root artifact dir).- Related: Vendored yarn classic exits 0 when .gitignore covers the vendored tarball (
*.tgz,vendor/,.socket/), so the commit drops it and every fresh checkout's install fails #831 / Fix vendored npm-family tarballs dropped by .gitignore (#831) #837 (the root artifact), Vendored Maven, Gradle and NuGet artifacts can be git-ignored silently, because only npm checks .gitignore #1061 (the same class for Maven, Gradle and NuGet).
Backlog review — 2026-10-08
Priority: P1 → P2. Ignored mirror tarballs break fresh installs for older binary-lock Bun workspace layouts. Keep the gitignore guard; visible install failure and narrow layout.
Activity
bun: run 31 ledger (#1116, #1101 comment)
mikolalysenko commentedon Oct 8, 2026
[agent] Triaged:
priority:p1(Bun). Confirmed onmain(b96a785): the member-mirror loop incrates/socket-patch-core/src/vendor/bun_binary.rs(~L156-205) writesroot.join(rel)with nonpm_dir::gitignoredprobe and no<uuid>/.gitignore. The #837 guard innpm_common.rs:185-222only coverscoords.uuid_dir_rel. This isn't a duplicate. It's related to #1061 (the same guarantee missing for Maven/Gradle/NuGet), but that needs separate writers, so I'm not clustering them. Not covered by the open Bun PR #1009.Generated by Claude Code
mikolalysenko commentedon Oct 12, 2026
[agent] Re-triage (Bun bug-hunt run 38, ledger #306): this still reproduces on main
4e146dd(after #1279 removed the old vendoring machinery), Linux, using the nested shape and root.gitignore*.tgzfrom the issue body:git status --ignoredbun install --frozen-lockfilevendor --checkbun.lockb)success, no warnings!! packages/a/.socket/ENOENT extracting tarball from left-padbun.lockb)success, no warnings!! packages/a/.socket/Bun 1.4.3 behaves the same as 1.4.2: the install succeeds because it resolves paths from the root, but the CI gate stays red in every clone.
Generated by Claude Code
mikolalysenko commentedon Oct 12, 2026
[agent] Claiming this issue (shared root cause: the bun.lockb member-relative tarball mirrors are written without the git-ignore probe and
<uuid>/.gitignorethe root artifact gets). Branch: agent/fix-bun-lockb-mirror-gitignore. Claim-ID: 2026-10-12T18:21:05Z-285ce2Generated by Claude Code
mikolalysenko commentedon Oct 12, 2026
[agent] Draft PR: #1442
Generated by Claude Code
Keep bun.lockb workspace mirrors committable
Document bun.lockb member mirror ignore checks
Tidy bun mirror ignore checks after review
mikolalysenko commentedon Oct 12, 2026
[agent] #1442 is ready: CI is green on
79c12b6, Bugbot found nothing, and it has an approval. Each bun.lockb member mirror now gets the root artifact's!*<uuid>/.gitignore(on vendor, re-run andrepair). A member uuid dir that git ignores as a directory now refusesvendor_artifact_gitignoredbefore anything is written.Generated by Claude Code