Skip to content

Human-output scan --mode agent / --sync still never re-applies an already-recorded patch after a reinstall (#454 fixed only the --json path) #732

Description

[agent] Found by the scheduled npm bug-hunt routine (ledger #302). The Bun routine noticed it first and handed it over (ledger entry entries/npm/20261003T193043Z-from-bun.md).

Summary

#454 ("scan --sync / --mode agent never re-applies an already-recorded patch") was fixed by #456 in the shared fetch loop: patches already recorded in .socket/manifest.json now count towards the nested apply (get.rs to_apply = downloaded + batch.already_recorded). But the human-output scan path drops those selections before they reach that loop. crates/socket-patch-cli/src/commands/scan/mod.rs:2733-2771 partitions every selection whose uuid is already recorded into already_recorded, prints [skip] … (already recorded: …), and when nothing else is left returns finish_human(0) without applying anything. That partition came in with de316b4 (#358), merged six minutes before the #456 fix, so #454 still reproduces whenever --json is omitted.

So the same scan --mode agent (or scan --sync) command patches the files with --json and leaves them unpatched without it. get <purl> --mode agent (human) does re-apply.

Impact

After any reinstall (npm ci, rm -rf node_modules && npm install, a CI cache miss), a human-output socket-patch scan --mode agent or scan --sync exits 0 and leaves the vulnerable bytes installed. It prints "All selected patches are already recorded in the manifest; run socket-patch apply to re-apply them.", but a CI log or a cron job only sees exit 0. vex afterwards refuses (not_applied), so attestation stays honest. Only the disk state is wrong.

Repro (npm, Linux, main 045d7ec)

A local mock of the patch API serves one free patch for left-pad@1.3.0, prepending /* SOCKET-PATCHED */ to index.js.

mkdir p && cd p && git init -q
echo '{"name":"p","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}' > package.json
npm install
socket-patch scan --mode agent --yes          # patched
rm -rf node_modules && npm ci                 # pristine bytes again
socket-patch scan --mode agent --yes          # or: scan --sync --yes
#   [skip] pkg:npm/left-pad@1.3.0 (already recorded: 11111111)
#   All selected patches are already recorded in the manifest; run `socket-patch apply` to re-apply them.
#   exit 0, node_modules/left-pad/index.js still unpatched
socket-patch scan --mode agent --yes --json   # apply.applied: 1, file patched

Expected vs actual

Cells

OS npm / Node human scan --mode agent after npm ci human scan --sync --json
Linux 6.14.18 / 22.22 unpatched, exit 0 — re-applied
Linux 10.9.4 / 22.22 unpatched, exit 0 (×3) unpatched, exit 0 re-applied
Linux 12.2.0 / 24 unpatched, exit 0 — re-applied
Linux (Bun 1.4.2, from the handover) — unchanged — re-applied

The decision is in OS-independent code, so I didn't run a macOS / Windows probe.

First bad version

Suspect code

crates/socket-patch-cli/src/commands/scan/mod.rs:2733-2771: the already_recorded partition and the early finish_human(0).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions