Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a7b7019
Plan staged patch rollout for v5
claude Sep 28, 2026
d087a63
Revise rollout plan after adversarial review
claude Sep 28, 2026
bdbe735
Close interface gaps in the rollout plan
claude Sep 28, 2026
ff7a30a
Clarify who shapes scan's selection output
claude Sep 28, 2026
c434039
Merge remote-tracking branch 'origin/release/v5-prerelease' into v5/s…
claude Sep 28, 2026
3b6b95e
Add the rollout planner for capped scans
claude Sep 28, 2026
4fe9c6c
Add the socket.yml selection policy to core
claude Sep 28, 2026
b0eaacb
Cap new patches per scan, most critical first
claude Sep 28, 2026
7717f50
Test the scan cap end to end in every mode
claude Sep 28, 2026
f5db6be
Honor socket.yml patch policy in disk scans
claude Sep 28, 2026
d4c7b70
Merge work item A's policy core into the scan cap
claude Sep 28, 2026
c167b49
Cap new patches in the in-memory hosted engine
claude Sep 28, 2026
7eebde4
Document the per-run cap on new patches
claude Sep 28, 2026
ae6fa06
Apply socket.yml policy in the in-memory engine
claude Sep 28, 2026
48f2e78
Document the socket.yml patch policy
claude Sep 28, 2026
711ee3f
Fix rollout review findings
claude Sep 28, 2026
faa6ffc
Harden the socket.yml policy after review
claude Sep 28, 2026
a7a006a
Match zero-cap test to dry-run wording
claude Sep 28, 2026
566b528
Merge socket.yml policy (A) and wire its cap
claude Sep 28, 2026
b975913
Give the release test job more time
claude Sep 28, 2026
a5757a1
Merge socket.yml policy branch (A) at b975913
claude Sep 28, 2026
32cf3cd
Merge release/v5-prerelease into socket.yml policy
claude Sep 28, 2026
eb01114
Merge release/v5-prerelease (plan PR landed)
claude Sep 28, 2026
e1a35fe
Apply socket.yml paths during memory selection
claude Sep 28, 2026
ed6f51c
Keep excluded roots out of the memory stream
claude Sep 28, 2026
4b71112
Merge release/v5-prerelease (vlt rollback fix)
claude Sep 28, 2026
47d218f
Merge socket.yml branch (A) and base rollback fix
claude Sep 28, 2026
03aed58
Merge release/v5-prerelease (lockfile models)
claude Sep 28, 2026
6fe0989
Merge release/v5-prerelease (lockfile models)
claude Sep 28, 2026
38b1e9a
Merge release/v5-prerelease (setup removal)
claude Sep 28, 2026
9c7f2f1
Merge release/v5-prerelease (setup removal)
claude Sep 28, 2026
f680990
Keep scan -h short with the policy flags
claude Sep 28, 2026
0da9e4b
v5: keep scan -h within the option budget
claude Sep 28, 2026
c59c8f4
Merge v5/socket-yml-patch-config (scan -h fix)
claude Sep 28, 2026
65ef71f
Fail report-only JSON when detail queries fail
claude Sep 28, 2026
0881ded
Merge release/v5-prerelease (one hosted engine)
claude Sep 28, 2026
2270cb3
Merge v5/socket-yml-patch-config (one engine)
claude Sep 28, 2026
a6f5008
Merge release/v5-prerelease (CI tiers)
claude Sep 28, 2026
eeed6f6
Merge release/v5-prerelease (fewer downloads)
claude Sep 29, 2026
c28e7e4
Merge release/v5-prerelease (dead code removal)
claude Sep 29, 2026
23c89e8
Merge release/v5-prerelease (test suites)
claude Sep 29, 2026
1613348
Merge release/v5-prerelease (socket.yml landed)
claude Sep 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -678,14 +678,34 @@ into the new version's section — see docs/releasing.md.

### Added

- **`scan --max-new-patches <N|none>` rolls patches out gradually**
(env `SOCKET_MAX_NEW_PATCHES`; socket.yml `patches.maxNewPatches`).
Each run adds at most N patches to packages that had none, most severe first
(then by how many advisories a patch fixes), and defers the rest to the
next run; upgrades of packages that are already patched are never
capped, and `0` means upgrades only. Repeated scans on an unchanged repo
add the same packages in the same order and stop once everything is
patched. A patch that cannot land (not granted, refused by a preflight,
nothing in the lockfile to pin) never holds a slot, and a failed lookup
admits nothing new that run (`rollout_incomplete_lookup`). The project
directories of one scan share the budget. Works in hosted, vendored and
agent mode, `--dry-run` included; `scan --json` gains a top-level
`rollout` block (`maxNewPatches`, `counts`, ranked `deferred[]`) and
hosted mode lists deferred rows in `redirect.skipped[]` as
`rollout_deferred`.
- **The in-memory hosted engine paces rollouts too.** It (napi,
`hosted-bundle`) takes
`maxNewPatches`, `maxNewPatchesCap` and `inFlightPatches`, spends one
budget across every project root, and reports a session `rollout` block
and `ProjectResult.deferred[]`.
- **socket.yml patch policy (staged rollout).** A `patches` block in the
repo-root socket.yml narrows what `scan` patches: `enabled` (false =
report only), `includePaths` / `ignorePaths` (gitignore patterns matched
against each project's lockfiles, npm `ignore` semantics),
`ecosystems`, `packages` / `ignorePackages` (`--package` specs),
`minSeverity` (critical|high|medium|moderate|low, judged by the worst
advisory a patch fixes) and `maxNewPatches` (validated; the per-run cap
lands with `--max-new-patches`). List flags (`--ecosystems`,
advisory a patch fixes) and `maxNewPatches` (the per-run cap of
`--max-new-patches`). List flags (`--ecosystems`,
`--package`, PATHs) only narrow further; `--min-severity` beats the
file's floor and `--no-socket-yml` ignores the file. A package
that already carries a patch is never removed, upgraded or replaced by
Expand Down Expand Up @@ -1909,6 +1929,15 @@ into the new version's section — see docs/releasing.md.

### Changed

- **`scan` keeps a patch you already have unless the new one supersedes
it.** A package whose recorded patch (agent manifest, hosted lockfile
pin or vendor ledger) still ranks level with the top offer on every
meaningful rung (merged state, severity, a later publish date) keeps
its recorded patch instead of switching on the tier or uuid tiebreak,
so re-running `scan` never swaps patches. `updates[]` and the
`[UPDATE]` marker now use the per-package records the selection itself
uses, so they list exactly the upgrades the run applies; a JSON
report-only run still reads the batch records.
- **Fewer downloads in vendored runs.** A vendored run now asks the patch
service for all of its planned packages' download references in one
request (in chunks of 500) from the first package it reaches, in place
Expand Down
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,13 @@ the same way everywhere, from the patches your account can download:

"Newest" is when the patch was published, not the package version. When a better patch
appears for a package you already patched, the JSON `updates[]` array lists it and the
next `scan` in the same mode takes it.
next `scan` in the same mode takes it. A patch that only wins on the tier or UUID
tiebreak never replaces one you already have, so re-running `scan` never swaps patches.

This order picks the patch *for* a package. When a capped scan
([`--max-new-patches`](#add-a-few-new-patches-per-run)) has to choose *which packages*
get their first patch, it takes the most severe first, then the ones fixing the most
advisories.

### State in `.socket/`

Expand Down Expand Up @@ -416,6 +422,37 @@ hosted and vendored mode each PATH is a project directory, scanned as if it were
To make the choice stick for everyone who runs `scan` in the repo (CI and the Socket
autopatch bot included), put it in `socket.yml` instead — see
[Roll out gradually](#roll-out-gradually-with-socketyml).
### Add a few new patches per run

```bash
socket-patch scan --max-new-patches 5 # at most 5 packages get their first patch
socket-patch scan --max-new-patches 0 # only upgrade patches you already have
socket-patch scan --max-new-patches none # no cap this run
```

A capped scan patches the most critical packages first: by the severity of the patch,
then by how many advisories it fixes. Upgrades of packages that are already patched are
never capped. Commit the result and run `scan` again to add the next batch; repeated
runs on an unchanged repo add the same packages in the same order and stop once
everything is patched. `--dry-run` shows exactly what the run would add and defer, and
`--json` reports it under `rollout` (`jq '.rollout.counts.deferred'`). In hosted and
vendored mode, several project directories in one run (`scan apps/*`) share the cap,
visited in sorted order; `--json` takes one directory, so a CI job per directory gets
its own N.

To drip patches in through a PR bot, set the cap once in the repo's `socket.yml`
(part of its [`patches:` policy](#roll-out-gradually-with-socketyml); the flag and
`SOCKET_MAX_NEW_PATCHES` override it, and `--no-socket-yml` ignores it):

```yaml
# Weekly drip with the depscan autopatch PR
version: 2
patches:
maxNewPatches: 5 # the PR keeps the same 5 until merged, then the next 5
```

A cap only advances when the scan's changes are committed (or merged by a PR bot). In a
CI job that scans without committing, set no cap.

### Patch one specific CVE or advisory

Expand Down Expand Up @@ -650,6 +687,7 @@ socket-patch scan [PATHS]... [options]
| `--package <name\|purl>` | `SOCKET_SCAN_PACKAGES` | Only scan these packages: a name (`lodash`, `@scope/pkg`, `requests`; case-insensitive) or a purl with or without its version (`pkg:npm/lodash`, `pkg:pypi/requests@2.31.0`). Repeat the flag or separate with commas. |
| `--prune` | — | Agent-mode garbage collection after the scan: remove manifest entries for packages no longer present in the crawl (installed trees + lockfiles — a wiped `node_modules` alone doesn't prune lockfile-listed entries) and delete orphan blob/diff-archive files (plus any legacy package archives). [Vendored](#vendor) packages are exempt from the crawl-based prune, but a vendored entry whose dependency has left the lockfile is reverted. Ignored, with a `redirect_prune_ignored` warning, in hosted mode; without a mode the scan is report-only. |
| `--sync` | — | Shorthand for `--mode agent --prune`: the one-flag agent-mode auto-update run. |
| `--max-new-patches <N\|none>` | `SOCKET_MAX_NEW_PATCHES` | Add at most N patches to packages that have none yet, most severe first; the rest are deferred to the next scan and listed in the output. Upgrades of already-patched packages are not capped. `0` adds no new patches, `none` means no cap (it also lifts a `socket.yml` `patches.maxNewPatches`). See [Add a few new patches per run](#add-a-few-new-patches-per-run). |
| `--batch-size <n>` | `SOCKET_BATCH_SIZE` | Packages per API request (default: `500` on the authenticated API, `100` on the public proxy). A request whose body would exceed 256 KiB is split into smaller ones. |
| `--min-severity <level>` | `SOCKET_MIN_SEVERITY` | Only patch packages whose patch fixes an advisory of at least `critical`, `high`, `medium` (or `moderate`) or `low`; `none` lifts the floor. Overrides `patches.minSeverity` in socket.yml. Patches of unknown severity are skipped whenever a floor is set. |
| `--no-socket-yml` | `SOCKET_NO_SOCKET_YML` | Ignore the repo's socket.yml patch policy for this run (the built-in test/fixture directory ignores still apply). |
Expand Down Expand Up @@ -678,6 +716,9 @@ socket-patch scan --package lodash
# Two projects of a monorepo
socket-patch scan apps/web apps/api

# Roll out gradually: at most 5 new patches, most critical first
socket-patch scan --max-new-patches 5

# Vendored mode: build + commit every patched dependency
socket-patch scan --json --mode vendored

Expand Down
Loading
Loading