Repository navigation
Fix berry hosted pin beside a later registry entry (#1082) - #1397
Mikola Lysenko (mikolalysenko) merged 7 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A hosted yarn berry pin routes each descriptor that existed at scan time to the Socket tarball. A descriptor added later (a workspace member's exact range, an npm: alias) gets its own registry entry, so that copy installs unpatched. A re-scan used to refuse with a "run yarn install to dedupe" remedy that never works, since the pin keeps the entries apart. It now adds a selector for the new descriptor and drops its registry entry, which is the lock yarn writes once that selector exists. rollback and remove restored the hosted entry next to that registry entry with the same resolution. Yarn merges such entries, so every fresh yarn install --immutable failed with YN0028 while the unwind reported success. The restored entry is now merged into it. Fixes #1082 Assisted-by: Claude Code:claude-opus-5-5
Adds a real-yarn workspace e2e: a member added after the hosted pin gets its own registry entry; rollback of that lock, and a re-scan followed by rollback, each leave a lock a fresh yarn install --immutable accepts. The hosted API mocks move into a helper shared with the existing capstone. Assisted-by: Claude Code:claude-opus-5-5
vendor --revert (and rollback, remove, the hosted takeover) put the pre-vendor yarn.lock entry back verbatim. When an npm: alias or a member range of the same package was added after vendoring, yarn had locked it as its own registry entry with the same resolution, so the reverted lock held two entries yarn merges and every fresh yarn install --immutable failed with YN0028. The restored entry is now merged into that entry, as yarn writes it. The merge helper moves to formats::yarn::stanzas, shared with the hosted restore. Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
The vendored berry revert also merges a restored pruned entry into a sibling with its resolution. The hosted restore drops its node-gyp advisory for an entry merged into yarn's own, and skips the catalog lookup when nothing is folded. Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
|
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 f3d85e3. Configure here.
|
Ready for review at
Generated by Claude Code |
|
[final reviewer] Review brief for What it does. Fixes #1082. When a new range of an already-pinned yarn berry package shows up later (for example a workspace member's Risk: medium. It changes how lockfiles are rewritten on the hosted pin, hosted restore and vendored revert paths. The fold is narrow: it only applies when exactly one target is our own URL-keyed entry. Two plain registry entries still get Look here
Verified
Changes I made: none. Auto-merge (squash) is armed, so approving sends this straight to the merge queue. Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1082
Summary
A yarn berry hosted pin routes each descriptor that existed at scan time to the Socket tarball through a root
resolutionsselector. Sometimes a range of the same package is added later, such as a workspace member'sleft-pad: 1.3.0, or annpm:alias of it. Yarn then locks that descriptor as a separate registry entry, and that copy installs unpatched.Before this PR:
redirect_yarn_berry_ambiguous_entryand suggested "runyarn installto dedupe". That can't work, because the pin is what keeps the two entries apart.rollback/removeexited 0 but left two entries with the sameresolution:. Yarn merges such entries, so every freshyarn install --immutablefailed with YN0028.vendor --revert,rollbackorremoveafter an alias was added post-vendoring.After this PR:
Root cause
The berry hosted rewriter and both unwind paths treated the hosted (or vendored) entry and a later registry entry of the same
name@versionas unrelated blocks:patch/redirect/mod.rs(berry rewriter): whentargets.len() > 1, it refused, even when one target was our own URL-keyed entry and the others were plainnpm:registry entries.patch/redirect/upstream/npm.rs(restore_berry) andvendor/yarn_berry_lock.rs(revert_yarn_berry_opts): both restored the original entry next to an existing entry with the same resolution.The bisect in the issue points at #1008. Its
Discovery::shadowedchange hands these refs to rollback; before it, they were refused.Changes
redirect/mod.rs): when exactly one target is URL-keyed, the othernpm:targets are folded in.BerryResolutionsPin::add_rangesroutes their ranges (plus any matching catalog selectors) and removes their entries (edit kindredirect_yarn_berry_entry_folded). Two registry entries with no pin of ours still getambiguous_entry.formats/yarn/stanzas.rs,merge_same_resolution): folds each restored stanza into a sibling with the sameresolution:. The merged stanza keeps the sibling's (yarn-written) body and takes the sorted union of both keys. The merged key goes torender, which places it in yarn's order.upstream/npm.rs): runs the merge after re-keying. Theyarn_berry_node_gyp_unresolvedadvisory is dropped for an entry that was merged into yarn's own.yarn_berry_lock.rs): runs the merge over the restored lock and pruned entries.Tests (red on main, green here)
redirect::tests::yarn_berry_rerun_folds_a_descriptor_added_after_pinningredirect_yarn_berry_ambiguous_entryrollbackandremovemerge into a later plain entry and into an alias entryin_process_redirect::yarn_berry_unwind_merges_into_a_registry_entry_added_after_pinningyarn_berry_lock::tests::revert_merges_into_an_alias_entry_added_after_vendoringmovedbookkeepingstanzas::tests::restored_entries_merge_into_a_sibling_with_their_resolution--immutableinstall gets only the patched bytes; (3) roll back, then a fresh--immutableinstall passese2e_yarn4_workspaces_build::yarn4_hosted_pin_folds_a_member_added_later_and_rolls_backrestore_berryfrom main, rollback leaves two entries. With the rewriter from main, the re-scan refuses (ambiguous_entry, applied 0)Per-issue checklist:
yarn install --immutablerejects (YN0028) #1082 point 1 (re-scan dead end): fold test and real-yarn e2eyarn install --immutablerejects (YN0028) #1082 point 2 (rollback/remove → YN0028): in-process test and real-yarn e2e (--immutablepasses after rollback)yarn install --immutablerejects (YN0028) #1082 vendored counterpart (comment of 2026-10-09): vendored revert testLocal runs:
cargo fmt --all -- --check: cleancargo clippy --workspace --all-features -- -D warnings: cleancargo test --workspace --all-features --no-fail-fast(with corepack yarn available): 13905 passed, 15 failed. None of the failures is in code this PR changes, and all come from the sandbox:*_write_failure_*,*unremovable*,relax_loop_must_not_traverse_symlinked_root, and similar).e2e_bun_lockb::binary_shared_bundled_record_hosted_pin_is_managed, which needspatches-api.socket.dev.mode_migration_npm::berry_{hosted_then_vendored,vendored_then_hosted}_takeover_*. They panic in their own fixture setup (mount_hosted_mocks,mode_migration_npm.rs:329), where the test's reqwest client can't verify the sandbox proxy's certificate for registry.npmjs.org. That happens before any socket-patch code runs. Earlier agent runs had no corepack yarn, so these skipped there.cargo test -p socket-patch-cli --test e2e_yarn4_workspaces_buildwith real yarn 4.12.0 (SOCKET_PATCH_YARN_E2E_REQUIRED=1): passed/code-review highFixed:
movedkeys are droppedNot changed:
npm:entries of one version with no URL entry means they have different locators, for example a plain locator and an::__archiveUrl=one. Yarn does not merge those, so the refusal stays.package.jsonwrite fails after the lock was merged, a retry reportsvendor_lock_entry_removed(a not-drift warning, Afteryarn removeof a vendored package, rollback fails forever (exit 1) and no command can clean up the orphaned yarn classic artifact; the remedies it prints don't work #665) instead of staying silent. The retry still completes the revert.🤖 Generated with Claude Code
https://claude.ai/code/session_01TY1qeZG6YhbTSVfdgf4hhG
Note
Medium Risk
Changes hosted redirect, rollback, and vendored revert paths for
yarn.lockand rootresolutions; mistakes could break installs or leave packages unpatched, but behavior is heavily tested including real Yarn e2e.Overview
Fixes #1082: when Yarn Berry adds a second
yarn.lockentry for the same package after a hosted pin (e.g. a new workspace member range ornpm:alias with no matchingresolutionsselector), re-scan no longer bails withredirect_yarn_berry_ambiguous_entry, and rollback/remove/revert no longer leave two stanzas sharing oneresolution:(which breaksyarn install --immutablewith YN0028).Re-scan (hosted redirect) treats the URL-keyed pin plus one extra plain registry entry as foldable: it adds selectors for the new ranges, drops the duplicate stanza, and records
redirect_yarn_berry_entry_foldededits.Shared
merge_same_resolutionin yarn stanza handling combines restored stanzas into an existing sibling with the sameresolution:(sorted union of keys, Yarn’s body kept). Hosted restore and vendored revert call this after unwinding.Tests cover unit merge/rewrite behavior, in-process
rollback/remove, vendored revert with a post-vendor alias, and a real Yarn 4 workspace e2e (late member, re-scan fold, rollback). Docs inecosystems.mddescribe the fold/merge behavior.Reviewed by Cursor Bugbot for commit f3d85e3. Configure here.
Generated by Claude Code