GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Stop VEX attesting over yarn PnP, pnpm bundled and deno.lock copies by mikolalysenko · Pull Request #1033 · SocketDev/socket-patch Conversation
|
| Finding | Verdict | Resolution |
|---|---|---|
major: pnpm bundled kills ledger liveness / vendor --check |
confirmed | Moved to Unattested (9ac96fc6). New test e2e_vex_vendor::pnpm_bundled_copy_blocks_vex_but_not_vendor_check (control, true, list): vendor --check verifies and vex omits with vex_pnpm_bundled_copy, naming the bundling entry. The pnpm lock never records a bundled version, so the "exact name@version" hard-contest path the reviewer offered doesn't apply. |
| minor: deno.lock contest kills liveness | confirmed (in part) | Moved to Unattested too. The nodeModulesDir: "manual" skip is not taken: in manual mode deno install still populates node_modules from deno.lock, so the files can't tell which installer ran. Documented as fail-closed for vex only. |
| minor: PnP substring match with both locators | confirmed, and a real gap | The berry same-lock rule was missing, so this case attested. Fixed in 98d9b0b2, pinned by yarn::berry_registry_locator_beside_a_hosted_one_contests_it and e2e_vex_lockfile::yarn::pnp_loader_naming_hosted_and_registry_copies_is_not_attested (berry 4 + yarn 1). |
| minor: per-extractor loop / cross-lock leak / wording | confirmed | The loop over out.refs is gone (the orchestrator matches). The pnpm mark is scoped to its own lock, with a test that a package-lock.json twin is unaffected. The PR wording is corrected above. The npm/vlt bundled duplication is deferred. |
minor: bundledDependencies: true → whole lock |
accepted as-is | It now only blocks attestation, not liveness. Narrowing via snapshots is deferred. |
| minor: stale #940 base | confirmed | Merged #940's current head acbac79a (clean). |
Each new regression test fails on the code before its fix and passes now:
| Fix | Test |
|---|---|
| #519 | e2e_vex_lockfile::yarn::pnp_layout_contract (yarn 1 + berry, fresh vs stale loader); unit crawlers::pkg_managers::tests::yarn_pnp_loader_resolves_patch_only_when_it_names_it |
| B04 | vex::discover::npm::tests::pnpm_bundled_copy_marks_the_ref_unattested, pnpm_bundled_copy_does_not_reach_another_lock; formats::pnpm::grammar::tests::entry_bundled_reads_every_spelling |
| B04 liveness | e2e_vex_vendor::pnpm_bundled_copy_blocks_vex_but_not_vendor_check |
| #406 | vex::discover::deno::tests::deno_lock_marks_an_npm_lock_pin_of_the_same_version_unattested, deno_npm_keys_cover_every_lock_version |
| berry same-lock | vex::discover::yarn::tests::berry_registry_locator_beside_a_hosted_one_contests_it, e2e_vex_lockfile::yarn::pnp_loader_naming_hosted_and_registry_copies_is_not_attested |
Commands run (macOS, CARGO_INCREMENTAL=0, through /private/tmp/claude-501/heavy-job.sh, -j4):
cargo test -p socket-patch-core --lib -- vex:: crawlers:: formats:: patch::redirect vendor::: 4379 passed. The vex-discover-golden/redirect-npm.json golden was regenerated; the only change is new unpatched_copies rows for 9 berry fixtures (no ref changed).cargo test -p socket-patch-cli --lib --test e2e_vex_lockfile --test e2e_vex_vendor --test e2e_vex --test e2e_vex_redirect --test e2e_embedded_vex --test covgap_commands_vex --test e2e_safety_yarn_pnp --test vex_terminal_output --test e2e_vex_build --test contract_gradle_codes: all passed (867 lib, 324 lockfile, 29 vendor, 19, 31, 15, 12, 36, 12, 1; vex_build cells ignored locally).cargo test -p socket-patch-cli for every suite that touches yarn.lock (in_process_vendor, in_process_redirect, in_process_rollback_hosted, in_process_get_modes, covgap_commands_{vendor,rollback,scan_mod}, e2e_{redirect,vendor}_yarn_berry_build, e2e_yarn4_workspaces_build, e2e_yarn_legacy_cachekey_refusal_build, hosted_memory_{parity,engine}, global_scope_project_state, cli_parse_list, e2e_{hosted,vendored}_production, mode_migration_npm): all passed except mode_migration_npm::berry_vendored_then_hosted_takeover_leaves_pure_hosted. That test fails identically with this PR's yarn change reverted (a hosted resolutions entry is left in package.json with the local real yarn), so it is not caused by this PR; CI will show whether it is local-only.cargo clippy -p socket-patch-core -p socket-patch-cli --tests -- -D warnings: no findings in any touched file. The local run fails only on lints already in files this PR doesn't touch (python_crawler.rs unused unix_default on macOS, jvm_jar.rs, maven_repo.rs, nuget_feed.rs, test prebuilt_common, …).rustfmt was run only on the touched files.integrity_required = false (part of B05): unchanged on purpose. Requiring Trusted Checksums would stop lock-only attestation for ordinary hosted Maven projects. This is maintainer decision E46, still open.push_uncontested (npm) and contest_bundled_copies (vlt) still emit their own bundled-copy diagnostics instead of using Discovery::unpatched_copy. This predates the PR and is left for a follow-up consolidation.bundledDependencies: true to the names in the parent's snapshots dependencies. It only costs attestations now, not liveness.resolved has no #sha1 fragment: the purl stays omitted (a missed attestation, never a false one).yarn.lock doesn't record bundled copies, so lockfile-only discovery can't see them.scan --vex path and a hosted-scan warning for deno.lock.packageManager set: the two-document pnpm-lock.yaml makes vendor refuse, and vendor --revert, rollback and the hosted takeover half-revert the project and break frozen installs #466, Bun hosted and vendored modes skip a URL or file: tarball copy of the patched package without warning, and vendored vex attests not_affected (the #326 fix covers npm locks only) #497, With Bun's globalStore (Bun ≥ 1.3.14), agent mode patches and rolls back every other project sharing the store, and vex attests unpatched transitive copies as not_affected #635, npm hosted and vendored modes rewrite a lock entry nested under a dependency that ships npm-shrinkwrap.json (hasShrinkwrap), so npm 7–11 install it unpatched while vendored VEX attests not_affected #753, npm 12 never reads npm-shrinkwrap.json, so on a shrinkwrap-only project hosted and vendored scans rewrite a lock npm 12 ignores: scan succeeds with no warning, lockfile-only VEX attests not_affected, and npm install installs the unpatched package #899, …) are out of scope, owned by Fix 15 open pnpm issues across hosted, vendored and agent modes #1007 / Fix open npm issues #1008 / Fix open bun issues (#992, #861, #784, #764, #735, #635, #599, #578, #497, #443, #371) #1009 and Fix VEX attesting beside an unpatched same-lock copy (#935, #938, #939) #940.🤖 Generated with Claude Code
Note
Medium Risk
Changes VEX attestation and discovery semantics for npm-family locks (security-relevant), but the behavior is intentionally conservative—fewer false positives, more omitted patches when evidence is ambiguous.
Overview
Tightens standalone vex so it no longer issues not_affected from lock pins when the build can still run unpatched bytes beside the wiring.
Yarn Plug'n'Play (#519): Adds YarnPnpLoader to read .pnp.cjs / .pnp.js (and related files) and check whether the loader actually resolves through the Socket patch. Lockfile-only attestation for hosted npm purls is allowed only when the loader names the patch; stale loaders after a rewire stay package_not_found.
Unattested wiring (pnpm + Deno): Introduces UnwiredCopy → Unattested with kinds BundledCopy and DenoLock (alongside existing Gradle LockAboveBase). pnpm bundledDependencies and matching deno.lock npm keys block attestation only (vex_pnpm_bundled_copy, vex_deno_lock_copy) while list / rollback / vendor --check / scan still treat the pin as live.
Yarn Berry same-lock contest: Plain registry locators beside a hosted locator of the same name@version now go through unpatched_copy, dropping the contested ref (aligned with npm/Bun) so PnP substring matches cannot attest when both copies exist.
CLI_CONTRACT.md and yarn compatibility docs document the new rules; e2e and discover tests cover each case.
Reviewed by Cursor Bugbot for commit 314038b. Configure here.
Generated by Claude Code
Sorry, something went wrong.
There was an error while loading. Please reload this page.
A lockfile-only `vex` attested a package as not_affected while the same lock also installed an unpatched copy of that exact name@version: - pnpm: a `file:` directory or tarball copy (#935) - yarn classic: a registry block left beside the Socket block, e.g. after `yarn add -W left-pad --exact` (#938) - yarn berry: a `file:` / url copy locked under another dependency name, which the `resolutions` pin never reaches (#939) The cross-lock contest only weighs OTHER locks, and each extractor wrote its own same-lock rule (npm and yarn classic git only). Discovery now has one shared same-lock rule: extractors record an unpatched copy and every ref of the same name@version in that lock is dropped with a patched_ref_unattributable diagnostic naming the copy. Yarn classic's git-copy filter moves onto it. The berry and pnpm extractors read the copy's real package from its package.json (directory or tarball) or from the registry tarball url. Assisted-by: Claude Code:claude-opus-5-5
main has failed socket-patch-core's lib tests since Gradle support (#646) and the digest helpers (#865) both landed. The guard test production_digests_go_through_the_helpers flags three files #646 added that still hash inline: crawlers/gradle_cache.rs, patch/jvm_jar.rs and patch/sidecars/maven.rs. That breaks test, test-release and coverage on every open PR. Each inline sha1/sha256 call now goes through sha1_hex_of or sha256_hex_of, which compute the same lowercase hex. Behaviour is unchanged. Assisted-by: Claude Code:claude-opus-5-5 (cherry picked from commit 659ac2c)
Every non-Socket yarn classic block is now recorded as a possible unpatched copy, and each record scanned the whole list for a duplicate first. On a 3000-package lock that made hosted scans and rescans about 17% slower in the scan benchmark. The list is already sorted and deduplicated once when discovery finishes, so the per-record scan goes. Assisted-by: Claude Code:claude-opus-5-5
Conflicts: - vex/discover/mod.rs: kept both main's ContestedRef/`contested` and this branch's UnpatchedCopy/`unpatched_copies` (structs, fields, finalize); `contest_within_locks` still runs before `contest_across_locks`, after main's new sbt extractor. - vex/discover/testing/golden.rs: import and render both `contested` and `unpatched_copies`. - vex/discover/yarn.rs: kept main's ClassicBlockSource match and classic_block_purl; main's #921 `file:` directory copies and the git copies now go through the shared `Discovery::unpatched_copy` rule instead of main's local post-filter loop (same diagnostic: names the lock entry and "file: directory"). Co-Authored-By: Claude <[email protected]>
Standalone vex excused a hosted npm purl the crawler could not find (package_not_found) by attesting it from the lock's integrity pin. Under yarn Plug'n'Play the crawler cannot look at all: packages are zips the .pnp loader resolves. A hosted lock pulled over an existing PnP install (the loader still resolving the registry copy) was attested not_affected while the running copy stayed unpatched. The excuse now treats a yarn PnP project like the pnpm out-of-project store: the lock basis applies only when the loader itself resolves the package through the patch. yarn berry keeps each locator's reference verbatim in .pnp.cjs (or .pnp.data.json), so the hosted url's uuid is in the text after a fresh install (checked against real yarn 4.12.0 and the real-yarn pnp-linker cell). yarn classic names the cache folder npm-<name>-<version>-<hash>, whose hash is the resolved url's #sha1 fragment. A stale loader names neither and the purl is omitted. PnP detection reuses detect_npm_pkg_manager, so the linker-aware detection in #978 applies here unchanged once it lands. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
pnpm unpacks a package's bundledDependencies from that package's own tarball into its store directory and never locks them, so no Socket wiring reaches that copy. The npm, bun and vlt VEX extractors already contest a ref beside a bundled copy; the pnpm extractor had no bundled handling at all, so a lockfile-only vex attested not_affected while the bundled copy installed unpatched. formats/pnpm/grammar gains entry_bundled, which reads the bundledDependencies field in the shapes real pnpm writes (block list, true; checked with pnpm 11.27) plus a flow list, failing closed on any other value. The pnpm extractor feeds each bundled name into the shared same-lock rule (Discovery::unpatched_copy, from #940). The lock does not record a bundled copy's version, so a ref of the same name is contested whatever its version (a missed attestation, never a false one), and bundledDependencies: true contests every ref of that lock. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Deno installs a package.json project's npm dependencies from deno.lock and never reads package-lock.json. The deno extractor was deliberately empty, so a hosted pin in package-lock.json beside a deno.lock registry entry of the same version attested not_affected from the lockfile basis while Deno ran the unpatched copy. The extractor now reads deno.lock's npm section (top-level npm in lockfile v4/v5, npm.packages in v2, packages.npm in v3; Deno's _peer suffix stripped) as resolved_elsewhere evidence, so the existing cross-lock contest drops the npm-family ref with a diagnostic naming both files. The read is advisory: deno.lock still never yields a ref, and an unreadable or unparseable lock contests nothing. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…py-vex' into arch-fix/vex-false-attest
The pnpm bundled rule and the deno.lock read fed Discovery::unpatched_copy and resolved_elsewhere, which drop the ref. Its uuid stays recognized, so the shared liveness rule called the vendor-ledger entry or redirect record dead and vendor --check failed with a rewire remedy that could never clear it (any pnpm lock holding one bundledDependencies: true package failed every vendored npm entry in it). Both now record an UnwiredCopy. After every extractor has run, the orchestrator turns it into an Unattested mark on each ref it may stand beside, so the ref stays a ref (list, rollback, remove, ledger liveness) and only vex omits it. Unattested gains an UnattestedKind so vex reports vex_pnpm_bundled_copy / vex_deno_lock_copy with their own remedy instead of the Gradle code. The pnpm mark stays inside its own lock and is no longer cross-lock evidence. record_pnpm_bundled_copies no longer walks out.refs. Regression test: a pnpm vendored entry beside a bundledDependencies package still passes vendor --check, while vex omits it. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
A berry registry locator (left-pad@npm:1.3.0) beside the hosted __archiveUrl one of the same name@version was only cross-lock evidence, so the same lock never contested the hosted ref. yarn installs both, and vex's PnP loader check matches the patch anywhere in the loader text, so a loader naming both locators attested the hosted pin. Plain and custom-registry berry entries now go through Discovery::unpatched_copy, as yarn classic registry blocks already do (#938). Adds a core test and a PnP e2e test (berry 4 and yarn 1) where the loader names both locators: nothing attests. The golden only gains the new unpatched_copies rows. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Resolve conflicts in vex/discover: keep main's same-lock contest (#940) alongside this branch's unwired-copy unattestation, pnpm bundled copies and berry registry-locator contest. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
|
bugbot run |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem 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 314038b. Configure here.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
[agent] Ready for review at
Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
…test # Conflicts: # crates/socket-patch-core/src/crawlers/pkg_managers.rs # docs/testing/yarn-berry-compatibility.md
There was an error while loading. Please reload this page.
Resolve golden.rs Discovery destructure: keep this PR's read/withheld fields and main's unwired_copies (#1033). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Resolve conflicts with #1035 (supersede lifecycle), #1038 (shared repo-root walk), and #1033 (unwired VEX copies): - #1035 added `vex::discover::same_release` and a second `canonical_base_purl` there. `PurlKey::same` already treats composer version spellings as one release, so every `same_release` call (vex_sources, rollback, discover, and `ledgers::hosted_pins_matching`) now uses `PurlKey::same`, and the duplicate helpers are dropped. - Both sides' new ledgers tests are kept. - The repo-root lookup in `policy` takes main's `utils::repo_root` version. `canonical_pypi_purl` stays deleted (nothing calls it now). - `vex` re-exports main's `UnattestedKind`. `UnwiredCopy::covers` compares purls with `PurlKey::same` rather than raw string equality. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Conflicts resolved: - vex discover: main's UnattestedKind (#1033) replaces this branch's parallel UnattestedWhy; the #899 shrinkwrap case becomes UnattestedKind::NpmShrinkwrapOnly, mapped through vex_sources' unattested_note like the other kinds. - scan/policy.rs: the #812 shared-copy keys use PurlKey (#1045) instead of the removed canon(). - CLI_CONTRACT.md: main's contested/unattested bullets, plus this branch's #828 withheld-ref sentence, #899 shrinkwrap bullet and npm warning rows. - redirect npm.rs / scan mod.rs: imports and key types from both sides. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
In a yarn classic Plug'n'Play project,vex attests a hosted patch as not_affected while the copy .pnp.js loads is still unpatched
There was an error while loading. Please reload this page.