GeezerVison is showing github.com — Fix fragmentless yarn classic hosted pins (#558) by mikolalysenko · Pull Request #1328 · SocketDev/socket-patch
Conversation
LLM Description written by Claude Code:claude-opus-5-5
Fixes #558
Summary
A hosted yarn classic pin now always carries the #<sha1> fragment yarn 1 keys its cache slot on. When the grant has no sha1, scan --mode hosted (disk flow and the in-memory engine) downloads the served tarball, checks it against the grant's sha512 and pins the sha1 of those bytes. If the tarball can't be fetched or doesn't match, the patch is skipped as npm_tarball_unavailable and the lock is left alone. It is never pinned without a fragment.
Root cause
rewrite_yarn_classic (crates/socket-patch-core/src/patch/redirect/mod.rs) built the fragment from dep.integrity.sha1 with unwrap_or_default(). A sha512-only grant produced resolved "<hosted-url>", and yarn 1 then filed the hosted tarball under npm-<name>-<version>-integrity. That is the same slot as any fragmentless upstream copy, so a warm cache served the unpatched bytes (yarn <= 1.17) or failed with Incorrect integrity (yarn >= 1.19).
Changes
hosted::npm_manifest::{decode,fetch}_hosted_npm_sha1: verify the served bytes against the grant's sha512, then return their sha1.
hosted::engine::yarn_classic_sha1_targets picks out the npm candidates that need it: no sha1, a sha512, and a classic yarn.lock naming the package. set_derived_sha1 records the result, and npm_tarball_unavailable is the skip.
- Disk flow (
commands/scan/hosted.rs) and in-memory flow (hosted/memory/{stages,discover,mod}.rs) fetch next to the existing berry manifest fetch.
- As a backstop, the rewriter refuses a dep that still has no sha1 (
redirect_yarn_classic_missing_sha1), the way composer does with redirect_composer_missing_sha1.
- docs/ecosystems.md (yarn classic hosted notes) describes the fragment rule and the new skip reason. CLI_CONTRACT already lists
#sha1 as required for the classic hosted pin.
Tests (each red before the fix, green after)
tests/scan/hosted_yarn_classic_sha1.rs (built binary + wiremock):
issue_558_sha512_only_grant_pins_the_served_tarballs_sha1: before the fix, resolved had no fragment.
issue_558_served_tarball_not_matching_the_grant_skips_the_patch
issue_558_unfetchable_tarball_skips_the_patch
- Before the fix, both skip tests pinned a fragmentless URL and reported
redirected: 1.
hosted_memory_engine::issue_558_yarn_classic_pin_takes_sha1_from_the_served_tarball: the in-memory engine, served and 404.
- Unit tests:
redirect::tests::issue_558_yarn_classic_refuses_a_dep_without_sha1
npm_manifest::tests::sha1_is_taken_from_bytes_matching_the_sha512
Review follow-up
- Bugbot: target selection used a raw substring. It now matches by block real name, version and registry copy source (
classic_locks_registry_copy), tested by hosted::engine::tests::classic_registry_copy_is_matched_by_block_name_and_source.
Fixture updates
- Unit-test
npm_override and the CLI mocks in covgap_commands_scan_hosted, in_process_redirect and in_process_vendor now model grants that carry a sha1. Expected classic resolved values gain the fragment.
- The
yarn_classic_rewrite equivalence golden was re-blessed: most sweep deps now carry a sha1, and every seventh deliberately doesn't, so the new refusal code is covered.
Commands run
cargo test --workspace --all-features --no-fail-fast: all green except e2e_vendor_cargo_build old-toolchain legs (x86_64 rustup 1.41 can't exec on this arm64 host, so unrelated). The 4 fixture failures it first surfaced are fixed above, and their binaries were re-run green.
cargo clippy --workspace --all-features -- -D warnings: clean.
cargo fmt --all -- --check: only changed files formatted.
🤖 Generated with Claude Code
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
A hosted yarn classic pin wrote `resolved "<url>"` with no `#<sha1>`
fragment when the grant carried only a sha512. Yarn 1 names its cache
slot after that fragment, so the hosted tarball shared the slot of any
fragmentless upstream copy of the same version: a warm cache installed
the unpatched bytes (yarn <= 1.17) or failed every install with
"Incorrect integrity" (yarn >= 1.19), while scan reported success.
When a classic yarn.lock is targeted and the grant has no sha1, the
disk and in-memory hosted flows now download the served tarball, check
it against the grant's sha512 and pin the sha1 of those bytes. A
tarball that can't be fetched or verified drops the patch as
`npm_tarball_unavailable`, and the rewriter itself refuses a dep that
still lacks a sha1 (`redirect_yarn_classic_missing_sha1`).
Fixes #558
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
cursor
Bot
left a comment
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
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.
Stale Bugbot comment from a previous run.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
The served-tarball fetch picked its yarn classic targets with a raw
substring test, so `lodash` matched a `lodash.debounce` block and a
package locked only as a git or file: copy (which the rewriter never
pins) was fetched too, and a failed fetch dropped its patch. Targets
are now read by block real name, version and registry copy source,
the way the rewriter selects blocks.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
cursor[bot] reacted with thumbs up emoji
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
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 494932e. Configure here.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
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]>
…test
Two interactions with main after merging it into this branch:
- #1026 made ApiClient's "artifact not found" errors redact the grant
token themselves, so the error no longer contains the raw artifact URL
and npm_tarball_unavailable's literal replace of that URL with
"<hosted artifact>" stopped matching. The token was still redacted, but
the detail now shows the host and path, which broke
issue_558_unfetchable_tarball_skips_the_patch's "server URI absent"
check. npm_tarball_unavailable now goes through redact_artifact_text
like its sibling skip builders. The test asserts that the grant token
never appears, and that the unfetchable detail names the URL with the
token redacted. The #558 skip assertions (npm_tarball_unavailable,
nothing redirected, yarn.lock untouched) are unchanged.
- #1274's yarn_classic_empty_range_key_is_pinned expected a fragmentless
resolved. With this PR the pin carries the grant's sha1 fragment
(#5ha1), as in the other classic tests this PR already updated.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
|
Merge-fix after approval (224bd92): after merging main, the PR's own issue_558_unfetchable_tarball_skips_the_patch failed because #1026 now redacts the grant token inside the artifact URL, so npm_tarball_unavailable's whole-URL replace no longer matched (nothing leaked). npm_tarball_unavailable now uses main's shared redact_artifact_text, like the neighbouring skip builders. The test now asserts the token never appears and pins the exact message. #558's behaviour is unchanged (skip, nothing redirected, yarn.lock byte-identical). yarn_classic_empty_range_key_is_pinned from #1274 now expects this PR's #sha1 suffix. scan 125 / core yarn 308 / core lib 6173 passing; clippy clean.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Oct 10, 2026
This was referenced Oct 12, 2026
Mikola Lysenko (mikolalysenko)
pushed a commit
that referenced
this pull request
Oct 12, 2026
A hosted scan of a yarn classic project re-read the whole yarn.lock
once per patched package to decide which served tarballs it must
fetch. On a 3000-package lock with 60 patches that made hosted scans
about 2.6x slower than before #1328, even on a rescan that fetches
nothing.
The lock's registry copies are now collected in one pass, and the
cheap "lock already pins this artifact" test runs first, so a rescan
of a fully pinned lock never reads the blocks at all. The selected
tarballs are unchanged.
Fixes #1423
Assisted-by: Claude Code:claude-opus-5-5
This was referenced Oct 13, 2026
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
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.
|