-
Notifications
You must be signed in to change notification settings - Fork 0
Comparing changes
Open a pull request
base repository: SocketDev/socket-patch
base: main
head repository: SocketDev/socket-patch
compare: feat/apply-mismatch-warning
- 14 commits
- 38 files changed
- 2 contributors
Commits on Jun 11, 2026
-
fix(purl): percent-decode purl components from the API
The patches API serves scoped purls percent-encoded (pkg:npm/%40scope/name@1.0.0) and scan stores them verbatim as manifest keys, but neither the npm crawler nor the vendor coordinate parser decoded them — so apply/vendor reported scoped packages as 'package not installed', and detect_prunable saw every encoded entry as prunable. - utils/purl.rs: percent_decode_purl_component (strict, all-or-nothing, fail-safe passthrough), normalize_purl + purl_eq (compare/display only, never path construction) - npm_crawler parse_purl_components, vendor parse_npm_purl (NpmCoords now owns decoded name/version; base_purl stays verbatim for ledger/ manifest key parity), parse_jsr_purl: decode AFTER /-and-@ splits, BEFORE the is_safe_* guards — %2e%2e/%2f cannot smuggle traversal - detect_prunable + purl_matches_identifier compare normalized forms - human output shows the decoded purl; JSON keeps verbatim keys Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 42e95be - Browse repository at this point
Copy the full SHA 42e95beView commit details -
feat(vendor): auto-force staging on content mismatch + correct alread…
…y-applied events The vendor stage is a private copy and every apply write path is hash-gated to exactly afterHash, so a beforeHash mismatch (a patch built against different bytes than the installed artifact, or a package already patched in place by apply) no longer fails the vendor: the stage is overwritten with the verified patched content and the overwrite surfaces as a vendor_content_mismatch_overwritten warning event. Missing patch-target files still fail closed without --force (force's silent NotFound skip would pack an artifact without the fix). - shared force_apply_staged / missing_existing_patch_files / mismatch_overwrite_warnings policy helpers in vendor/mod.rs, used by all npm flavors (via stage_patch_pack) + cargo/composer/gem/pypi/ golang backends; dry runs predict the same outcome - vendor.rs: gate the already_vendored rewrite on entry.is_none() — the first vendor of an in-place-applied package now emits Applied (it packed + rewired this run) instead of a miscounted skip - scan --vendor: pre-prompt baseline check annotates mismatched packages before the confirm prompt (best-effort, read-only) - --force narrowed to missing-file tolerance + variant-probe bypass; CLI_CONTRACT.md documents the new warning code Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for c3c012f - Browse repository at this point
Copy the full SHA c3c012fView commit details -
feat(vendor): take over exact-version override pins (pnpm + yarn berry)
A user-authored override/resolution that pins the package to exactly the version being vendored (Flowise: pnpm.overrides 'tar-fs': '3.1.0') no longer refuses with vendor_override_conflict. The pin's key is kept (its spelling and quoting preserved on both pnpm surfaces — pnpm hard-requires the package.json and lock override maps to agree), its VALUE is rewritten to the file:.socket/vendor/... spec, and the pinned value is recorded as the wiring original so every revert path (--revert, reconcile, remove) restores the user's pin verbatim. - pnpm: classify_pkg_override (Insert / Ours / Takeover) replaces the boolean conflict checks; effective key threads through EditCtx, apply_pkg_override and edit_overrides; revert restores originals in place instead of deleting. Ranges, different versions, parent>child selector chains, and duplicate same-name keys still refuse, now with a hint that exact pins are taken over. - yarn berry: bare-name resolutions pin equal to the version is taken over symmetrically (KIND_RESOLUTION records the original). - npm/yarn-classic/bun wire the lock only (no override surface), so no conflict exists there to take over. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 7363c65 - Browse repository at this point
Copy the full SHA 7363c65View commit details -
feat(scan): prune lifecycle for vendored packages
scan --prune previously blanket-exempted vendored purls, so nothing ever cleaned unused vendored state: dropped patches kept their artifacts and overrides forever, removed dependencies stayed redirected, and orphan uuid dirs were only swept by vendor --revert. The prune pass now runs a vendored-state GC first (under the apply lock; contention degrades to a skip, never a scan failure): (a) entries whose patch is gone from the manifest are reverted (same stale test as the vendor flows' reconcile_dropped); (b) entries whose dependency left the lockfile graph are reverted and their manifest entries dropped, feeding the same pass's blob sweep. Per-flavor in-use probes: pnpm scans packages:/snapshots: blocks for the artifact (the mirrored overrides: declaration alone is not usage); package-lock/yarn/bun probe the lock text for the uuid dir (those flavors wire resolutions into the lock itself). None = cannot determine = keep, fail-safe; detached entries are exempt (lockfile-invisible by design); (c) orphan .socket/vendor/<eco>/<uuid> dirs are swept (extracted from run_revert into a shared sweep_orphan_vendor_dirs). JSON gc gains revertedVendoredEntries/removedVendorOrphanDirs (wet) and revertableVendoredEntries/vendorOrphanDirs (preview, which also mirrors the wet pass's manifest drops so blob counts agree); human output gains a GC summary line. CLI_CONTRACT.md updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Configuration menu - View commit details
-
Copy full SHA for adc5179 - Browse repository at this point
Copy the full SHA adc5179View commit details -
test: e2e coverage for encoded scoped purls, mismatch annotation, pru…
…ne lifecycle - scan_vendor_e2e: full pipeline with the API's percent-encoded scoped purl form (download -> vendor lookup against node_modules/@scope -> lock rewiring -> prune exemption); interactive pre-prompt baseline annotation + auto-force warning; scan --prune reverting an unused vendored entry (ledger + manifest + artifact + lock all reconciled) - clippy: too_many_arguments allow on stage_patch_pack, JsrPurlParts type alias Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 7042cbc - Browse repository at this point
Copy the full SHA 7042cbcView commit details -
feat(vendor): lockfile inventory module for npm-family locks
Read-only inventories of the dependency set a lockfile resolves, independent of what is installed: name/version/purl plus the lock's artifact URL and content verifier (typed LockIntegrity: SRI, yarn sha1 fragment, berry cache-zip checksum, sha256 hex, go.sum h1 — the latter two for the ecosystems that follow). Powers scan's lockfile supplement and vendor's missing-package fetch. Covers all five npm flavors via detect_npm_lock_flavor (package-lock/ shrinkwrap, pnpm v9, yarn classic, yarn berry, bun). Fail-soft per entry, fail-closed per value (names/versions path-guarded; git/file/ link/workspace specs and our own vendored entries excluded; duplicate instances dedup preferring a verifier). lookup() bridges percent- encoded manifest purls. Reuses the wiring backends' parsers via pub(super) visibility bumps. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 1a2dc4a - Browse repository at this point
Copy the full SHA 1a2dc4aView commit details -
feat(vendor): registry_fetch — verified pristine-artifact fetching
Downloads the artifact a lockfile entry resolves (lock-recorded URL, else the conventional npm registry URL; SOCKET_NPM_REGISTRY override), verifies it against the lock-recorded integrity FAIL-CLOSED before any disk write (strongest hash of a multi-hash SRI; yarn sha1 fragment; sha256 hex), and extracts to a private tempdir the vendor pipeline can stage from. Entries with no verifier are refused without any network I/O (Unverifiable). Hardening: http(s)-only, download/decompression/entry-count/entry-size caps, regular-files-only extraction with first-component strip + is_safe_relative_subpath (fail-closed on traversal-bearing tarballs, nothing half-extracts), exec bits preserved so the deterministic re-pack keeps bin scripts executable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 9c93b90 - Browse repository at this point
Copy the full SHA 9c93b90View commit details -
feat(vendor,scan): auto-fetch missing packages + lockfile/ledger disc…
…overy vendor: a manifest patch whose package has no installed copy is now satisfied automatically (no flag) instead of failing with package_not_installed: - already-vendored purls stage from their own committed artifact, sha256-verified against the vendor ledger (fresh-clone re-vendor and in-sync runs work offline, no registry traffic); - otherwise the lockfile-resolved pristine artifact is fetched (lock-recorded URL else conventional registry URL), verified against the lock's integrity FAIL-CLOSED, and staged from a private tempdir — the project tree is never touched. Reason codes: vendor_fetched_missing (skip-warning beside the Applied event), vendor_fetch_failed (distinct Failed, suppresses the duplicate not-installed skip), vendor_fetch_unverifiable (no lock integrity → calm skip). --offline keeps the calm skip and names the lockfile as the would-be source. scan: discovery now supplements the installed-tree crawl with (a) lockfile-only dependencies — warned '[NOT INSTALLED]' in the table + a stderr note, JSON lockfileOnlyPackages + packages[].notInstalled, counted as scanned so a wiped node_modules no longer prunes lockfile-listed entries, partitioned out of --apply BEFORE download (calm skipped/package_not_installed records, exit 0, no manifest writes) while --vendor passes them to the auto-fetch; and (b) vendored-ledger entries — the committed artifact IS the dependency, so updates[] detection and scan --vendor keep working on a fresh clone before any install. scan --json --vendor now vendors a completely fresh clone end-to-end (e2e-proven, second run already_vendored). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Configuration menu - View commit details
-
Copy full SHA for 18822dc - Browse repository at this point
Copy the full SHA 18822dcView commit details -
feat(vendor): yarn berry checksum-verified fetch + ledger artifact st…
…aging tests Berry locks never hash the tarball — the checksum is sha512 of the deterministic cache zip. The fetch rebuilds that zip from the fetched bytes via the same spike-pinned berry_zip recipe the wiring uses and compares the 10c0/<hex> value fail-closed (foreign cacheKeys are Unverifiable). Plus unit coverage for stage_local_artifact's ledger-sha256 gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 430145a - Browse repository at this point
Copy the full SHA 430145aView commit details -
feat(vendor): cargo + golang lockfile inventory and verified fetch
- Cargo.lock [[package]] inventory: crates.io-sourced entries carry their sha256 .crate checksum (Sha256Hex); workspace members skipped, git/custom-registry sources discovery-only. Fetch from static.crates.io (SOCKET_CRATES_REGISTRY override), verify, extract ({name}-{version}/ top dir) — feeds vendor_cargo_crate's pristine_src. - go.sum inventory: module-zip h1: lines (the /go.mod manifests-only lines skipped). Fetch from the module proxy (SOCKET_GOPROXY, else the standard GOPROXY's first non-direct element, else proxy.golang.org) with Go's !uppercase path escaping; verify the dirhash Hash1/HashZip in memory BEFORE extraction (algorithm validated against a live sum.golang.org lookup for golang.org/x/text@v0.14.0); extract with the explicit module@version/ prefix (module paths contain slashes, so a first-component strip would be wrong) — feeds vendor_go_module. - lookup() generalized across ecosystems; inventory_project() returns the union the scan supplement and vendor auto-fetch consume. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Configuration menu - View commit details
-
Copy full SHA for 16e7e54 - Browse repository at this point
Copy the full SHA 16e7e54View commit details -
feat(vendor): composer + gem + pypi lockfile inventory and verified f…
…etch - composer.lock packages[]/packages-dev[]: zip dists with their sha1 shasum (frequently empty → discovery-only); names lowercased to the packagist form, pretty leading v dropped; path dists (ours) excluded. Fetch verifies sha1 and strips the variable zipball top dir. - Gemfile.lock GEM/specs + bundler 2.6 CHECKSUMS sha256 (older locks discovery-only); the GEM remote drives the /downloads/<gem> URL. Platform-suffixed specs skipped (unsupported for vendoring). The fetched .gem (plain tar) is sha256-verified whole, then data.tar.gz extracts at the root (no prefix strip). - pypi: uv.lock registry packages with a pure py3-none-any wheel carry a fetchable URL + sha256; poetry.lock and ==-pinned requirements.txt contribute discovery-only entries (PEP 503-normalized names). The unzipped wheel is a site-packages-shaped stage for the pypi backend. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for b5e9f63 - Browse repository at this point
Copy the full SHA b5e9f63View commit details -
feat(scan): all-ecosystem lockfile supplement + docs
scan's lockfile supplement now consumes inventory_project (npm-family, Cargo.lock, go.sum, composer.lock, Gemfile.lock, uv/poetry/requirements) with per-ecosystem counts; the vendor auto-fetch pass likewise serves every inventoried ecosystem. CLI_CONTRACT.md gains the lockfile- supplement and vendor-auto-fetch sections + the three reason codes; README notes the fresh-clone flow; the exact-shape empty-scan contract test pins the additive lockfileOnlyPackages field; the cargo build e2e scrubs ambient CARGO_TARGET_DIR from child builds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 772f98d - Browse repository at this point
Copy the full SHA 772f98dView commit details -
feat(apply): beforeHash mismatch warns and applies the full blob by d…
…efault; --strict restores the hard error A file whose on-disk content matches NEITHER the patch's beforeHash nor its afterHash previously hard-failed the in-place apply (the flatted case: a patch built against non-registry bytes made plain apply unusable). The default now overwrites such files with the FULL verified patched content and continues: - core: apply_package_patch's force bool becomes MismatchPolicy {Warn (default) | Strict | Force}. Warn promotes HashMismatch to Ready keeping the warning signature (expected/current hashes); the diff strategy self-disables on a wrong base (partial patches are skipped, as they must be) and the archive/blob writes stay hash-gated to exactly afterHash — a tolerated mismatch lands verified patched bytes or fails, never silent corruption. Missing pre-existing files still fail closed (only Force skips them). - CLI: global --strict (env SOCKET_STRICT) restores the fail-closed behavior across apply/get/scan --apply/the hook/go redirects (--force overrides it); plumbed through DownloadParams into the nested applies. Vendor staging is unaffected (already auto-forces into its private stage). - Each overwrite logs a content_mismatch_overwritten warning to stderr and rides the JSON envelope as a Skipped warning event beside the package's Applied event. - Since the full content lives in the afterHash blob and the default --download-mode diff may not have staged it, a pre-apply pass probes for mismatches and downloads the missing blobs by hash (offline runs warn and let those files fail). Live-verified: pristine flatted@3.3.1 + its bad-baseline patch now applies 6/6 files via blob with per-file warnings (exit 0); apply --strict exits 1 with the old error and leaves files untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Configuration menu - View commit details
-
Copy full SHA for 0426e0b - Browse repository at this point
Copy the full SHA 0426e0bView commit details -
polish(apply): decode percent-encoded purls in human output
The 'Patched packages' summary and the no-matching-installed-package warning printed manifest keys verbatim (pkg:npm/%40scope/...); show the decoded form like the scan/vendor output does. JSON keeps verbatim keys. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 64c59f1 - Browse repository at this point
Copy the full SHA 64c59f1View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff main...feat/apply-mismatch-warning