Repository navigation
Fix yarnrc ${VAR} and YAML setting reads (#1100) - #1433
Merged
Mikola Lysenko (mikolalysenko) merged 5 commits intoOct 12, 2026
Merged
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Add one reader for top-level .yarnrc.yml settings that parses the
file as YAML (quoted keys, next-line values, flow maps, last key
wins) and expands ${NAME}, ${NAME-fallback} and ${NAME:-fallback}
references exactly as yarn's replaceEnvVariables does. A file that
is not one YAML document falls back to the old column-0 line scan.
Assisted-by: Claude Code:claude-opus-5-5
A project whose .yarnrc.yml says nodeLinker: "${L:-pnp}" is a live
Plug'n'Play project to yarn, but socket-patch read the literal text,
so agent apply exited 0 "not installed" instead of refusing PnP, and
lock-only vendor passed its PnP gate. compressionLevel: "${CL:-0}"
was likewise refused as a non-default level.
nodeLinker (disk and in-memory views), compressionLevel and the yarn
pnpm-store check now read the value yarn uses. A reference yarn cannot
expand counts as PnP while a loader exists, and refusals still name
the value as written. yarn_node_linker is read in any case, as yarn
does. The registry reader shares the same expansion code.
Fixes #1100
Assisted-by: Claude Code:claude-opus-5-5
Review follow-ups for the yarnrc reader:
- Hosted in-memory scans and the compressionLevel gate no longer
expand ${VAR} from the scanning host's environment, so the same
repository gets the same answer on every machine.
- yarn_node_linker and yarn_rc_filename are matched in any case,
in the order yarn uses.
- A linker that expands to nothing no longer inherits a parent rc's
value, and a .yarnrc.yml whose root is a list sets nothing.
- The vendor PnP refusal names an unexpandable linker instead of
claiming nodeLinker: pnp.
Assisted-by: Claude Code:claude-opus-5-5
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 12, 2026 15:30
Collaborator
Author
|
BugBot review Generated by Claude Code |
A checked-in .yarnrc.yml like nodeLinker: "${NPM_TOKEN}${" expanded
the token, kept the trailing "${", and was then refused as PnP with
the expanded value (the token) in the vendor refusal text. A linker
that still holds a literal "${" after expansion now falls back to
the text as written, so refusals only ever name unexpanded values.
Assisted-by: Claude Code:claude-opus-5-5
Collaborator
Author
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ 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 e90a047. Configure here.
Tanmay Singla (Tanmay182003)
approved these changes
Oct 12, 2026
Collaborator
Author
|
Final reviewer: approved on head e90a047, Generated by Claude Code |
Mikola Lysenko (mikolalysenko)
deleted the
agent/fix-yarnrc-setting-interpolation
branch
October 12, 2026 16:58
This was referenced Oct 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1100
Summary
socket-patch now reads
.yarnrc.ymlsettings the way yarn does. Before this change, a live Plug'n'Play project whose.yarnrc.ymlsaidnodeLinker: "${L:-pnp}"got exit 0 andpackage_not_installedfrom agentapplyinstead of ayarn_pnp_unsupportedrefusal, and lock-onlyvendorpassed its PnP gate.compressionLevel: "${CL:-0}"was refused as a non-default level, even though yarn reads it as 0.Root cause
Every
.yarnrc.ymlsetting socket-patch decides on (nodeLinker,compressionLevel,pnpmStoreFolder) went throughyarnrc_scalar, a column-0 line scan that returned the literal text afterkey:. Yarn parses the file as YAML, expands${NAME}/${NAME-fallback}/${NAME:-fallback}in every value (replaceEnvVariables), and matchesyarn_*environment keys in any case. So socket-patch and yarn disagreed on:compressionLevelrefusal),yarn_node_linkerin lower case (ignored).Fix
formats::yarn::rcmodule, a single reader for top-level.yarnrc.ymlsettings:replaceEnvVariables(expand_env), now also used by the npm registry restore (which keeps its rule that it never expands a set variable into a URL).nodeLinker(disk probe, in-memory hosted view, home rc,YARN_NODE_LINKER), thecompressionLevelgate and the yarn pnpm-store check all read through it.nodeLinker: pnp.compressionLevelgate expand from an empty environment, so a reference passes only through its fallback. A level set in some install environment is already recorded in the lock'scacheKey, which the cache-key gate checks. Agent mode on disk expands from the process environment yarn would run in.yarn_node_linker/yarn_rc_filenameare matched in any case, in the order yarn uses (last spelling of a setting wins, first spelling of the rc file name).The TS/Python/gem wrappers only dispatch to the binary, so they need no change.
Test evidence
Each issue row has a regression test. Every one was run red against
main's core and green with the fix:nodeLinker: "${L:-pnp}"/"${L}"withL=pnp/"${L:-node-modules}"withL=pnp, agentapplye2e_safety_yarn_pnp::pnp_loader_under_interpolated_pnp_linker_refuses,pkg_managers::yarnrc_linker_is_read_as_yarn_resolves_it,pkg_managers::yarnrc_linker_references_read_the_environmentyarn_pnp_unsupportedvendorPnP gatein_process_vendor::berry_lock_only_pnp_project_refused_up_front("interpolated pnp" leg)yarn_node_linker(fail-closed rows)e2e_safety_yarn_pnp::stale_pnp_loader_under_yaml_spelled_linker_applies,rc::yaml_shapes_read_like_yarn,pkg_managers::yarn_env_keys_match_any_casenpm_flavor::tests::unexpandable_linker_refusal_never_prints_an_expanded_variablesecret${compressionLevel: "${CL:-0}"(comment)berry_gates::an_interpolated_compression_level_is_read_as_yarn_resolves_itCommands run locally:
cargo fmt --all -- --check: cleancargo clippy --workspace --all-features -- -D warnings: cleancargo test -p socket-patch-cli --all-features --test e2e_safety_yarn_pnp: 43 passedcargo test --workspace --all-features: every suite passes except 14 tests across 5 targets (covgap_commands_vendor,e2e_bun_lockb,in_process_redirect,repair, core lib), which fail identically onorigin/mainin this sandbox: write-failure and permission tests that do not hold when running as root (verified by running each onmain)/code-review highran on the diff. These findings were fixed: host-env leakage in the memory view and the compression gate, env-key order,yarn_rc_filenamecase, a root list read as settings, an empty expansion inheriting a parent's linker, the misleading refusal text, and a dead wrapper. Not fixed:npmRegistryServer/npmScopeswith its own line-based YAML path reader; only the expansion is shared now. Moving the nestednpmScopeslookup onto a YAML tree is a separate change to the restore path, so it's left as a follow-up.${…}text rather than a typed state. That keeps theOption<String>linker API every caller uses, and a literal${in a linker isn't a value yarn accepts either way, so both read as PnP (fail closed).🤖 Generated with Claude Code
Note
Medium Risk
Changes Plug'n'Play detection and Berry gate logic for all
.yarnrc.ymlreads; behavior is intentionally stricter (fail-closed) but could shift outcomes for repos using env interpolation or non-flat YAML.Overview
Fixes #1100 by replacing the column-0
.yarnrc.ymlline scan with a sharedformats::yarn::rcreader that parses YAML (quoted keys, block/flow maps, last key wins) and expands${NAME}/${NAME-fallback}/${NAME:-fallback}like Yarn Berry.PnP and vendor safety:
nodeLinkerresolution (disk, hosted memory view, env overrides) now uses expanded values. Interpolated linkers that resolve topnpcorrectly triggeryarn_pnp_unsupportedinstead of falsepackage_not_installed; stale loaders under realnode-modulesconfigs are ignored. Unexpandable references fail closed as PnP; error text uses the raw rc value so secrets from env are not leaked.Other call sites:
compressionLevelgates andpnpmStoreFolderchecks use the same reader (hosted scans use an empty env /YarnEnv::repository_only()).yarn_*env keys are matched case-insensitively with Yarn’s first/last-win rules. Registry URL expansion reusesexpand_envwith the existing “never expand a set var into a URL” rule.Regression coverage spans e2e apply, in-process vendor, and unit tests for interpolation, YAML shapes, and refusal messaging.
Reviewed by Cursor Bugbot for commit e90a047. Configure here.
Generated by Claude Code