Skip to content

Hosted → vendored takeover on yarn berry reverts the hosted redirect before a per-package vendor refusal, leaving the package unpatched in both modes #369

Description

[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)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions