Skip to content

Vendored → hosted takeover on yarn berry deletes the vendored patch, then skips the hosted rewrite when the grant has no yarnBerry10c0 checksum, and still exits 0 "fully hosted" #468

Description

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

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