[agent] Found by the scheduled Yarn Berry (2+) bug-hunt routine (ledger #305).
Summary
scan --mode hosted on a yarn 4 project whose package is already vendored takes the package over (vendored → hosted). It reverts the vendored wiring first: the root package.json resolutions entry, the file: lock entry, the committed .socket/vendor/npm/<uuid>/ artifact and the ledger entry. Only after that does the berry hosted rewriter check the grant. When the grant carries a tarball artifact but no yarn-berry-zip yarnBerry10c0 checksum, the rewriter skips the package with redirect_yarn_berry_missing_checksum, and the run ends with:
status: "success", exit 0, redirected: 0, rewrittenFiles: []
- a
redirect_takeover_reverted_vendored warning that says "the project is now fully hosted for this package"
The package is now patched in neither mode. yarn.lock is back to the plain registry entry, .socket/vendor is gone, a fresh yarn install --immutable installs the unpatched registry bytes, and vex fails with manifest_not_found ("no hosted or vendored patch references were found").
A grant like this is a normal shape for the service. Vendored mode only uses the tarball artifact (api/client.rs says "the npm yarn-berry-zip artifact is intentionally ignored here"), so any patch that can be vendored but has no berry zip checksum (yet) triggers this.
Impact
A user switching a vendored berry project to hosted mode silently loses a working security patch, and the run reports success with exit 0, so CI passes. Unlike #369 (the reverse direction, which at least exits 1), nothing fails here.
Repro (Linux, yarn 4.12.0, node-modules linker)
I used a local mock of the patch API: batch, by-package, view, and /patches/package returning a granted tarball artifact with a real sha512. Vendoring works against it.
echo '{"name":"app","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}' > package.json
printf 'nodeLinker: node-modules\nenableGlobalCache: false\n' > .yarnrc.yml
touch yarn.lock && yarn install
API="--api-url http://127.0.0.1:8901 --org org --api-token x --patch-server-url http://127.0.0.1:8901"
socket-patch scan --mode vendored --json --yes $API
# -> success, applied 1; fresh `yarn install --immutable` installs the patched index.js
# mock now returns the same granted uuid with the tarball artifact but yarnBerry10c0: null
socket-patch scan --mode hosted --json --yes $API ; echo exit=$?
Actual:
exit=0
status=success redirect.redirected=0 rewrittenFiles=[]
redirect.warnings = [redirect_yarn_berry_missing_checksum "left-pad@1.3.0 has no yarnBerry10c0 cache checksum",
redirect_takeover_reverted_vendored "pkg:npm/left-pad@1.3.0 was vendored; reverted its vendored wiring, ledger entry, and committed artifact before switching to hosted (mode takeover: the project is now fully hosted for this package)"]
package.json resolutions: gone; .socket/vendor/npm: empty; yarn.lock: 0 __archiveUrl, 0 .socket/vendor entries
fresh checkout `yarn install --immutable` -> node_modules/left-pad/index.js is the UNPATCHED registry file
socket-patch vex -> exit 2, manifest_not_found
Control: with yarnBerry10c0 present, the same takeover redirects 1, and the fresh immutable install gets the patched bytes.
Expected vs actual
- Expected: CLI_CONTRACT.md (the yarn berry line-endings paragraph of the hosted section) says a vendored→hosted takeover refuses before reverting, "so a refused purl keeps its vendored wiring, ledger entry and artifact byte-identical and is skipped with the gate's code (never announced as
redirect_takeover_reverted_vendored and then left unpatched in both modes)". docs/testing/yarn-berry-compatibility.md has the same guarantee in the "mode takeover into this mode" row. The contract also says a dep counts as redirected only when its hosted URL actually lands. A grant the berry rewriter can't use should leave the package vendored, with redirect_yarn_berry_missing_checksum.
- Actual: the takeover preflight only runs the project-level berry gates (
preflight_yarn_berry_hosted: line endings, cacheKey, compressionLevel). The per-dep checksum check runs inside the rewriter, after the vendored state was already deleted.
Matrix
| OS |
yarn |
vendored → hosted, grant without yarnBerry10c0 |
| Linux |
4.0.2 (bare-hex lock) |
fails |
| Linux |
4.12.0 |
fails (reproduced 3 times) |
| Linux |
4.18.1 |
fails |
| Linux |
4.12.0, checksum present (control) |
pass |
| macOS / Windows |
— |
untested (the logic is platform-independent) |
First bad release: not bisected. 4.0.0's vendored mode builds locally from blobs, so this mock doesn't drive it.
Suspect code
crates/socket-patch-cli/src/commands/scan/hosted.rs:1586: berry_takeover_refusal only calls preflight_yarn_berry_hosted. The revert at hosted.rs:1733 (dispatch_revert_one) then runs unconditionally for the berry entry.
crates/socket-patch-core/src/patch/redirect/mod.rs:3295: the redirect_yarn_berry_missing_checksum skip, which happens only inside rewrite_yarn_berry after the revert. The candidate's dep.integrity.yarn_berry10c0 is already known before the takeover loop, so it could be gated there.
[agent] Found by the scheduled Yarn Berry (2+) bug-hunt routine (ledger #305).
Summary
scan --mode hostedon a yarn 4 project whose package is already vendored takes the package over (vendored → hosted). It reverts the vendored wiring first: the rootpackage.jsonresolutionsentry, thefile:lock entry, the committed.socket/vendor/npm/<uuid>/artifact and the ledger entry. Only after that does the berry hosted rewriter check the grant. When the grant carries a tarball artifact but noyarn-berry-zipyarnBerry10c0checksum, the rewriter skips the package withredirect_yarn_berry_missing_checksum, and the run ends with:status: "success", exit 0,redirected: 0,rewrittenFiles: []redirect_takeover_reverted_vendoredwarning that says "the project is now fully hosted for this package"The package is now patched in neither mode.
yarn.lockis back to the plain registry entry,.socket/vendoris gone, a freshyarn install --immutableinstalls the unpatched registry bytes, andvexfails withmanifest_not_found("no hosted or vendored patch references were found").A grant like this is a normal shape for the service. Vendored mode only uses the
tarballartifact (api/client.rssays "the npm yarn-berry-zip artifact is intentionally ignored here"), so any patch that can be vendored but has no berry zip checksum (yet) triggers this.Impact
A user switching a vendored berry project to hosted mode silently loses a working security patch, and the run reports success with exit 0, so CI passes. Unlike #369 (the reverse direction, which at least exits 1), nothing fails here.
Repro (Linux, yarn 4.12.0, node-modules linker)
I used a local mock of the patch API: batch, by-package, view, and
/patches/packagereturning a grantedtarballartifact with a real sha512. Vendoring works against it.Actual:
Control: with
yarnBerry10c0present, the same takeover redirects 1, and the fresh immutable install gets the patched bytes.Expected vs actual
redirect_takeover_reverted_vendoredand then left unpatched in both modes)". docs/testing/yarn-berry-compatibility.md has the same guarantee in the "mode takeover into this mode" row. The contract also says a dep counts as redirected only when its hosted URL actually lands. A grant the berry rewriter can't use should leave the package vendored, withredirect_yarn_berry_missing_checksum.preflight_yarn_berry_hosted: line endings, cacheKey, compressionLevel). The per-dep checksum check runs inside the rewriter, after the vendored state was already deleted.Matrix
yarnBerry10c0First bad release: not bisected. 4.0.0's vendored mode builds locally from blobs, so this mock doesn't drive it.
Suspect code
crates/socket-patch-cli/src/commands/scan/hosted.rs:1586:berry_takeover_refusalonly callspreflight_yarn_berry_hosted. The revert athosted.rs:1733(dispatch_revert_one) then runs unconditionally for the berry entry.crates/socket-patch-core/src/patch/redirect/mod.rs:3295: theredirect_yarn_berry_missing_checksumskip, which happens only insiderewrite_yarn_berryafter the revert. The candidate'sdep.integrity.yarn_berry10c0is already known before the takeover loop, so it could be gated there.