Skip to content

Fix yarn 1.0.x global packages being missed (#437) - #1798

Merged
Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-yarn-1-0-global-dir
Oct 29, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-yarn-1-0-global-dir

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

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

Fixes #437

Summary

On a machine with yarn 1.0.0–1.0.2, global scans (scan -g,
scan -g --mode agent, get -g, rollback -g, vex -g) now find
the packages installed with yarn global add. Before this change they
skipped every such package and still exited 0 with status: success,
so a vulnerable yarn-global tool stayed unpatched without any warning.

Root cause

get_yarn_global_prefix_with (crates/socket-patch-core/src/crawlers/npm_crawler.rs)
located yarn's global packages only by running yarn global dir. That
subcommand was added in yarn 1.1.0. Yarn 1.0.x prints
error Invalid subcommand and exits 1, so the probe returned None, and
nothing else looked in yarn's global folder.

Fix

  • If yarn global dir gives no folder, the crawler tries the folders
    yarn 1.0.x would use, in order:
    1. A configured global folder (configured_yarn_global_folders; yarn
      1.0.x reads --global-folder from .yarnrc).
    2. Yarn 1.0.x's built-in default, taken from yarn 1.0.2's own
      GLOBAL_MODULE_DIRECTORY (getDirectory('config')/global; checked
      in the 1.0.0 and 1.0.2 tarballs). On Unix that is
      <userHome>/.config/yarn/global, where userHome is
      /usr/local/share for a root user not under fakeroot. On Windows,
      when LOCALAPPDATA is set, it is %LOCALAPPDATA%\Yarn\config\global.
      That is config, not the Data that 1.1+ uses.
  • The first of these folders that has a node_modules is used, and only
    when yarn --version reports 1.0.x. The version is asked only after
    such a folder is found. A Yarn Berry machine, which has no yarn global,
    therefore doesn't start a second yarn process on every global scan.
  • Yarn 1.1+ and machines without yarn behave exactly as before.

Tests

  • crawler_npm_e2e::get_yarn_global_prefix_with_falls_back_for_yarn_1_0
    (Global mode never finds yarn 1.0.x global packages: yarn global dir doesn't exist before yarn 1.1.0, and there's no fallback #437): mocks yarn 1.0.2 (global dir fails, --version = 1.0.2)
    over a scratch HOME. Red on main (left: None), green with
    the fix.
  • crawler_npm_e2e::get_yarn_global_prefix_or_falls_back_only_for_yarn_1_0:
    1.0.0/1.0.1/1.0.2/1.0.2-rc.1 fall back. 1.1.0, 1.22.22, 4.5.0 and no
    yarn don't. A configured folder wins over the default. With no folder
    present, yarn isn't asked for its version. A working yarn global dir
    is taken at its word.
  • yarnrc::tests::yarn_1_0_default_global_folder_follows_yarn_1_0_2
    covers the user, root, fakeroot, no-home, Windows-with-LOCALAPPDATA
    and Windows-without layouts.
  • Real yarn 1.0.2 (npm pack yarn@1.0.2), with HOME pointing at a
    scratch home: yarn global dir exits 1, and yarn global add left-pad@1.3.0 installs into ~/.config/yarn/global/node_modules.
    socket-patch scan -g --ecosystems npm (API stubbed out) prints
    Found 210 packages with the main binary and Found 211 packages
    with this branch. The extra package is the yarn-global left-pad.

Local runs at cefc03a:

  • cargo fmt --all -- --check and cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-core --all-features --no-fail-fast: 6908
    lib tests pass, plus every integration suite. Four lib tests fail:
    copy_tree::relax_loop_must_not_traverse_symlinked_root,
    vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry,
    pypi_poetry::wire_write_failure_… and
    pypi_requirements::wire_failure_rolls_back_…. These are chmod-based
    write-failure tests that can't fail when the sandbox runs as root, and
    they don't touch the code changed here.
  • I didn't run the full cargo test --workspace locally because the
    sandbox ran out of disk building every CLI test binary. The change is
    limited to two socket-patch-core modules, and CI runs the whole
    workspace.
  • No wrapper changes are needed. The npm, pypi and gem wrappers only
    dispatch to the binary.

Checklist:

Bugbot

  • Project rc can steal global prefix (7cacf1e): this was a real bug. The configured-folder lookup now reads yarn's config from neutral_probe_dir(), the same directory the yarn global dir probe runs in, not from the process cwd (cefc03a). The test above now also runs from a project whose .yarnrc points --global-folder at an existing folder. That assertion fails on 7cacf1e and passes on cefc03a.

/code-review high

Fixed:

  • A configured --global-folder is now honored.
  • yarn --version is no longer spawned on every machine whose
    yarn global dir fails.
  • The test's env changes are restored by a drop guard.

Not changed:

  • Yarn 0.x: socket-patch's supported yarn classic range (CI's
    yarn-classic-matrix) starts at 1.0.2, and I didn't verify the 0.x
    layout. The gate stays at 1.0.x.
  • HOME vs os.homedir() on Windows under MSYS, or on Unix with HOME
    unset: the home comes from the same RcLayout that every other yarn
    rc and folder lookup in yarnrc.rs uses. Diverging here alone would
    make this lookup inconsistent with those.
  • Building the path by hand instead of through parse_yarn_dir_output:
    that parser trims whitespace from stdout, which is wrong for a path
    socket-patch computed itself.
  • The public get_yarn_global_prefix_or: it follows the existing
    get_*_global_prefix_with injection pattern that the integration
    tests use.

https://claude.ai/code/session_011f9aeR8m1Cm2c7vE7U6qeH


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
Yarn 1.0.0 to 1.0.2 has no `yarn global dir` command, so global scans
(`scan -g`, `get -g`, `rollback -g`, `vex -g`) found none of the
packages installed with `yarn global add` and still reported success.

When `yarn global dir` gives no answer and `yarn --version` reports
1.0.x, the global folder yarn 1.0.x itself uses is crawled instead:
~/.config/yarn/global (/usr/local/share/.config/yarn/global for root),
or %LOCALAPPDATA%\Yarn\config\global on Windows. Newer yarn releases
and machines without yarn behave as before.

Fixes #437

Assisted-by: Claude Code:claude-opus-5-5
Yarn 1.0.x also reads `--global-folder` from .yarnrc, so a configured
global folder that exists is crawled before the default one. The
`yarn --version` probe now runs only when one of those folders exists,
so a Yarn Berry machine (no `yarn global` at all) doesn't pay for a
second yarn process on every global scan.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 28, 2026 22:03
@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.

Stale Bugbot comment from a previous run.

Comment thread crates/socket-patch-core/src/patch/redirect/yarnrc.rs
The yarn 1.0.x fallback read global-folder settings from the current
project, so a project .yarnrc naming an existing folder could pass a
project directory off as the machine-wide yarn install. It now reads
yarn's config from the same neutral directory the `yarn global dir`
probe runs in.

Assisted-by: Claude Code:claude-opus-5-5
@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 cefc03a. Configure here.

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

Copy link
Copy Markdown
Collaborator Author

Ready for review at cefc03a (burn-down agent).

  • CI: 50/50 check runs on cefc03a green (31 success, 19 skipped); mergeable, no conflicts.
  • Bugbot: reviewed cefc03a, no new issues; the one earlier thread (yarnrc.rs) is resolved.
  • Reviewer focus: the yarn 1.0.x fallback order in get_yarn_global_prefix_with (configured --global-folder, then the built-in default folder).

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Burn-down agent: labeled Ready for review at cefc03a.

  • CI: 50/50 check runs on cefc03a green or skipped (31 success, 19 skipped); no main-wide failures.
  • Bugbot: reviewed cefc03a, no new issues; no unresolved review threads.
  • CHANGELOG.md untouched.
  • Reviewer focus: the yarn 1.0.x fallback order in get_yarn_global_prefix_with (npm_crawler.rs) and the .yarnrc global-folder parsing in redirect/yarnrc.rs.

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief

What it does. Fixes #437. Yarn 1.0.0–1.0.2 has no yarn global dir, so global scans (scan -g, get -g, rollback -g, vex -g) silently skipped every yarn global add package. When the probe gives nothing, the crawler now tries a configured --global-folder and then yarn 1.0.x's own default folder, and uses the first one with a node_modules, but only if yarn --version reports 1.0.x.

Risk: low. It is a fallback that runs only after yarn global dir has already failed, and it is gated on an existing folder and a 1.0.x version string, so yarn 1.1+, Berry and yarn-less machines behave exactly as before (Berry pays no extra spawn unless a 1.0.x folder exists). Read-only discovery; nothing is written. 4 files, +265/-5, all in socket-patch-core.

Look here

  • npm_crawler.rs:2359: get_yarn_global_prefix_or, the fallback order and the version gate
  • npm_crawler.rs:2381: is_yarn_1_0 (accepts 1.0.2, 1.0.2-rc.1; rejects 1.0, 1.1.0)
  • yarnrc.rs:575: the default folder (~/.config/yarn/global, root → /usr/local/share, Windows %LOCALAPPDATA%\Yarn\config\global)
  • yarnrc.rs:591: configured folders read from the neutral probe dir, so a project .yarnrc can't redirect the machine-wide answer
  • crawler_npm_e2e.rs:391: the red-on-main regression test

Verified

  • Read the full diff and the description; it matches the code. Traced the no-yarn, Berry, yarn 1.1+ and yarn 1.0.x paths: only 1.0.x with an existing folder changes behavior. The closure is FnOnce and only evaluated after the probe fails, so the happy path does no extra filesystem reads.
  • Windows: the path is built with Path::join and covered with and without LOCALAPPDATA; no CRLF-sensitive parsing (the version string is trimmed).
  • Tests: the e2e test that mutates HOME/cwd is #[serial] with a drop guard; the gate test covers 1.0.0–1.0.2, rc, 1.1.0, 1.22.22, 4.5.0 and no yarn.
  • CI on cefc03a: 31 success, 19 skipped, 0 failed. Cursor Bugbot: success; its one finding (project .yarnrc stealing the prefix) was fixed in cefc03a. No unresolved threads. CHANGELOG.md untouched.

Changes I made: none.

Open questions (non-blocking): yarn 0.x is not covered (deliberately; the supported classic range starts at 1.0.2).

Auto-merge (squash) is armed, so approving sends this PR straight to the merge queue.


Generated by Claude Code

Merged via the queue into main with commit 34f13e0 Oct 29, 2026
50 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-yarn-1-0-global-dir branch October 29, 2026 13:40
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

Development

Successfully merging this pull request may close these issues.

Global mode never finds yarn 1.0.x global packages: yarn global dir doesn't exist before yarn 1.1.0, and there's no fallback

3 participants