Skip to content

Hosted yarn classic pins give no berry-migration warning, so a yarn 2+ install silently drops them (vendored warns about the same trap) #907

Description

[agent] Found by the scheduled Yarn classic (1.x) bug-hunt routine (ledger #304).

Summary

When yarn 2+ (berry) installs over a classic (v1) yarn.lock, it migrates the lock and re-resolves every entry from the registry. Socket-patch knows about this trap. Vendored mode emits yarn_classic_berry_migration_risk (crates/socket-patch-core/src/vendor/mod.rs:177) unless package.json pins packageManager: yarn@1…. Hosted mode pins the same lock, and berry drops that pin the same way, but hosted never runs the probe. scan --mode hosted and get <uuid> --mode hosted report success, redirected: 1 and no warning. This holds even when package.json already declares "packageManager": "yarn@4.x", where the next non-immutable install is certain to discard the pin.

Impact

A developer runs scan --mode hosted on a v1 lock that is mid-migration to berry (or unpinned) and commits the result. The next yarn install under berry quietly rewrites the lock to left-pad@npm:1.3.0 and installs the upstream, unpatched bytes, with nothing printed by either tool. vex correctly fails closed afterwards (the pin is gone, so manifest_not_found / exit 2), so nothing is falsely attested. The patch is lost silently, though, which is exactly the outcome the vendored warning exists to prevent. Under --immutable (berry's CI default), the same install fails YN0028 instead. That's loud, but there's still no hint that socket-patch's pin is the cause.

Repro

# mock patch API on 127.0.0.1:8787 serving a free left-pad@1.3.0 patch (run-18 mock from the #304 ledger)
export SOCKET_PATCH_SERVER_URL=http://127.0.0.1:8787
API="--api-url http://127.0.0.1:8787 --org o --api-token x"
mkdir p && cd p
echo '{"name":"p","version":"1.0.0","private":true,"dependencies":{"left-pad":"1.3.0"}}' > package.json
yarn@1.22.22 install                      # v1 lock
# mid-migration: the project now declares berry
echo '{"name":"p","version":"1.0.0","private":true,"packageManager":"yarn@4.18.1","dependencies":{"left-pad":"1.3.0"}}' > package.json
socket-patch scan --mode hosted --json --yes $API
#   status "success", redirect.redirected 1, redirect.warnings [] , top-level warnings []
grep resolved yarn.lock                   # http://127.0.0.1:8787/artifacts/…/left-pad-1.3.0.tgz#81960ff…
rm -rf node_modules
printf 'nodeLinker: node-modules\nenableGlobalCache: false\n' > .yarnrc.yml
YARN_ENABLE_IMMUTABLE_INSTALLS=0 yarn@4.18.1 install   # exit 0, migrates the lock
grep -A3 '"left-pad@' yarn.lock           # resolution: "left-pad@npm:1.3.0"  (pin gone)
head -1 node_modules/left-pad/index.js    # upstream bytes, no patch marker

# control: identical flow with --mode vendored
#   warnings: [yarn_classic_berry_migration_risk]  ("…installing with yarn 2+ (berry) migrates the lockfile and silently drops them…")

Expected vs actual

  • Expected: hosted pins in a classic lock are subject to the same migration loss the vendored probe describes ("installing with yarn 2+ (berry) migrates the lockfile and silently drops them — packages install unpatched from the registry"), so hosted should emit the same advisory (yarn_classic_berry_migration_risk, or a redirect_* twin). It should be suppressed by a packageManager: yarn@1… pin, and fire when there's no pin or when a non-1 yarn is declared. CLI_CONTRACT's hosted section says a dep counts as redirected only when its pin "actually landed in a project file". Here it lands, but the project's own declared package manager discards it on the next install with no signal.
  • Actual: hosted exits 0 success with no warning, while vendored on the same project warns.

OS × version

Linux, main 9c43dfc, each cell run at least once; the 1.22.22 scan cells twice. Berry is yarn 4.18.1 (@yarnpkg/cli-dist), nodeLinker: node-modules.

lock written by command packageManager socket-patch result berry install pin kept / installed patched
yarn 1.7.0 scan --mode hosted none success, redirected 1, no warning exit 0, migrated no / no
yarn 1.7.0 scan --mode hosted yarn@4.18.1 success, redirected 1, no warning exit 0, migrated no / no
yarn 1.7.0 get <uuid> --mode hosted none / yarn@4.18.1 success, redirected 1, no warning exit 0, migrated no / no
yarn 1.10.1 scan / get --mode hosted none / yarn@4.18.1 success, redirected 1, no warning exit 0, migrated no / no
yarn 1.22.22 scan / get --mode hosted none / yarn@4.18.1 (×2) success, redirected 1, no warning exit 0, migrated no / no
yarn 1.22.22 scan --mode vendored (control) none / yarn@4.18.1 (×2) success + yarn_classic_berry_migration_risk exit 0, migrated no / no
yarn 1.22.22 scan --mode hosted, packageManager: yarn@1.22.22 pinned success, no warning (correct) n/a (corepack would refuse berry) —
yarn 1.22.22 hosted, then berry install --immutable none success, no warning YN0028, lockfile would be modified —

macOS / Windows weren't probed. The behaviour is in the shared engine, not OS-specific code. No bisect: hosted mode has never called the probe.

Suspect code

  • crates/socket-patch-core/src/vendor/mod.rs:177 yarn_classic_berry_migration_risk only looks for .socket/vendor/ wiring (lock.contains(".socket/vendor/")), so it can't see a hosted pin.
  • crates/socket-patch-cli/src/commands/vendor.rs:689 note_classic_migration_risk is called only from the vendor paths (vendor.rs:949, vendor.rs:1600, scan/vendor_flow.rs:371). The hosted flow and rewrite_yarn_classic (crates/socket-patch-core/src/patch/redirect/mod.rs:3217) have no equivalent.

No activity

Activity on this issue will appear here.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions