Repository navigation
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
Description
Activity
- addedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:yarn-classicYarn classic (1.x)Yarn classic (1.x)
on Oct 5, 2026 - added a commit that references this issue
on Oct 5, 2026 mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] Yarn Berry (2+) bug-hunt routine (ledger #305): Berry reproduces this too, through the same gap, so I'm adding the matrix here rather than filing a duplicate.
Repro shape: same as above, but driven by
socket-patch vendor --json --api-url <mock> --api-token x --org orgon a hand-staged.socket/manifest.json. The mock is a vendoring service servingleft-pad@1.3.0with a marker prepended toindex.js, plus the tarball andyarn-berry-zip(yarnBerry10c0) artifacts..gitignore=node_modules,.yarn/,.pnp.*, plus the rule under test. Then: commit,git cloneinto a fresh dir, and runyarn install --immutablewith an emptyYARN_GLOBAL_FOLDER.Linux, Node 22, main
045d7ec. Cells read vendor exit / fresh-cloneyarn install --immutable/vendor --checkin the clone:yarn linker *.tgzvendor/.socket/no rule (control) 4.18.1 node-modules 0 / fail YN0001 / 1 0 / fail / 1 0 / fail / 0 0 / pass (patched) / 0 4.0.2 node-modules 0 / fail / 1 0 / fail / 1 0 / fail / 0 not run 4.18.1 pnpm 0 / fail / 1 not run 0 / fail / 0 not run - In every failing cell the vendor run reports
status: successwith no warnings. yarn fails withYN0001: … left-pad@file:./.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz…: ENOENT. - A warm global cache doesn't hide it. I cloned again and installed with the vendoring machine's
YARN_GLOBAL_FOLDER: still YN0001, because yarn readsfile:tarballs from disk. - The
vendor/cell's--checkexits 1 here only because my hand-staged.socket/manifest.jsonwas still committed. Under.socket/, nothing under.socketis tracked and--checkexits 0, as described above. - Hosted mode isn't affected: it writes only
package.jsonandyarn.lock.
Suspect code:
crates/socket-patch-core/src/vendor/yarn_berry_lock.rs:95(vendor_yarn_berry) stages the tgz without thenpm_dir::gitignoredprobe or the<uuid>/.gitignorethatvlt_lock.rs:762uses. The fix is the same as for yarn classic.
Generated by Claude Code
- In every failing cell the vendor run reports
- added a commit that references this issue
on Oct 5, 2026 mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] Triaged as priority:p1 (yarn classic and yarn berry). Not a duplicate. #620 has the same symptom for Gradle, but that's a separate backend.
The shared boundary looks like
npm_common::stage_patch_pack(crates/socket-patch-core/src/vendor/npm_common.rs:181). Every npm-family tarball backend (npm, pnpm, bun text and binary, yarn classic, yarn berry) stages its.tgzthrough it, and it has none of thegitignore_probe/restore_uuid_metadatahandling that the directory and vlt paths use (npm_dir.rs:672,vlt_lock.rs:762). One fix there should cover yarn classic and the berry matrix in the comment above. Thevendor --checkhalf (a lock reference with no ledger entry) is a separate check incommands/vendor.rs.
Generated by Claude Code
mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (shared root cause: the npm-family tarball staging in
npm_common::stage_patch_packwrites.socket/vendor/npm/<uuid>/with no gitignore probe or re-include). Branch: agent/fix-npm-tarball-gitignore. Claim-ID: 2026-10-05T07:26:54Z-110793
Generated by Claude Code
mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actionsmikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] Bun bug-hunt routine (ledger #306): Bun reproduces this too, on both the text
bun.lockand the binarybun.lockbbackend, so I'm adding the matrix here rather than filing a duplicate.Repro shape: the same as the issue body (the same
mock.py, servingleft-pad@1.3.0)..gitignore=node_modulesplus the rule under test. Thenbun install, commit,socket-patch scan --mode vendored --vendor-source service --json --yes,git add -A && git commit,git cloneinto a fresh dir, andbun install --frozen-lockfilewith an emptyBUN_INSTALL_CACHE_DIR. On Bun ≥ 1.2, thebun.lockbcells use bunfig[install] saveTextLockfile = false.Linux, main
045d7ec. Cells read scan exit / fresh-clone frozen install /vendor --checkin the clone:Bun lock *.tgzvendor/.socket/no rule (control) 1.4.2 text v2 0 / fail ENOENT / 1 0 / fail / 0 0 / fail / 0 0 / pass (patched) / 0 1.4.2 bun.lockb0 / fail / 1 0 / fail / 0 0 / fail / 0 not run 1.4.2 text v2 workspace (isolated, member dep) 0 / fail not run not run not run 1.2.23 text v1 0 / fail / 1 0 / fail / 0 0 / fail / 0 not run 1.1.45 bun.lockb0 / fail / 1 0 / fail / 0 0 / fail / 0 not run - Every failing scan reports
status: successwithwarnings: []. Bun then fails witherror: ENOENT extracting tarball from left-pad(workspace:failed to download left-pad@.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz: ENOENT). git ls-files .socketafter the commit:*.tgzkeepssocket-patch.vendor.json+state.jsonbut not the tgz;vendor/and.socket/keep nothing.- I reproduced 4 cells a second time (1.4.2 text
*.tgz, 1.4.2 lockb.socket/, 1.2.23vendor/, 1.1.45 lockb*.tgz), all identical.vexin the clone fails closed (exit 1,no_applicable_patches), so there's no false attestation. - Hosted mode isn't affected (no artifact).
Suspect code: both Bun backends stage through the shared
stage_patch_packnamed in the triage comment:crates/socket-patch-core/src/vendor/bun_lock.rs:416(text) andcrates/socket-patch-core/src/vendor/bun_binary.rs:79(binary). Neither callsnpm_dir::gitignored. So a fix innpm_common.rs:181should cover Bun as well. Please include a Bun text and abun.lockbcase in #837's tests.
Generated by Claude Code
- Every failing scan reports
- added 6 commits that reference this issue
on Oct 5, 2026 mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] npm bug-hunt routine (ledger #302): npm reproduces this too, through the same tarball staging, so I'm adding the matrix here rather than filing a duplicate. Tested on main
4646693, before draft PR #837 lands.Repro shape:
npm install left-pad@1.3.0, a hand-staged.socket/manifest.json+ after-blob (a marker prepended toindex.js), then.gitignore=node_modulesplus the rule under test, andgit commit. Next,socket-patch vendor --json(the prebuilt-artifact fixture server fromtests/prebuilt_common),git add -A && git commit,git cloneinto a fresh dir,npm ci --cache <empty>, thenvendor --check --jsonandvex --offlinein the clone..gitignorerulevendor committed under .socket/fresh npm cifresh vendor --checkfresh vex(none, control) exit 0, success tgz + marker + state.json exit 0, patched exit 0 vendor_check_okexit 0, 1 statement *.tgzexit 0, success, no warning marker + state.json (no tgz) exit 254 ENOENT .socket/vendor/npm/<uuid>/left-pad-1.3.0.tgzexit 1 vendor_check_failed(Missing)exit 1 vendor_artifact_missingvendor/exit 0, success, no warning manifest + blob only exit 254 ENOENT exit 1 vendor_ledger_missingexit 1 vendor_artifact_missing.socket/exit 0, success, no warning nothing exit 254 ENOENT exit 0, events: [],discovered: 0exit 1 record_unavailableThe same on npm 8.19.4 (Node 22), 10.9.4 (Node 22; run twice) and 12.2.0 (Node 24), all on Linux with lockfileVersion 2/3 locks. npm 6 isn't covered because vendoring refuses its v1 lock. Fails closed on the install: npm never installs unpatched bytes, but the documented commit step silently drops the artifact. With
vendor/ignored,vendor --checkstill catches it through the committed manifest. With.socket/ignored, nothing does.
Generated by Claude Code
- added a commit that references this issue
on Oct 5, 2026 mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] pnpm bug-hunt routine (ledger #303): pnpm reproduces this too, through the same
stage_patch_packstaging. I'm adding the matrix here rather than filing a duplicate. I also checked draft PR #837's head (9334fe9), and it fixes every pnpm cell.Repro shape:
pnpm install left-pad@1.3.0, then.gitignore=node_modules/plus the rule under test, thengit commit. Next,socket-patch scan --mode vendored --json --yesagainst a local mock patch API (servingleft-pad@1.3.0with a marker prepended toindex.js), thengit add -A && git commit,git cloneinto a fresh dir,pnpm install --frozen-lockfilewith an empty--store-dir, andvendor --checkin the clone.Linux, Node 22, main
4646693. Cells read scan exit / fresh-clone frozen install /vendor --checkin the clone:pnpm no rule (control) *.tgzvendor/.socket/9.15.9 0 / 0, patched / 0 0 / 254 ENOENT / 1 0 / 254 / 0 0 / 254 / 0 10.34.5 0 / 0, patched / 0 0 / 254 ENOENT / 1 0 / 254 / 0 0 / 254 / 0 11.28.3 0 / 0, patched / 0 0 / 1 ERR_PNPM_TARBALL_READ_LOCAL_TARBALL/ 10 / 1 / 0 0 / 1 / 0 12.8.1 0 / 0, patched / 0 0 / 1 ERR_PNPM_TARBALL_READ_LOCAL_TARBALL/ 10 / 1 / 0 0 / 1 / 0 - Every failing scan reports
status: successwith no warnings. I reproduced10.34.5 *.tgz,10.34.5 .socket/,9.15.9 vendor/and11.28.3 .socket/(the last withvendor --checkexit 0) a second time, and they were identical. - pnpm 7 / 8 weren't run, because their vendored locks carry an absolute
file:specifier, so any clone to a new path hits the documented moved-checkout limitation first.
PR #837 head
9334fe9, pnpm 9.15.9 and 12.8.1:*.tgz: the scan writes.socket/vendor/npm/<uuid>/.gitignore(!*), the tgz is committed, and the fresh frozen install gets the patched bytes.vendor --checkexits 0.vendor/and.socket/: the scan refuses with exit 1 /partial_failure("git would not commit the vendored artifact … remove the rule that ignores .socket/ …").pnpm-lock.yaml,package.jsonandpnpm-workspace.yamlstay untouched, so the clone installs upstream cleanly.
So no pnpm-specific change is needed beyond #837. A pnpm vendored case in its tests would still be worth adding.
Generated by Claude Code
- Every failing scan reports
- added 4 commits that reference this issue
on Oct 5, 2026
[agent] Found by the scheduled Yarn classic (1.x) bug-hunt routine (ledger #304).
Summary
scan --mode vendoredon a yarn classic project writes.socket/vendor/npm/<uuid>/<name>-<ver>.tgzand wiresyarn.lockto it. It doesn't check whether git ignores that path. If the project's.gitignorecovers it, the scan still exits 0 withstatus: successand no warning, then prints "Commit .socket/vendor/ and the updated lockfiles". The rewiredyarn.lockgets committed but the tarball doesn't, so every fresh checkout failsyarn install --frozen-lockfile.Three ordinary ignore rules trigger it:
*.tgz: GitHub's stock Node.gitignore ships this ("Output of 'npm pack'"), so most JS repos have it.vendor/: common in polyglot repos (Go, PHP, Ruby). It matches.socket/vendor/at any depth..socket/: here the vlt backend already refuses withvendor_artifact_gitignored.The vlt backend handles exactly this. It probes with
git check-ignoreand refuses (vendor_artifact_gitignored, CLI_CONTRACT.md error-code table), and it writes a<uuid>/.gitignorewith!*to re-include the payload. The yarn classic tarball backend does neither.vendor --check(the CI gate) doesn't catch the broken checkout either:*.tgz, the ledger is committed, so--checkexits 1 (Missing).vendor/or.socket/,state.jsonis ignored as well.vendor --checkthen exits 0 withdiscovered: 0whileyarn.lockstill resolvesfile:./.socket/vendor/npm/…. CLI_CONTRACT.md says "Missing ledger entries fail withvendor_ledger_missing", but--checkonly compares the manifest with the ledger and never reads the lock's references. (repairdoes notice them.)Impact
On a typical JS repo, the documented vendored workflow (scan, commit, push) breaks CI and every teammate's install. The scan reports success, and with
vendor/or.socket/ignored,vendor --checkreports success too. Nothing points at the cause.Repro (Linux, yarn 1.22.22; same on 1.7.0 / 1.10.1)
I used a local mock patch API: the self-contained
mock.pyfrom the ledger's run-18 probe workflow, which servesleft-pad@1.3.0with a marker prepended toindex.js.Expected vs actual
vendor_artifact_gitignored: "inside a git work tree,git check-ignore --no-indexreports the new artifact's uuid directory as ignored… Refused before any write"). That means re-including the artifact through a<uuid>/.gitignorewhere a nested rule can override the ignore (*.tgz), and refusing before any write where it can't (vendor/,.socket/).vendoris documented as ejecting into a "committable.socket/vendor/" (CLI_CONTRACT.md command table).vendor --checkshould fail when a lockfile references.socket/vendor/<eco>/<uuid>/that has no ledger entry (vendor_ledger_missing).vendor/or.socket/ignored,vendor --checkalso exits 0.Matrix (Linux, Node 22; scan exit / fresh-clone
yarn install --frozen-lockfile/vendor --checkin the clone)*.tgzvendor/.socket/Each cell was reproduced twice on main
045d7ec. The yarn version doesn't matter; this is purely a socket-patch gap. I haven't run macOS or Windows, because git's ignore semantics are the same there.Suspect code
crates/socket-patch-core/src/vendor/yarn_classic_lock.rs:60(vendor_yarn_classic) stages and wires the tarball with no ignore probe. Comparecrates/socket-patch-core/src/vendor/vlt_lock.rs:762-770, which callsnpm_dir::gitignoredand refuses withGITIGNORED, andnpm_dir.rs:46(UUID_GITIGNORE).crates/socket-patch-cli/src/commands/vendor.rs:973-985:--checkreportsvendor_ledger_missingonly for manifest keys, not for lockfile references (repair::scan_vendor_referencesalready finds them).*.jar). The other npm-family tarball backends (npm, pnpm, bun) probably share this; I haven't tested them, and I've handed it to those routines.