Repository navigation
Hosted scan/get run from a yarn classic workspace member still reports success while pinning nothing: the #598 governing-root refusal covers pnpm and cargo only #884
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): Yarn Berry has the same bug on main
9c43dfc.governing_root.rshas no yarn case, so a Berry member with noyarn.lockof its own falls through toredirect_npm_no_lockfile. I'm adding the evidence here rather than filing a duplicate; one ancestor-workspaces-root check would cover both yarns.Layout: root
package.jsonwith"workspaces":["packages/*"]and theyarn.lock, pluspackages/adepending onleft-pad@1.3.0. A local mock patch API serves a grantedyarn-berry-zipartifact (theyarnBerry10c0is bootstrapped with a real yarnfile:install). Every run used--cwd packages/a.yarn linker / layout member scan --mode hosted(×2)member get <uuid> --mode hostedmember scan --mode vendoredfresh yarn install --immutableafter the member runsroot scan (control) 4.0.2 node-modules, hoisted exit 0, 0 packages found exit 0, success, redirected: 0,redirect_npm_no_lockfileexit 0, 0 packages unpatched redirected: 14.0.2 node-modules + nmHoistingLimits: workspaces(member owns its copy)exit 0, success, found 1, redirected: 0,redirect_npm_no_lockfile(both runs)same exit 1 partial_failure(fails closed)unpatched redirected: 14.12.0 hoisted 0 packages fail (as above) 0 packages unpatched redirected: 14.12.0 nmHoistingLimits: workspacesfail (both runs) fail exit 1 unpatched redirected: 14.18.1 hoisted 0 packages fail 0 packages unpatched redirected: 14.18.1 nmHoistingLimits: workspacesfail (both runs) fail exit 1 unpatched redirected: 1; a fresh--immutableloads the patched bytes4.18.1 nodeLinker: pnpm(member'snode_modules/left-padlinks into the root.store)fail not run not run — — Nothing in the tree changes after any member run (
git statusis clean). The human output names npm, not yarn:Summary: 1 package with 1 free patch Switched 0 packages to hosted patches; rewrote 0 files. No patches could be switched to hosted: pkg:npm/left-pad@1.3.0: no lockfile entry pinning it could be rewritten (see the warning below) Warning: No package-lock.json / npm-shrinkwrap.json presentNotes for the fix:
- For Berry,
yarn installworks from any member directory and always uses the rootyarn.lock, so the refusal (or redirect to the root) should trigger on an ancestorpackage.jsonwithworkspaces(array or{packages: [...]}) that holds ayarn.lock. The member doesn't need its ownnode_modulescopy:get <uuid>fails even in the hoisted layout. - A nested separate Berry project (its own
yarn.lock, not listed in the parent'sworkspaces) passed in earlier runs. It's already excluded byOWN_LOCKScontainingyarn.lock; please keep that working. - Yarn 2/3 members would show the same silent success, though hosted refuses those cacheKeys from the root anyway.
Generated by Claude Code
- For Berry,
- added a commit that references this issue
on Oct 5, 2026 mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] Bun bug-hunt routine (ledger #306): the same symptom on Bun workspaces, on main
9c43dfc(Linux).Layout: a root with
"workspaces":["packages/*"]and a single textbun.lockat the root.packages/adepends onleft-pad@1.3.0andpackages/bonleft-pad@1.2.0. Run frompackages/a:Bun linker scan --jsonfrom the member (2 runs each)get <uuid> --mode hostedfrom the memberroot bun.lock1.4.2 isolated (workspace default) exit 0, success,packagesWithPatches: 1,redirected: 0, onlyredirect_npm_no_lockfileexit 0, successunchanged 1.3.9 isolated same same unchanged 1.2.23 isolated ( linker = "isolated")same same unchanged 1.4.2 / 1.3.9 / 1.2.23 hoisted packagesWithPatches: 0(Bun hoists 1.3.0 to the root, so the member has no copy of its own)exit 0, successunchanged On the isolated linker the member's
node_modules/left-padlink resolves to the root'snode_modules/.bun/left-pad@1.3.0/..., so the patch is found but nothing is pinned, and the warning names npm's lockfiles even though abun.locksits at the workspace root. A freshbun install --frozen-lockfilestill installs the upstream bytes. Vendored mode from the member already fails closed (vendor_lockfile_missing, pinned in docs/testing/bun-compatibility.md "Not measured"), so the hosted/vendored split matches the yarn classic case. The Bun ledger used to list this as a known non-bug. Now that #598 refuses the pnpm shape, I've moved it here rather than filing a separate Bun issue. The fix would needgoverning_root.rsto recognize an ancestorworkspacesroot holding abun.lock/bun.lockbas well.
Generated by Claude Code
mikolalysenko commented
on Oct 6, 2026 CollaboratorAuthorMore actions[agent] npm bug-hunt routine (ledger #302): I confirmed the npm workspaces shape that the yarn classic routine handed over. It's the same root cause, so I'm adding it here rather than filing a separate npm issue. For npm the diagnostic is even more misleading: the warning says "No package-lock.json / npm-shrinkwrap.json present" while a
package-lock.jsonsits two directories up, at the workspace root.Tested on main
9c43dfc(Linux, Node 22.22, plus Node 24.21 for npm 12). A local mock patch API served a free patch forpkg:npm/left-pad@1.3.0, with--patch-server-urlpointed at it.Layout: root
package.jsonwith"workspaces":["packages/*"]and"dependencies":{"left-pad":"1.2.0"}.packages/adepends onleft-pad@1.3.0, so npm installs a non-hoisted copy atpackages/a/node_modules/left-pad. The root holds the onlypackage-lock.json.cd packages/a socket-patch scan --json --yes --api-url $MOCK --org o --api-token x --patch-server-url $MOCK # exit 0, status success, packagesWithPatches 1, redirect.redirected 0, warnings [redirect_npm_no_lockfile] socket-patch get 5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d --mode hosted --json --yes ... # exit 0, success, same socket-patch scan --mode vendored --json --yes ... # exit 1, partial_failure (fails closed) cd ../.. && git status --short # clean: the root lock is untouched npm ci # packages/a/node_modules/left-pad/index.js is the upstream bytes
npm (lockfileVersion) member scan(×2)member get <uuid> --mode hostedmember scan --mode vendoredroot lock after fresh npm ciroot scan(control)7.24.2 (v2) fail, fail fail exit 1 unchanged — — 8.19.4 (v2) fail, fail fail exit 1 unchanged — — 10.9.4 (v3) fail, fail fail exit 1 unchanged unpatched redirected: 1(.npmrc+package-lock.json)12.2.0 (v3) fail, fail fail exit 1 unchanged unpatched — 10.9.4, hoisted layout (no copy in the member) exit 0, 0 packages found fail ( found: 1,redirected: 0,redirect_npm_no_lockfile)— unchanged — — 6.14.18 n/a (npm 6 has no workspaces) "fail" means exit 0,
status: success,redirected: 0, and only theredirect_npm_no_lockfilewarning.Note for the fix: npm resolves the governing lock from the nearest ancestor whose
package.jsonworkspacesglobs include the cwd, and it holds the lock there (package-lock.jsonornpm-shrinkwrap.json). So the ancestor-workspaceslookup that the yarn and Bun comments propose would also needpackage-lock.json/npm-shrinkwrap.jsonin its list of root locks. A nested separate npm project with its ownpackage-lock.json(not listed in the parent'sworkspaces) is the documented loud case in the npm ledger and should keep working.
Generated by Claude Code
mikolalysenko commented
on Oct 6, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (shared root cause:
hosted/governing_root.rsrefuses a workspace member only for pnpm and cargo, with no npm, yarn classic, yarn berry or Bun workspace-root case). Branch: agent/fix-npm-family-member-governing-root. Claim-ID: 2026-10-06T00:20:59Z-c867b7
Generated by Claude Code
mikolalysenko commented
on Oct 6, 2026 CollaboratorAuthorMore actions- added 7 commits that reference this issue
on Oct 6, 2026 mikolalysenko commented
on Oct 6, 2026 CollaboratorAuthorMore actions[agent] Yarn classic bug-hunt run 25: there's a second entry point to the same gap, the positional PATH form of hosted
scan. CLI_CONTRACT says each hosted/vendored PATH is scanned "exactly as if it were--cwd", so in a yarn classic workspace whose members have non-hoisted copies,socket-patch scan --mode hosted packages/aandscan --mode hosted 'packages/*'(theapps/*form the contract uses as its example) reportsuccess,redirected: 0with the npm-onlyredirect_npm_no_lockfilefor every member. They exit 0 and leave yarn.lock untouched (Linux, main9c43dfc, yarn 1.7.0 / 1.10.1 / 1.22.22).run_project_dirs(crates/socket-patch-cli/src/commands/scan/mod.rs:1537) only setschild.common.cwd = dir, so PR #901's governing-root refusal will reach this form too. A regression test forscan --mode hosted <member>may still be worth adding beside the--cwdone.
Generated by Claude Code
[agent] Found by the scheduled Yarn classic (1.x) bug-hunt routine (ledger #304).
Summary
Yarn classic keeps one
yarn.lockat the workspace root. A member gets its ownnode_modules/<pkg>copy whenever yarn can't hoist it, for example when two members need different versions or the root usesworkspaces.nohoist. If you runsocket-patch scan(hosted is the default) orget <uuid> --mode hostedfrom that member directory, hosted mode finds the patch for the member's copy. It then reads locks only in the cwd, finds none, rewrites nothing and exits 0 withstatus: "success"andredirected: 0. The only signal isredirect_npm_no_lockfile("no package-lock.json / npm-shrinkwrap.json present"), which names the wrong package manager: theyarn.lockis two directories up.This is the shape of #590, which #598 fixed for pnpm only.
hosted/governing_root.rsnow refuses a pnpm member (redirect_pnpm_lockfile_elsewhere) and a cargo member, but it has no case for a yarn workspace root. Vendored mode in the same directory already fails closed (vendor_lockfile_missing, exit 1), so the two modes still disagree.Impact
get <uuid>asks for it, but nothing is pinned. Exit 0 andsuccesstell CI and users the project is protected.yarn install --frozen-lockfileinstalls the vulnerable upstream bytes intopackages/a/node_modules/left-pad.Repro (Linux, yarn 1.22.22; identical on 1.0.2 / 1.7.0 / 1.10.1)
A local mock patch API serves a free patch for
pkg:npm/left-pad@1.3.0, withSOCKET_PATCH_SERVER_URLpointed at it (the run-18 mock on ledger #304).The
nohoistlayout gives the same result:"workspaces":{"packages":["packages/*"],"nohoist":["**/left-pad"]}with onlyadepending onleft-pad.Human output from the member:
Expected vs actual
redirect_pnpm_lockfile_elsewhere/cargo_manifest_not_workspace_rootrow). The hosted run from a directory with no lock of its own, under an ancestorpackage.jsonwhoseworkspacesincludes it and next to that root'syarn.lock, should refuse with exit 1 before any write and name the directory to run from. Alternatively it could pin through the root lock. Either way, the diagnostic should name yarn, not npm.success, exit 0, nothing pinned, and an npm-only "no package-lock.json" warning.OS × version
get <uuid> --mode hostedvendor_lockfile_missingnohoistlayout)Tested on main
9c43dfc. This isn't a regression: release 4.0.0 (--mode hosted) behaves the same.npm workspaces show the same symptom (npm 10.9.4: a member with a non-hoisted copy → exit 0,
redirected: 0,redirect_npm_no_lockfile). I've handed that shape to the npm routine's ledger rather than filing it twice.Suspect code
crates/socket-patch-core/src/hosted/governing_root.rs:54-82:refusalchecks onlycargo_member_refusalandpnpm_lock_elsewhere, andpnpm_lock_elsewhere(:106) only looks for an ancestorpnpm-workspace.yaml. There's no lookup for an ancestorpackage.jsonworkspacesroot that holds ayarn.lock(or apackage-lock.json).crates/socket-patch-core/src/patch/redirect/mod.rs:945-970then falls through toredirect_npm_no_lockfileand keeps the run a success.Related: #590 / #598 (pnpm, fixed), #417 (cargo), #691 (vendored yarn classic installs run from a member directory).