GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Refuse yarn classic pins with unlocked deps (#591) by mikolalysenko · Pull Request #1329 · SocketDev/socket-patch

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 9, 2026 •
edited by cursor Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Collaborator

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

Fixes #591

Stacked on #1328 (#558): the hosted half reuses that PR's served-tarball fetch. The base is agent/v5-yarn-classic-sha1, and GitHub retargets this PR to main once #1328 merges.

Summary

A patch that rewrites the patched package's own package.json to add a dependency, or to move one to a new range, no longer leaves a yarn classic lock that yarn can't install reproducibly.

  • Vendored: the patch is refused before any wiring is written, as vendor_dep_manifest_unlocked, when a dependency descriptor (name@range) has no yarn.lock block of its own. The staged uuid dir is removed. When every descriptor is already locked, the sub-maps are recomputed as before.
  • Hosted: for any classic entry it hasn't pinned yet, the scan reads the served tarball's package.json (one download per artifact, checked against the grant's sha512, shared with Hosted yarn classic rewrite drops the #sha1 fragment when the grant has no sha1, so yarn's cache serves stale bytes: yarn ≤1.17 silently installs the unpatched package, and yarn ≥1.19 fails every warm-cache install #558's sha1 derivation).
    • If a descriptor isn't locked, the pin is refused (redirect_yarn_classic_dep_manifest_unlocked). The uuid is never confirmed or attested, and the lock is left alone.
    • If every descriptor is already locked, the block's dependencies: / optionalDependencies: sub-maps are rewritten to match (redirect_yarn_classic_dep_manifest_rewritten).
  • Both refusals name the descriptors and give a remedy: lock them first (for example yarn add is-odd@^3.0.0), then re-run.

Root cause

  • Vendored rewrite_classic_block (vendor/yarn_classic_lock.rs) recomputed the sub-map from the patched manifest but never checked that each descriptor resolves to a block. The result was a dangling dependency: online frozen installs fetched it unpinned, --offline installs failed, and every plain yarn install re-saved the lock.
  • Hosted rewrite_yarn_classic never saw the patched manifest, so yarn kept the old graph. An added dependency was never installed, and a changed range stayed at the old version, while scan and vex reported success.

Changes

  • formats/yarn/classic_deps.rs is new. It holds the sub-map rebuild (moved from the vendored backend), unlocked_descriptors and dep_maps_match, shared by both writers.
  • NpmLockBackend::manifest_refusal is a new hook, checked after staging and before wire. The yarn classic backend implements it.
  • Hosted, disk and in-memory flows: yarn_classic_artifact_targets / fetch_hosted_classic_artifact / fetch_classic_artifacts return the sha1 plus the manifest. The manifest is passed to the classic rewriter through the existing per-URL metadata map, the one the berry bin: renderer uses.
    • A fetch is made only for a registry block of the package that isn't pinned yet, or when the grant lacks a sha1.
    • No fetch is made when an offline mirror refuses the lock outright.
  • Docs: CLI_CONTRACT.md (yarn classic row of the vendor table, plus three code rows) and docs/ecosystems.md (yarn classic hosted notes).

Tests (red before, green after)

  • vendor::yarn_classic_lock::tests::issue_591_added_dependency_without_a_lock_block_is_refused
  • vendor::yarn_classic_lock::tests::issue_591_changed_range_without_a_lock_block_is_refused, which also checks that the patch vendors once the new range is locked.
  • Both vendored tests ran red with the refusal hook disabled: vendoring returned Done.
  • patch::redirect::tests::issue_591_hosted_classic_checks_the_served_manifest_against_the_lock covers an added dep, a changed range, an unchanged manifest, and a locked new range whose sub-map is rewritten.
  • scan::hosted_yarn_classic_sha1::issue_591_served_dependency_the_lock_does_not_lock_is_refused (built binary + wiremock) ran red on the Hosted yarn classic rewrite drops the #sha1 fragment when the grant has no sha1, so yarn's cache serves stale bytes: yarn ≤1.17 silently installs the unpatched package, and yarn ≥1.19 fails every warm-cache install #558 base: it pinned and reported redirected: 1.
  • formats::yarn::classic_deps::tests::*

Fixture updates

The hosted classic pin now reads the served tarball, so these mocks serve a real tarball whose grant hashes match it:

  • covgap_commands_scan_hosted (2 classic tests), in_process_redirect (CRLF classic test), hosted_memory_parity (parity_yarn_classic, via a serve_npm_tarballs case option), and e2e_redirect_yarn_classic_build::mock_hosted_grant.
  • In classic_redirect_tampered_hosted_tarball_fails_integrity, the scan's own read now gets the real bytes and yarn's install gets the tampered ones. Without that, the scan would refuse the tampered bytes before yarn's integrity check ever ran.
  • Existing vendored sub-map tests now lock the descriptors their patches add.

Commands run

  • cargo test --workspace --all-features --no-fail-fast: green except the e2e_vendor_cargo_build old-toolchain legs (x86_64 rustup 1.41 can't exec on this arm64 host). After the rebase onto the Fix fragmentless yarn classic hosted pins (#558) #1328 review fix, I re-ran socket-patch-core --lib and the 9 affected CLI binaries, including the real-yarn e2e_redirect_yarn_classic_build and e2e_vendor_yarn_classic_*, all green.
  • cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo fmt --all -- --check: only a pre-existing diff in an untouched file.

Not covered

  • vendor --check / repair still pass a lock that an older release already vendored with a dangling descriptor (the Yarn classic: a patch that adds a dependency to the package's own package.json leaves vendored yarn.lock with a dangling dependency (offline frozen install fails, lock churns), and hosted silently installs without it #591 follow-up comment). This PR only stops new runs from writing one.
  • A vendored --dry-run stages nothing, so it doesn't foresee vendor_dep_manifest_unlocked.

🤖 Generated with Claude Code


Note

Medium Risk
Changes yarn classic vendored and hosted lock rewriting with new refusal paths; incorrect descriptor matching could block valid pins or allow bad graphs, but behavior is heavily tested and fails closed when descriptors are missing.

Overview
Fixes #591: patches that change a package’s own package.json dependencies are no longer wired into yarn classic in a way yarn 1 cannot install reproducibly.

Vendored mode checks the staged manifest before any lock write via a new NpmLockBackend::manifest_refusal hook. If a name@range descriptor has no matching yarn.lock block, the run fails with vendor_dep_manifest_unlocked, removes the staged uuid dir, and leaves the lock untouched. When every descriptor is already locked, dependencies / optionalDependencies sub-maps are still recomputed from the patch (shared logic in new formats/yarn/classic_deps.rs).

Hosted mode downloads and verifies the served tarball for classic pins that need it (sha1 and/or manifest), not just sha1 (#558). It refuses the pin with redirect_yarn_classic_dep_manifest_unlocked when the tarball’s manifest introduces unlocked descriptors, or rewrites sub-maps with redirect_yarn_classic_dep_manifest_rewritten when all descriptors exist in the lock. Contract docs and ecosystem notes document the new codes.

Tests and mocks were updated so classic hosted flows serve real tarballs whose grants match the bytes.

Reviewed by Cursor Bugbot for commit 1d7e1bf. Configure here.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@mikolalysenko
Mikola Lysenko (mikolalysenko) force-pushed the agent/v5-yarn-classic-added-deps branch from b2d2f85 to d29e412 Compare October 9, 2026 17:56
@mikolalysenko
Mikola Lysenko (mikolalysenko) changed the base branch from main to agent/v5-yarn-classic-sha1 October 9, 2026 17:56
@mikolalysenko @claude
Refuse yarn classic pins with unlocked deps
1d7e1bf
A patch that adds a dependency to the package's own package.json, or
moves one to a new range, left yarn classic locks that yarn could not
install reproducibly. Vendored mode recomputed the block's
dependencies sub-map but added no block for the new descriptor, so
online frozen installs fetched it unpinned, --offline installs failed
and every yarn install re-saved the lock. Hosted mode never looked at
the patched manifest, so yarn never installed the new dependency and
the patched package crashed at runtime, while scan and vex reported
success.

Both writers now compare the patched package.json with the lock.
Vendored mode refuses the patch before any wiring is written
(vendor_dep_manifest_unlocked) when a descriptor has no block of its
own. Hosted mode reads the served tarball (with the #558 sha1 fetch)
for every entry it has not pinned yet, refuses the pin with
redirect_yarn_classic_dep_manifest_unlocked, and rewrites the sub-maps
when every descriptor is already locked. Each refusal names the
descriptors and a remedy (lock them first, e.g. with yarn add).

Fixes #591

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko
Mikola Lysenko (mikolalysenko) force-pushed the agent/v5-yarn-classic-added-deps branch from d29e412 to 1d7e1bf Compare October 9, 2026 18:36
@mikolalysenko Mikola Lysenko (mikolalysenko) changed the title Refuse incomplete yarn classic dep graphs (#591) Refuse yarn classic pins with unlocked deps (#591) Oct 9, 2026
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 9, 2026 18:36
@mikolalysenko

Mikola Lysenko (mikolalysenko) commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

BugBot review

cursor[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko
Mikola Lysenko (mikolalysenko) merged commit f2866e2 into agent/v5-yarn-classic-sha1 Oct 9, 2026
43 of 46 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/v5-yarn-classic-added-deps branch October 9, 2026 18:36
@mikolalysenko
Mikola Lysenko (mikolalysenko) restored the agent/v5-yarn-classic-added-deps branch October 9, 2026 18:37
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Oct 9, 2026
Refuse yarn classic pins with unlocked deps (#591) #1363
Merged
@mikolalysenko

Mikola Lysenko (mikolalysenko) commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

[agent] This stacked PR was merged into its base agent/v5-yarn-classic-sha1 (an unprotected agent branch) as soon as auto-merge was requested. Nothing reached main. I reset that branch to its pre-merge head (494932e), so #1328 again carries only #558. The #591 change continues in #1363.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

cursor[bot]
cursor Bot reviewed Oct 9, 2026
View reviewed changes

@cursor cursor Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

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 1d7e1bf. Configure here.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Oct 9, 2026
CI performance dashboard #1182
Open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@cursor cursor[bot] cursor[bot] left review comments

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Yarn classic: a patch that adds a dependency to the package's own package.json leaves vendored yarn.lock with a dangling dependency (offline frozen install fails, lock churns), and hosted silently installs without it

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@mikolalysenko
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.