[agent] Found by the scheduled Yarn Berry (2+) bug-hunt routine (ledger #305).
Summary
Running socket-patch vendor on a yarn 4 project where the purl is already hosted-redirected takes over the purl (hosted → vendored). It first reverts the hosted yarn.lock edit and drops the redirect-ledger record (vendor_takeover_reverted_redirect). Only then does the berry backend run its per-package gates. When one of those gates refuses, the command exits 1. Here the refusal is vendor_override_conflict because the lock also resolves another version of the same name, which a name-keyed resolutions entry would move. The purl is then patched in neither mode: the lock is byte-identical to the pre-hosted registry lock, and the next install fetches the unpatched registry tarball.
The berry takeover preflight (yarn_berry_vendor_preflight) only covers project-level gates (line endings, cacheKey, compressionLevel). The per-target gates in scan_berry_target (another version of the name, a patch:/workspace:/portal: entry, an entry mixing descriptors, duplicate entries) and in resolutions_gate (a user-authored resolutions override) all run after the hosted revert.
Impact
A user who switches from hosted to vendored mode silently loses a working security patch, and the lock goes back to the unpatched registry entry. The run does exit 1, but the failure message only describes the vendor refusal. Nothing says the hosted redirect was already removed. The skipped event with vendor_takeover_reverted_redirect is the only trace, and a follow-up vex reports no_applicable_patches.
Repro (Linux, yarn 4.12.0)
The self-contained script is in the probe workflow linked below (probe.sh, case B-takeover).
# root depends on left-pad 1.3.0, a workspace member on left-pad 1.1.3
echo '{"name":"app","version":"1.0.0","private":true,"workspaces":["pkgs/*"],"dependencies":{"left-pad":"1.3.0"}}' > package.json
mkdir -p pkgs/a && echo '{"name":"a","version":"1.0.0","dependencies":{"left-pad":"1.1.3"}}' > pkgs/a/package.json
printf 'nodeLinker: node-modules\nenableGlobalCache: false\nunsafeHttpWhitelist:\n - "127.0.0.1"\n' > .yarnrc.yml
touch yarn.lock && yarn install
socket-patch scan --mode hosted --json --yes --api-url <mock> --org test-org --api-token fake
# -> success, redirected 1; fresh `yarn install --immutable` installs the patched [email protected] (hosted works)
# stage .socket/manifest.json + blob for pkg:npm/[email protected], then:
socket-patch vendor --json --offline
Actual:
vendor exit=1 partialFailure
events: [('skipped', 'vendor_takeover_reverted_redirect'),
('failed', 'vendor_override_conflict')] # "yarn.lock also resolves [email protected] … refusing"
archiveUrl entries in yarn.lock after vendor: 0
yarn.lock == the pre-hosted registry lock: yes
fresh `yarn install --immutable` -> node_modules/left-pad/index.js is the UNPATCHED registry file
socket-patch vex -> no_applicable_patches
Expected vs actual
- Expected: docs/testing/yarn-berry-compatibility.md, the "mode takeover into this mode" row for vendored, says the gates run before the hosted redirect is reverted, so "a refused purl stays hosted, byte-identical". A per-package refusal should keep that guarantee too: refuse first, then leave
yarn.lock and the redirect ledger untouched.
- Actual: the hosted redirect is reverted, then the vendored refusal fires, and the package is left unpatched in both modes.
Matrix
| OS |
yarn |
hosted → vendored takeover with a refused target |
| Linux (sandbox) |
4.12.0 |
fails (reproduced twice) |
| ubuntu-latest (probe) |
4.12.0, 4.18.1 |
fails |
| macOS (probe) |
4.12.0, 4.18.1 |
fails |
| Windows (probe, CRLF lock) |
4.12.0, 4.18.1 |
fails |
First bad release: release 4.0.0 (npm) behaves the same.
Suspect code
crates/socket-patch-cli/src/commands/vendor.rs:2578 (the takeover preflight only calls yarn_berry_vendor_preflight) and crates/socket-patch-core/src/vendor/yarn_berry_lock.rs:1032 (the preflight skips resolutions_gate / scan_berry_target / target_gate, lines 467 and 1113).
Probe run: https://github.com/SocketDev/socket-patch/actions/runs/36764922521 (its case outputs are in the Probe step log for each OS job)
[agent] Found by the scheduled Yarn Berry (2+) bug-hunt routine (ledger #305).
Summary
Running
socket-patch vendoron a yarn 4 project where the purl is already hosted-redirected takes over the purl (hosted → vendored). It first reverts the hostedyarn.lockedit and drops the redirect-ledger record (vendor_takeover_reverted_redirect). Only then does the berry backend run its per-package gates. When one of those gates refuses, the command exits 1. Here the refusal isvendor_override_conflictbecause the lock also resolves another version of the same name, which a name-keyedresolutionsentry would move. The purl is then patched in neither mode: the lock is byte-identical to the pre-hosted registry lock, and the next install fetches the unpatched registry tarball.The berry takeover preflight (
yarn_berry_vendor_preflight) only covers project-level gates (line endings, cacheKey, compressionLevel). The per-target gates inscan_berry_target(another version of the name, apatch:/workspace:/portal:entry, an entry mixing descriptors, duplicate entries) and inresolutions_gate(a user-authoredresolutionsoverride) all run after the hosted revert.Impact
A user who switches from hosted to vendored mode silently loses a working security patch, and the lock goes back to the unpatched registry entry. The run does exit 1, but the failure message only describes the vendor refusal. Nothing says the hosted redirect was already removed. The
skippedevent withvendor_takeover_reverted_redirectis the only trace, and a follow-upvexreportsno_applicable_patches.Repro (Linux, yarn 4.12.0)
The self-contained script is in the probe workflow linked below (
probe.sh, caseB-takeover).Actual:
Expected vs actual
yarn.lockand the redirect ledger untouched.Matrix
First bad release: release 4.0.0 (npm) behaves the same.
Suspect code
crates/socket-patch-cli/src/commands/vendor.rs:2578(the takeover preflight only callsyarn_berry_vendor_preflight) andcrates/socket-patch-core/src/vendor/yarn_berry_lock.rs:1032(the preflight skipsresolutions_gate/scan_berry_target/target_gate, lines 467 and 1113).Probe run: https://github.com/SocketDev/socket-patch/actions/runs/36764922521 (its case outputs are in the
Probestep log for each OS job)