fix(scan): scope takeover cleanup per package, warn on hosted --prune - #191
fix(scan): scope takeover cleanup per package, warn on hosted --prune#191Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
Conversation
The mode-takeover warning told users to delete the whole redirect ledger (vendored direction) or the whole .socket/vendor/<eco>/ tree (hosted direction). Following it destroyed live data for packages the takeover never touched: other packages' VEX records, the only recorded pre-redirect lockfile originals, and still-live vendored artifacts. The remediation is now per-package and non-destructive — run `socket-patch remove <purl>` per named package (hosted direction) or delete only the named records from the redirect ledger (vendored direction) — and explicitly warns against whole-file/tree deletion and blanket reverts. `scan --mode hosted --prune` silently dropped --prune: both hosted terminals return before the GC blocks, so a bot migrating from `--mode agent --prune` stopped pruning forever with exit 0 and no signal. The flag stays accepted (an orthogonal knob per the CLI contract), but the run now emits an explicit `redirect_prune_ignored` warning on stderr and in the JSON `redirect.warnings[]`, including the zero-discovery envelope. Two takeover blind spots are also closed. A redirect ledger whose every record fetch failed (edits present, records empty) was invisible to overlap detection; the vendored purls are now matched against the recorded edit keys so the stale ledger is still flagged. And hosted liveness was proved only by a hardcoded patch.socket.dev inventory URL — structurally unprovable for yarn-berry (inventory resolved is always None), bun (URL 3-tuples are skipped), and any non-default patch host. It is now proved by the record's patch uuid: in the inventory URL on any host, or in the redirect-edited lockfile text outside a .socket/vendor/<eco>/ path (vendored wiring embeds the same uuid, so only non-vendored occurrences count). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit a9f2e45. Configure here.
| // The scan inventory keeps only http(s) `resolved` URLs and DROPS our own | ||
| // `file:.socket/vendor/…` specs (see `lock_inventory`), so a | ||
| // `patch.socket.dev` resolved for a purl is a purl-scoped proof the lock now | ||
| // points at hosted. |
There was a problem hiding this comment.
Cleanup leaves sticky takeover warning
Medium Severity
Vendored-direction cleanup tells operators to drop only records and keep edits. After those records are gone, overlapping_ledger_purls treats the leftover edits as a degraded ledger and still reports the same packages, so the takeover warning can keep firing—especially when the takeover cleared the last redirect records.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit a9f2e45. Configure here.
| VEX do not read superseded wiring. Do not delete the whole \ | ||
| `.socket/vendor/<eco>/` tree and do not run `vendor --revert`: \ | ||
| other vendored package(s) may still be live in the lockfile and \ | ||
| would break or be mass-reverted." |
There was a problem hiding this comment.
Remove advice drops live hosted patch
Medium Severity
Hosted-direction takeover text says socket-patch remove only drops the stale vendored ledger entry and its uuid directory. remove also rolls back applied files and deletes the manifest patch, so following the warning can strip the still-live hosted package from .socket/manifest.json.
Reviewed by Cursor Bugbot for commit a9f2e45. Configure here.


Problem
Four audit findings (2026-08-13 adversarial audit of origin/main 4e5288e) around the mode-takeover warning and hosted-mode flag handling:
Destructive takeover remediation (medium) — the takeover warning fires per package, but its cleanup advice was file/tree scoped. Vendored direction told users to delete the whole
.socket/vendor/redirect-state.json, destroying other packages' live VEX records and the only recorded pre-redirect lockfile originals. Hosted direction told users to delete the whole.socket/vendor/<eco>/tree (which holds every vendored uuid dir, including still-live packages) or run a blanketvendor --revert(mass-reverting unrelated packages). Concrete failure: redirect packages A and B, vendor A, follow the warning literally →vexstops attesting B and B's pre-redirect lock fragment is unrecoverable.scan --mode hosted --prunesilently drops--prune(low) — both hosted terminals return before the GC blocks, so a bot migrating from--mode agent --prunestops pruning forever with exit 0, no warning, and a JSON envelope that simply omits thegckey.Takeover detection blind to degraded ledgers (low) — a hosted run where every record fetch failed persists a ledger with edits but an empty
recordsmap;overlapping_ledger_purlsderived the overlap exclusively from record keys, so a later vendored takeover of those same packages emitted no warning at all.Hosted direction proof hardcoded
patch.socket.devand could not see berry/bun wiring (low) — liveness was proved only by the inventoryresolvedURL containing the default hostname, so non-default patch hosts (staging,--patch-server-urldeployments) were unprovable, and yarn-berry (inventoryresolvedalwaysNone) plus bun (URL 3-tuples skipped by the inventory) were structurally unprovable.No findings were skipped. Note: the in-flight branch
work/mode-takeover-fixis content-identical to what is already merged as PR #164 and covers neither blind spot, so nothing here duplicates it.Fix
mode_takeover_detailnow gives per-package, non-destructive cleanup. Hosted direction: runsocket-patch remove <purl>per named package — its revert path is drift-guarded (vendor_lock_entry_drifted), so when hosted has won the lockfile it drops only that ledger entry and its own.socket/vendor/<eco>/<uuid>/dir without touching the live wiring — with an explicit warning against tree deletion and blanket reverts. Vendored direction: delete only the named packages' entries underrecordsinredirect-state.json, with an explicit warning against deleting the file (it holds other packages' live records plus the pre-redirect originals inedits).--prunewith--mode hostedstays accepted (CLI_CONTRACT documents it as an orthogonal knob that never conflicts, so a hard error would break existing pipelines) but now emits an explicitredirect_prune_ignoredwarning on stderr (human path, once inrun) and in the JSONredirect.warnings[], including the zero-discovery envelope. CLI_CONTRACT.md and the arg docs name the code.overlapping_ledger_purlsfalls back to matching vendored purls against the recordedFileEditkeys (name,name@version,/namesuffix) whenrecordsis empty buteditsexist. The fallback only activates on the degraded shape, so the well-formed-ledger path is unchanged, and the direction gate inclassify_overlap_takeoverstill requires live-lock proof before anything is reported.Hosted liveness is now proved host-agnostically by the record's patch uuid: in the inventory
resolvedURL on any host (patch.socket.devkept only as a no-record fallback), or in the redirect-edited lockfile text outside a.socket/vendor/<eco>/path — making berry (::__archiveUrl=bindings) and bun (URL 3-tuples) provable. Vendored wiring embeds the same uuid in its path, so only non-vendored occurrences count (guard test included); ledger-named files pass through the same traversal guard asvendored_wiring_live(extracted asis_safe_project_rel_file). Unprovable direction still stays silent rather than guessing.Testing
cargo test -p socket-patch-cli --lib— 373 passedcargo test -p socket-patch-cli --test cli_parse_scan— 48 passedcargo test -p socket-patch-cli --test in_process_scan— 23 passedcargo test -p socket-patch-cli --test in_process_redirect— 24 passedNew tests:
takeover_detail_remediation_is_per_package_and_non_destructive(verified red against the pre-fix remediation text)overlap_detected_when_redirect_ledger_has_edits_but_no_recordshosted_direction_provable_on_non_default_patch_hosthosted_direction_provable_for_bun_url_tuplehosted_direction_provable_for_berry_archive_urlvendored_path_uuid_does_not_prove_hosted(guard: a vendored-path uuid must not prove hosted)hosted_prune_emits_explicit_ignored_warning(subprocess--jsoncontract: warning present, nogckey, redirect unaffected)🤖 Generated with Claude Code
Note
Medium Risk
Changes warning text and overlap/takeover logic that drives CI bots and cleanup actions; behavior is safer but mis-detection could still mis-route users; no auth or network contract changes.
Overview
Fixes scan mode-takeover warnings and hosted-mode flag handling so automation and operators get accurate signals and safe cleanup guidance.
Per-package takeover remediation —
mode_takeover_detailno longer tells users to delete wholeredirect-state.jsonor entire.socket/vendor/<eco>/trees. Hosted wins: usesocket-patch remove <purl>per listed package; vendored wins: remove only those packages’recordsentries, keeping other live redirects andeditsrevert data.Hosted +
--prune—scan --mode hosted --prune(and--sync) still succeeds but emitsredirect_prune_ignoredon stderr and in JSONredirect.warnings[], including the zero-discovery hosted envelope, so migrations from agent sync jobs don’t silently stop GC.Overlap / direction detection —
overlapping_ledger_purlscan match vendored packages when the redirect ledger has edits but emptyrecords(failed record fetch). Hosted liveness is proved by patch UUID in inventoryresolvedURLs (any host, not onlypatch.socket.dev) or in redirect-edited lockfile text outside vendored paths, covering bun URL tuples and yarn berry::__archiveUrl=bindings; vendored-path UUID matches are excluded. Ledger lockfile reads use a shared path traversal guard.Reviewed by Cursor Bugbot for commit a9f2e45. Configure here.