GeezerVison is showing github.com — fix(vendor): accurate refusals for bundled/alias/CRLF lock shapes by mikolalysenko · Pull Request #185 · SocketDev/socket-patch
Conversation
Problem
Three vendored-mode diagnostics defects from the 2026-08-13 audit sent users down the wrong remediation path or silently hid security-relevant facts:
-
npm: all-bundled/all-link target refuses with a misleading "not found" and drops the UNPATCHED advisories (medium). When every lock instance of the target is bundled inside a parent's tarball (inBundle) or a link, scan_lock_matches returns zero rewritable matches and vendor_npm refused with the generic vendor_lock_entry_not_found ("make sure the package is installed and locked (npm install)"). The entry IS in the lock, npm install cannot help, and because VendorOutcome::Refused has no warnings channel, the per-instance "that copy stays UNPATCHED" advisories were silently discarded. Concrete scenario: a lock whose only [email protected] entries are an inBundle: true nested copy and a workspace link — the user is told the package isn't installed instead of being told it cannot be patched by vendoring and remains vulnerable.
-
npm v2 legacy dependencies mirror: bundled nodes wrongly rewritten, alias consumers silently unpatched (low). rewrite_legacy_tree rewrote bundled: true nodes (the packages scan skips their inBundle twins, so the two lock halves desynced — npm never installs a bundled copy from resolved), and alias consumers ("alias": {"version": "npm:[email protected]"}) matched neither key nor version, so npm 6 clients reading the mirror keep installing the unpatched registry bytes through the alias with zero warning.
-
pnpm: CRLF lockfile refuses with a misleading "not found" (low). A CRLF pnpm-lock.yaml (Windows autocrlf checkout) passes check_lock_version (str::lines strips \r) but breaks every structural probe (split_lines keeps the trailing \r, so packages: never matches "packages:\r"), surfacing as vendor_lock_entry_not_found — wrong diagnosis for a lock pnpm itself accepts.
Fix
vendor_npm: when matches is empty but the scan pushed vendor_bundled_instance_skipped / vendor_link_entry_skipped warnings, refuse with the new vendor_lock_entry_not_rewritable code whose detail carries the per-instance stays-UNPATCHED advisories verbatim and explicitly says npm install will not help. The genuinely-absent case keeps the existing vendor_lock_entry_not_found. Both codes remain non-benign (refusal_is_benign unchanged), so exit behavior is unchanged.
rewrite_legacy_tree: skips bundled: true nodes (parity with the packages scan's inBundle skip) and emits a loud vendor_legacy_alias_skipped warning for alias consumers, naming the JSON-pointer node and that npm 6 still installs UNPATCHED bytes through it. Aliases are warned rather than rewritten because the legacy alias spelling has no proven equivalent rewrite — fail loud, not fail open.
vendor_pnpm: fails closed immediately after the version sniff with the new vendor_lockfile_crlf_unsupported refusal, naming the CRLF line endings and the LF-normalization remedy, before any structural probe can produce the wrong diagnosis.
Skipped (out of lane scope, third gap of the low-severity legacy-mirror finding): recomputing the legacy node's requires map from the patched manifest. A correct recompute needs the staged patched package.json plumbed into rewrite_legacy_tree plus a proven mapping to npm 6's requires grammar; doing it without a spike risks corrupting v2 locks for a purely npm-6-era reader.
Testing
- New regression tests, each verified red against the pre-fix behavior (guards temporarily neutralized) before going green:
npm_lock.rs::tests::all_bundled_or_link_instances_refuse_with_accurate_reason
npm_lock.rs::tests::v2_legacy_bundled_node_is_not_rewritten
npm_lock.rs::tests::v2_legacy_alias_node_warns_and_keeps_registry_resolution
pnpm_lock.rs::tests::crlf_lock_refuses_naming_line_endings
cargo test -p socket-patch-core --lib — 2079 passed
cargo test -p socket-patch-cli --test in_process_vendor — 27 passed
cargo test -p socket-patch-cli --test e2e_vendor_npm_build — 7 passed
cargo test -p socket-patch-cli --test e2e_vendor_pnpm_build — passed
🤖 Generated with Claude Code
Note Medium Risk
Changes vendor lock rewrite and refusal paths that affect which lock bytes are edited and what users see when patches cannot apply; incorrect behavior could leave unpatched installs or mislead remediation, but scope is diagnostic/parity fixes with targeted tests.
Overview
Improves npm and pnpm vendoring diagnostics when lock entries exist but cannot be rewritten, so users are not told to run npm install / pnpm install incorrectly and security-relevant UNPATCHED facts are not dropped.
For npm, when every matching lock instance was skipped (bundled inBundle or link), refusal now uses vendor_lock_entry_not_rewritable with bundled/link skip details in the message instead of vendor_lock_entry_not_found. The v2 legacy dependencies mirror now skips bundled: true nodes (aligned with packages inBundle) and emits vendor_legacy_alias_skipped for npm:name@ver alias nodes left at registry resolution for npm 6 readers.
For pnpm, CRLF pnpm-lock.yaml is rejected up front with vendor_lockfile_crlf_unsupported and LF normalization guidance before structural parsing can misdiagnose a missing package entry.
Regression tests cover all-bundled/link refusal, legacy bundled skip, legacy alias warning, and CRLF refusal.
Reviewed by Cursor Bugbot for commit 03fe6cd. Configure here.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Three diagnostics fixes so vendored-mode refusals name the real cause
instead of sending users down the wrong remediation path:
- npm: when every lock instance of the target is bundled inside a
parent's tarball or a link, vendoring refused with the generic
vendor_lock_entry_not_found ("run `npm install`" -- which cannot
help) and silently dropped the stays-UNPATCHED advisories, since a
Refused outcome has no warnings channel. It now refuses with
vendor_lock_entry_not_rewritable and carries the per-instance
UNPATCHED advisories in the refusal detail.
- npm v2 legacy `dependencies` mirror: `bundled: true` nodes are no
longer rewritten (parity with the packages scan's inBundle skip --
npm never installs a bundled copy from `resolved`, and rewriting it
desynced the two lock halves), and alias consumers
(`"alias": {"version": "npm:real@ver"}`) now emit a loud
vendor_legacy_alias_skipped warning: npm 6 reading the mirror still
installs the unpatched registry bytes through the alias.
- pnpm: a CRLF pnpm-lock.yaml (Windows autocrlf checkout) passed the
version sniff but failed every structural probe, surfacing as the
misleading vendor_lock_entry_not_found. It now fails closed up
front with vendor_lockfile_crlf_unsupported, naming the line
endings and the LF-normalization remedy.
Co-authored-by: Claude Fable 5 <[email protected]>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
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.
|