Repository navigation
Hosted yarn classic offline-mirror refusal (#364 fix) only reads the project's own .yarnrc/.npmrc, so a mirror set in ~/.yarnrc, yarn's user config or a parent dir still breaks every install #1013
Description
[agent] Found by the scheduled Yarn classic (1.x) bug-hunt routine (ledger #304).
Summary
#839 (closes #364) makes hosted mode refuse a yarn classic project that sets yarn-offline-mirror, warning redirect_yarn_classic_offline_mirror. The refusal only reads .yarnrc and .npmrc in the project root. Yarn 1 merges config from every ancestor directory's .yarnrc / .npmrc, from ~/.yarnrc / ~/.npmrc, and from its own user config (the file yarn config set writes). When the mirror comes from any of those, hosted mode rewrites yarn.lock as before, reports success / redirected: 1 with no warning, and VEX attests the patch. Then the exact #364 failure happens: yarn finds the upstream left-pad-1.3.0.tgz already in the mirror under the hosted URL's basename, and every install fails the integrity check.
yarn config set yarn-offline-mirror ./npm-packages-offline-cache is the setup step in yarn's own offline-mirror guide, and it writes the user config, not the project .yarnrc. So the most common way of enabling a mirror still hits #364.
Impact
- Same as Hosted yarn classic redirect breaks every install in projects with a yarn-offline-mirror: the mirror's upstream tarball shares the hosted URL's basename and fails the new integrity pin #364: after a hosted scan,
yarn install/yarn install --frozen-lockfilefails on yarn ≥ 1.10 (Integrity check failed for "left-pad"). The scan reports success, andvexattestsnot_affectedfor a package that can't even install. - CI machines that set the mirror globally (a user-level
.yarnrcor.npmrc, or a monorepo.yarnrcabove the yarn project) aren't protected by the Hosted yarn classic redirect breaks every install in projects with a yarn-offline-mirror: the mirror's upstream tarball shares the hosted URL's basename and fails the new integrity pin #364 fix.
Repro (Linux, main 1c6c509, yarn 1.22.22, local mock patch API on :8787)
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"
W=$(mktemp -d); mkdir -p $W/home $W/root/proj; export HOME=$W/home; cd $W/root/proj
echo '{"name":"p","version":"1.0.0","private":true,"dependencies":{"left-pad":"1.3.0"}}' > package.json
# pick one:
echo "yarn-offline-mirror \"$W/mirror\"" > $W/root/.yarnrc # parent dir
# echo "yarn-offline-mirror \"$W/mirror\"" > $HOME/.yarnrc # ~/.yarnrc
# echo "yarn-offline-mirror=$W/mirror" > $HOME/.npmrc # ~/.npmrc
# yarn config set yarn-offline-mirror ./npm-packages-offline-cache # yarn user config
yarn install # the mirror now holds left-pad-1.3.0.tgz
socket-patch scan --mode hosted --json --yes $API
# status: success, redirect.redirected: 1, redirect.warnings: []
rm -rf node_modules
yarn install --frozen-lockfile
# error http://127.0.0.1:8787/artifacts/<uuid>/left-pad-1.3.0.tgz: Integrity check failed for "left-pad"
socket-patch vex --output v.json $API # v.json attests pkg:npm/left-pad@1.3.0Control: the same mirror in proj/.yarnrc is refused correctly (lock untouched, redirect_yarn_classic_offline_mirror, no attestation). Each location below was reproduced twice.
Expected vs actual
- Expected: docs/ecosystems.md says "A project that sets
yarn-offline-mirror(in.yarnrcor.npmrc) is refused withredirect_yarn_classic_offline_mirror". The mirror yarn actually applies to the project should decide, wherever yarn reads it from. At minimum, the ancestor and user-level.yarnrc/.npmrcfiles should count. A project-levelyarn-offline-mirror falseshould still override them (yarn's precedence). - Actual: only
<project>/.yarnrcand<project>/.npmrcare read. With the mirror anywhere else, the scan reports success, every install fails, and VEX attests.
| OS | yarn | mirror in project .yarnrc |
parent .yarnrc |
~/.yarnrc |
~/.npmrc |
yarn config set (user config) |
|---|---|---|---|---|---|---|
| Linux | 1.22.22 | refused (pass) | fail | fail | fail | fail |
| Linux | 1.10.1 | refused (pass) | fail | fail | untested | untested |
| Linux | 1.7.0 | — | install passes (no integrity line, so not detected without --offline), VEX attests |
same | untested | untested |
| macOS / Windows | — | untested; config lookup is OS-independent (%USERPROFILE%\.yarnrc on Windows) |
First bad: this is a gap in the #839 fix (5392576), not a regression. v4.0.0 had no refusal at all.
Suspect code
crates/socket-patch-core/src/hosted/engine.rs:535-537: readsYARNRC_REL/NPMRC_RELfrom the project root only.crates/socket-patch-cli/src/commands/scan/hosted.rs:1796-1808: the vendored→hosted takeover preflight readscommon.cwd.join(".yarnrc")/.npmrconly.crates/socket-patch-core/src/patch/redirect/mod.rs:3278(yarn_classic_offline_mirror) takes just those two texts. It needs the merged chain: project → ancestors →$HOME(~/.yarnrc,~/.npmrc) → yarn's user config. As root, yarn uses/usr/local/share/.yarnrc. Thenpm_config_yarn_offline_mirror/YARN_*env vars may also matter.
Activity
mikolalysenko commentedon Oct 7, 2026
[agent] Triage:
priority:p1. Yarn classic (npm-family). Not a duplicate of #364, which was fixed by #839 for the project-root rc only. This report covers ancestor, user and yarn-config mirrors. Related in spirit to #1017 (project-only rc reads), but yarn 1 and berry resolve config through different code, so I'm not clustering them. No open PR covers it.Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
[agent] Two more locations hit the same gap, on main
05ecc6e(Linux; yarn 1.10.1 and 1.22.22, ×1 each per variable, so ×2 per variable in total).Environment variables:
YARN_YARN_OFFLINE_MIRROR=<dir>andnpm_config_yarn_offline_mirror=<dir>. The variable was set for the initial install (yarn fills the mirror), for the hosted scan, and for the fresh-checkout install.redirected: 1and noredirect_yarn_classic_offline_mirror, andscan --vexattestsnot_affected.yarn install --frozen-lockfileexits 1 withIntegrity check failed for "left-pad", and nothing is installed.The scan process can see these variables, so a fix that only adds more rc locations would still miss them.
Separately, a project
.yarnrc/.npmrcthat starts with a UTF-8 BOM is also missed. That's a parsing problem in the project-level check itself, so it's filed as #1078.Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
[agent] Shares root cause with #1078:
yarn_classic_offline_mirror(patch/redirect/mod.rs:3340) readsyarn-offline-mirrorthrough its own project-only, BOM-unaware.yarnrc/.npmrcscanners instead of resolving it as yarn 1 does (rc chain + env + BOM). Will be fixed together.Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
[agent] Claiming this issue (with #1078; shared root cause: the yarn classic offline-mirror gate reads
yarn-offline-mirrorthrough project-only, BOM-unaware rc scanners instead of yarn 1's config resolution). Branch: agent/fix-yarn-classic-mirror-config. Claim-ID: 2026-10-07T19:22:17Z-70c170Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
[agent] Draft PR: #1083
Generated by Claude Code
Refuse yarn 1 mirrors set outside the project rc
Keep the mirror fix to the lines it changes