Repository navigation
Vendored→hosted takeover on yarn classic un-patches a vendored npm: alias copy when a direct copy is pinned, instead of retracting the takeover #1158
Description
Activity
- addedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:yarn-classicYarn classic (1.x)Yarn classic (1.x)
on Oct 8, 2026 - added a commit that references this issue
on Oct 8, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Triage: priority:p1 (yarn classic, npm family). Not a duplicate: #1081 is the VEX half of the same alias-skip shape (it attests over the skipped copy), while this one is the takeover planner (
Takeover::unpinnedinscan/hosted/takeover.rs) committing a partial pin and un-patching a previously vendored copy. Different code paths, so cross-linked rather than clustered. No open PR covers it yet.
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (with #1081; shared root cause: the hosted rewrite reports no per-patch signal for a yarn npm: alias copy it skipped, so the in-run VEX (assume_applied) and the takeover planner (Takeover::unpinned) both treat the purl as fully pinned). Branch: agent/fix-yarn-alias-skip-partial-pin. Claim-ID: 2026-10-08T21:44:16Z-5531e1
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions- added a commit that references this issue
on Oct 8, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Yarn-classic bug-hunt run 34: an independent check of PR #1180 at head
46f1bc0, with real yarn 1.22.22 and a local mock patch API:shape main 03b9418PR #1180 46f1bc0left-pad+lp: npm:left-pad@1.3.0, vendored → hosted takeoverredirect_takeover_reverted_vendored; fresh frozen install hasnode_modules/lpunpatchedredirect_takeover_kept_vendored; both copies patched after a fresh frozen installscoped alias @my/lp: npm:left-pad@1.3.0, same flow(not run on main) redirect_takeover_kept_vendored; both copies patchedplain hosted scan(no prior vendoring), same depspins nothing, exit 0: redirect_unattributable(the #1058 gate), so the direct copy also stays unpatcheddirect block pinned, alias skipped ( redirect_yarn_classic_alias_skipped); in-run--vexomits the package (vex_omitted) — #1081 fixedSo on current main, hosted mode can no longer pin a yarn classic package that also has an
npm:alias copy. That's the #1058 interaction the PR's 46f1bc0 already exempts, so it isn't filed separately. Merging #1180 resolves both.
Generated by Claude Code
- addedv5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.compatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.Public CLI/JSON, saved state, upgrades, or package-manager compatibility.
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actionsv5 release blocker (P1). A normal vendored-to-hosted transition must not silently unpatch an existing npm alias copy; PR #1180 is pending.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
[agent] Found by the scheduled Yarn classic (1.x) bug-hunt routine (ledger #304).
Summary
Take a yarn 1.22.22 project that depends on
left-pad@1.3.0both directly and through annpm:alias ("lp": "npm:left-pad@1.3.0"). yarn 1.22.22 writes these as two lock blocks.scan --mode vendoredwires both blocks to the vendored tarball, so both copies install patched.Now run
scan --mode hosted(orget <uuid> --mode hosted). The staged takeover from #1039 reverts both blocks. The hosted rewriter then pins only the direct block and skips the alias block withredirect_yarn_classic_alias_skipped. Because the purl was pinned once, the takeover is not retracted. It commits, deletes.socket/vendor/, and reportsredirect_takeover_reverted_vendored("the project is now fully hosted for this package"). The alias block goes back toregistry.yarnpkg.com, sonode_modules/lpinstalls unpatched. The exit code is 0 and the status issuccess.The same project with only the alias dep is handled correctly: the takeover is retracted with
redirect_yarn_classic_alias_skipped+redirect_takeover_kept_vendored, and the tree stays byte-identical. So the retract only triggers when the purl gets no pin at all, not when a copy the project had patched loses its patch.Impact
A user moving from vendored to hosted silently loses a patch they already had. The aliased copy goes from patched to unpatched with exit 0. The only signal is the generic alias-skip warning, while the takeover warning says the package is "fully hosted". The in-run
--vexthen attestsnot_affectedover that unpatched copy (that half is #1081).Repro (Linux, yarn 1.22.22, local mock patch API as in
tests/e2e_redirect_yarn_classic_build.rs)redirect.warnings[]codes:redirect_yarn_classic_alias_skipped,redirect_yarn_classic_berry_migration_risk,redirect_takeover_reverted_vendored.patches[]:left-pad@1.3.0pinned.Expected vs actual
crates/socket-patch-cli/CLI_CONTRACT.md, Staged takeover (v5.0): a staged purl the rewrite does not pin is retracted, with the cause taken from "the rewriter warning that names the package". It ends: "Exit 0: the package stays vendored and patched, never unpatched in both modes."docs/ecosystems.mddocuments that a hosted alias copy "keeps the unpatched artifact". In a takeover, though, that copy was patched (vendored) before the run.redirect_yarn_classic_alias_skippedon a block the vendored ledger wired), retract the purl. It stays vendored, byte-identical, withredirect_takeover_kept_vendored, as the alias-only shape already does. Failing that, at least don't announceredirect_takeover_reverted_vendored/ "fully hosted".Matrix
scan×2,get <uuid>×1)macOS / Windows weren't probed: the decision is platform-independent planner logic.
First bad version
Not a #1039 regression. v4.0.0 (npm
@socketsecurity/socket-patch@4.0.0) does the same: it reverts both blocks, pins the direct one, and leaves the alias on the registry withredirect_takeover_reverted_vendored. #1039 added the retract path, but it doesn't cover a partial pin.Suspect code
crates/socket-patch-cli/src/commands/scan/hosted/takeover.rs:285Takeover::unpinnedtreats a staged purl as pinned once any(purl, uuid)is confirmed. It doesn't check that every lock entry the reverted vendored ledger entry had wired got pinned again.crates/socket-patch-core/src/patch/redirect/mod.rs:3709is where the classic rewriter recordsalias_skippedfor the purl, the signal the takeover could use.The npm-family takeover path is shared, so yarn berry (
redirect_yarn_berry_alias_skipped) may show the same thing; that's for the yarn-berry routine to check.