Skip to content

Fix yarn mirror set in a workspace member (#1115) - #1694

Merged
Mikola Lysenko (mikolalysenko) merged 3 commits into
mainfrom
agent/fix-yarn-classic-member-mirror
Oct 23, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 3 commits into
mainfrom
agent/fix-yarn-classic-member-mirror

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #1115

Summary

A hosted scan of a yarn 1 workspace now refuses with redirect_yarn_classic_offline_mirror (and writes nothing, attests nothing) when yarn run in any workspace member would use a yarn-offline-mirror, e.g. one set only in packages/a/.yarnrc or packages/a/.npmrc. Before, it pinned the root yarn.lock, exited 0, VEX said not_affected, and every install run from that member failed Integrity check failed for "left-pad".

Root cause

resolve_outer_yarn_mirror_for_process (crates/socket-patch-core/src/patch/redirect/yarnrc.rs) resolved the mirror the way yarn 1 does from the scan root only: root rc files, env, user / global rc, the root's ancestors. Yarn 1 builds its config from the directory it runs in, and a member is a supported install directory (cd packages/a && yarn install, yarn --cwd packages/a install), which still installs into the root lock. A member's own rc files were never read.

Fix

  • yarn_classic_workspace_members lists the members yarn 1 installs for a classic lock: dirs holding a package.json that the root workspaces (array or object form) list, matched with the shared workspaces_include_as matcher in yarn classic's dialect. It follows dir links like yarn's globber, skips node_modules / .git, searches as deep as the deepest pattern (**: 32 levels), and stops after 20,000 dirs. It only runs when the root holds a classic yarn.lock and declares workspaces.
  • resolve_member_yarn_mirror resolves, per member, the full yarn 1 layering with the member as the project (its rc files as the project layer, the root's as an ancestor's) and returns the first member mirror. It lands in a new OuterYarnMirror::member field, which yarn_classic_offline_mirror falls back to. The refusal detail names the file and the member (…/packages/a/.yarnrc, as read by yarn run in the workspace member …/packages/a).
  • The hosted scan, its classic tarball prefetch and the vendored→hosted takeover all read the same resolver, so all three refuse. The hosted scan now resolves it once (OnceLock) instead of on every rewrite pass.
  • docs/ecosystems.md documents the member layer.

No wrapper (npm/, pypi/, gem/) change: they only dispatch to the binary.

Tests (per issue)

Red → green. With the fallback in yarn_classic_offline_mirror removed, the new e2e fails with the issue's exact symptom ("status":"success", "applied":1, rewrittenFiles: ["yarn.lock"], one VEX statement) and yarn_classic_outer_offline_mirror_refuses_rewrite fails on the member case; with it, both pass.

Local runs on 1f3fc57:

  • cargo fmt --all -- --check: clean. cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-cli --all-features --test e2e_redirect_yarn_classic_build: 41 passed.
  • cargo test --workspace --all-features --no-fail-fast: 14,834 passed, 10 failed, all environmental in this sandbox and outside the diff: 9 tests that make a write fail with chmod (the sandbox runs as uid 0, which bypasses it) and e2e_bun_lockb::binary_shared_bundled_record_hosted_pin_is_managed (needs patches-api.socket.dev, blocked by the sandbox proxy). CI is the reference for those.

/code-review high

Fixed: symlinked members were skipped; members deeper than 8 levels were missed; the resolver (now a tree walk) ran on every rewrite pass; the refusal didn't say which member. Not changed:

  • A root false no longer hides a user-level mirror in a workspace: that is yarn 1's precedence. A member run reads the user rc above the root's (an ancestor's), so that install really does use the mirror and would fail integrity. The docs now say to set false in the member too.
  • Reuse an existing member walker: npm_crawler::expand_workspace_pattern_sync and UserPatchIndex::workspace_members don't read yarn classic's full pattern grammar (braces, extglob, ignored negation) that workspaces_include_as does, so this walk drives that matcher instead.
  • Per-member re-resolution of the user / env layers: bounded by the member count and run once per scan now; not worth a cache.

https://claude.ai/code/session_01RJ6ze68VotuyevvN6kqX6r


Note

Medium Risk
Changes when yarn classic hosted redirect is allowed vs refused, which affects lockfile integrity and install behavior for workspace monorepos; bounded by new workspace walk limits and tests.

Overview
Yarn 1 hosted scans now treat yarn-offline-mirror set only on a workspace member (e.g. packages/a/.yarnrc or .npmrc) the same as a root-level mirror: hosted redirect is refused with redirect_yarn_classic_offline_mirror instead of rewriting the root yarn.lock.

Member discovery walks classic workspace globs (yarn_classic_workspace_members), resolves each member’s mirror with yarn 1’s full config layering (resolve_member_yarn_mirror → OuterYarnMirror::member), and yarn_classic_offline_mirror consults that fallback. The hosted scan resolves outer/member mirror once per run via OnceLock.

E2E and unit tests cover member rc files, workspace globbing, and docs in ecosystems.md describe member precedence (root false does not disable a user mirror for member installs).

Reviewed by Cursor Bugbot for commit 1f3fc57. Configure here.


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
A hosted scan of a yarn 1 workspace pinned the root yarn.lock and
reported success when only a member's .yarnrc or .npmrc set
yarn-offline-mirror. Installs run from that member read the member's
config, take the upstream tarball from the mirror and fail the
integrity check, while VEX said not_affected (#1115).

The mirror resolver now also resolves the mirror yarn 1 would use when
run in each declared workspace member, and the yarn classic rewriter
refuses with redirect_yarn_classic_offline_mirror when any member has
one. The hosted scan, its tarball prefetch and the vendored-to-hosted
takeover all read the same resolver, so each now refuses.

Assisted-by: Claude Code:claude-opus-5-5
Review follow-ups for the workspace-member mirror refusal:

- follow directory links when looking for members, as yarn's globber
  does, and search literal patterns as deep as they go (a ** pattern
  stops at 32 levels, and the search at 20,000 directories);
- resolve the yarn mirror config once per hosted scan instead of on
  every rewrite pass, since it now walks the workspace;
- say in the refusal which member's yarn run uses the mirror, and
  document that a member run reads the root .yarnrc below the user's.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 23, 2026 13:32
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 1f3fc57. Configure here.

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 23, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Labeled Ready for review (burn-down agent).

  • Head: 1f3fc57
  • CI: 86/86 settled green (36 success / 50 skipped); no main-wide failures on this head
  • Bugbot: reviewed 1f3fc57, no findings; no open review threads
  • Mergeable, no conflicts; CHANGELOG.md untouched
  • Reviewer focus: the new workspace-member walk in yarnrc.rs (yarn_classic_workspace_members: glob dialect, symlink following, 20,000-dir cap) and the OuterYarnMirror::member fallback in yarn_classic_offline_mirror.

Slack announcement not sent: this run had no Slack send tool.


Generated by Claude Code

Merged via the queue into main with commit ee40b70 Oct 23, 2026
86 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-yarn-classic-member-mirror branch October 23, 2026 14:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

3 participants