Fix yarn berry hosted pin of catalog deps (#632) - #763
Mikola Lysenko (mikolalysenko) merged 7 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A dependency declared "catalog:" in package.json was never patched by scan --mode hosted: the resolutions entry was keyed by the lock's expanded npm: range, but yarn matches resolutions before it expands the catalog. The scan reported success, then yarn install --immutable failed (YN0028) and a plain yarn install kept the unpatched release. Also route name@catalog: / name@catalog:<named> for every .yarnrc.yml catalog that maps the package to a pinned range. A re-run adds the selector to a pin written by an earlier release. Fixes #632 Assisted-by: Claude Code:claude-opus-5-5
Add a real-yarn check that a fresh checkout of a hosted-pinned catalog dependency installs the patched bytes under --immutable, an in-process scan + rollback round trip, and document catalog pins in the yarn berry hosted notes. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
cargo fmt --all also reformatted 127 files this fix doesn't touch (main isn't rustfmt-clean). Restore them and the untouched hunks of the edited files to main, so the PR only carries the catalog fix, its tests and the docs note. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
|
One CI check failed on 55dc0cb: I don't think this PR caused it:
I don't have a fix to port, because I haven't found a root cause in the PDM path. I've re-run the failed job once. If it fails again, I'll treat it as a real failure and dig in. Generated by Claude Code |
|
Ready for review at
Generated by Claude Code |
Resolve the docs/ecosystems.md conflict by keeping both changes: the yarn catalog routing note from this branch and main's note on how the re-keyed entry and its bin map are written. Also move the "#404 upgrade path" doc line back onto its own test; the new catalog test had been inserted in the middle of that comment. Co-Authored-By: Claude <noreply@anthropic.com>
|
bugbot run Generated by Claude Code |
|
One check failed on 2ab819a, the merge of This failure isn't caused by this PR. The PR's diff against Generated by Claude Code |
berry_catalog_selectors parsed .yarnrc.yml catalogs into serde_json Values, so an unquoted range like `1.10` became the number 1.1 and never matched the lock's `npm:1.10`: the `catalog:` selector was dropped while the pin was still confirmed. Yarn reads .yarnrc.yml with the failsafe schema, so deserialize the catalog tables as string tables instead, which keeps each scalar's source text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPHxnE5P1rkfCpHFFCwzFR
|
bugbot run Generated by Claude Code |
main fails commands::vex_consumed::tests::hosted_expands_alias_only_copies and hosted_reuses_expanded_npm_copies_and_merges_alias_variants since #605 landed alongside #738; #851 fixes the tests. Carry the same change so this PR's CI (coverage, test-release) is green; it no-ops once main has it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DPHxnE5P1rkfCpHFFCwzFR
|
On 2ab819a,
454b068 sits on top of 9abb2d9, which fixes Bugbot's YAML-number finding. The Generated by Claude Code |
|
bugbot run 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 454b068. Configure here.
|
Burn-down agent: labeled Ready for review at
Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #632
Summary
scan --mode hostednow pins yarn berry dependencies declared through a yarn catalog ("left-pad": "catalog:"). Before this, the scan reportedredirected: 1, but the nextyarn install --immutablefailed with YN0028 and a plainyarn installsilently installed the unpatched release. This was a regression from #465.Root cause
Since #465 the hosted yarn berry pin routes the lock entry's descriptors to the hosted tarball through root
package.jsonresolutions, keyedname@npm:<range>. Those keys come from the lock key's expanded ranges inberry_resolutions_pin. Yarn matchesresolutionsagainst the manifest descriptor before it expands the catalog, soleft-pad@npm:^1.3.0never matches a dependency declaredcatalog:orcatalog:<named>.Fix
berry_resolutions_pinreads the.yarnrc.ymlcatalog:/catalogs:tables through the newberry_catalog_selectors(serde-saphyr). Some catalogs give the package a range that, normalized to yarn'snpm:form, is one of the pinned ranges. For each of those, the pin also routesname@catalog:orname@catalog:<named>to the hosted tarball.1.10stays1.10), the way yarn's failsafe schema reads.yarnrc.yml.npm:selectors stay: transitive dependents still ask for the expanded range, and rollback rebuilds the lock key from them.npm:selector) adds the missing catalog selector and leaves the lock alone.npm:ones; a new test covers this.name@catalog:resolution still refuses withredirect_yarn_berry_resolutions_conflict.Checked by hand with real yarn 4.12.0:
{"left-pad@npm:^1.3.0": X, "left-pad@catalog:": X}installs the patched bytes for acatalog:dependency, and--immutablepasses.catalog:selector is harmless: the install gets the patched bytes and--immutablepasses.Per-issue checklist
catalog:dependency keysresolutionsby the resolvednpm:range, so everyyarn install --immutablefails YN0028 (regression from #465) #632, default catalog:yarn_berry_pin_routes_a_default_catalog_dependency(LF, and BOM + CRLF.yarnrc.yml, quotednpm:value)catalog:dependency keysresolutionsby the resolvednpm:range, so everyyarn install --immutablefails YN0028 (regression from #465) #632, workspace with default + named catalog in one merged entry:yarn_berry_pin_routes_every_catalog_locking_the_entry. Catalogs with another range, another package, or apatch:protocol are ignored.catalog:dependency keysresolutionsby the resolvednpm:range, so everyyarn install --immutablefails YN0028 (regression from #465) #632, unquoted numeric ranges:yarn_berry_catalog_ranges_keep_their_source_text.1.10matchesnpm:1.10, notnpm:1.1. Integer ranges, null entries, other nested keys, a non-table catalog and invalid YAML are all handled.catalog:dependency keysresolutionsby the resolvednpm:range, so everyyarn install --immutablefails YN0028 (regression from #465) #632, re-run loop:yarn_berry_catalog_pin_rerun_is_stable_and_heals_an_old_pin. A re-run is a no-op, and a pin written before this fix gets healed.catalog:dependency keysresolutionsby the resolvednpm:range, so everyyarn install --immutablefails YN0028 (regression from #465) #632, rollback:in_process_redirect::yarn_berry_catalog_dependency_is_pinned_and_rolled_back. package.json comes back byte-identical, and the lock gets itsnpm:key back.catalog:dependency keysresolutionsby the resolvednpm:range, so everyyarn install --immutablefails YN0028 (regression from #465) #632, real install:e2e_redirect_yarn_berry_build::berry_redirect_catalog_dependency_fresh_checkout_installs(real yarn 4.12.0). A freshyarn install --immutable --check-cacheinstalls the patched bytes. On yarn < 4.10 the test prints a note and returns, because catalogs don't exist there.Test evidence
left-pad@catalog:selector). With the fix, all pass:cargo test -p socket-patch-core --lib -- yarn_berrygives 102 passed on 9abb2d9.cargo test -p socket-patch-cli --test in_process_redirect -- yarn_berry: 7 passed.SOCKET_PATCH_YARN_E2E_REQUIRED=1 cargo test -p socket-patch-cli --test e2e_redirect_yarn_berry_build: 15 passed against real yarn 4.12.0.cargo test -p socket-patch-cli --lib: 840 passed on 454b068.cargo fmt --all -- --checkalso flags pre-existing code on main).cargo clippy --workspace --all-features -- -D warningsis clean.cargo test --workspace --all-features --no-fail-fastrun had 14 failures, all from the sandbox. 12 were chmod-based write-failure tests, which can't fail when running as root. 2 weremode_migration_npmfixtures whose registry download rejects the sandbox proxy's TLS certificate. CI runs these for real.History
cargo fmt --allhad reformatted files this PR doesn't touch. CI on 55dc0cb was green, and it was approved.main.berry_catalog_selectorsused to read unquoted catalog ranges as numbers, so1.10became1.1. It now deserializes the catalog tables as string tables. Bugbot re-reviewed 9abb2d9 and found no new issues.vex_consumedalias tests thatmainalso fails (Fix npm store copies missed by agent apply and vex (#601, #603) #605 and Fix agent mode skipping npm-aliased copies (#356) #738 conflicted once both merged). It becomes a no-op once Fix vex alias tests broken by store-copy merge #851 merges.coverage,test-releaseand the composer Windows job, which failed on 2ab819a, now pass on 454b068.🤖 Generated with Claude Code
https://claude.ai/code/session_01DPHxnE5P1rkfCpHFFCwzFR
Note
Medium Risk
Changes hosted Yarn Berry lock/manifest rewrite and resolution selector planning; wrong catalog matching could break immutable installs or leave deps unpatched, but behavior is heavily tested and user pins are refused rather than overwritten.
Overview
Fixes #632: Yarn Berry hosted redirects now route
catalog:dependencies to the patch tarball, not only the lock’s expandednpm:descriptors.Yarn Berry hosted pin reads
.yarnrc.ymlcatalog/catalogstables and adds matchingname@catalog:/name@catalog:<named>entries to rootpackage.jsonresolutionsalongside the existingnpm:selectors (needed for transitive deps and rollback). Catalog ranges are matched as string source text (e.g.1.10≠1.1). Re-runs are stable; older pins that only hadnpm:selectors get the catalog selector added without touchingyarn.lock. User-authored catalog resolutions still fail closed.Tests & docs: unit tests in
redirect/mod.rs, in-process pin/rollback, and a real-yarn e2e for freshyarn install --immutablewith catalog deps;docs/ecosystems.mdupdated.vex_consumednpm alias tests are adjusted so alias expansion is still exercised after the name-keyed resolver (#605) returns fuller copy sets.Reviewed by Cursor Bugbot for commit 454b068. Configure here.
Generated by Claude Code