Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 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
4fe9c6c
Add the socket.yml selection policy to core
claude Sep 28, 2026
f5db6be
Honor socket.yml patch policy in disk scans
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
faa6ffc
Harden the socket.yml policy after review
claude Sep 28, 2026
b975913
Give the release test job more time
claude Sep 28, 2026
32cf3cd
Merge release/v5-prerelease into socket.yml policy
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
6fe0989
Merge release/v5-prerelease (lockfile models)
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
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
997a6f5
Merge release/v5-prerelease (CI tiering)
claude Sep 28, 2026
0c5a8cd
Merge release/v5-prerelease (stage repair fix)
claude Sep 29, 2026
d9dd0ff
Merge release/v5-prerelease (dead-code removal)
claude Sep 29, 2026
29674bb
Merge release/v5-prerelease (per-command tests)
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
49 changes: 49 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -652,8 +652,57 @@ into the new version's section — see docs/releasing.md.
batch is reported as failed (warning, or the all-failed error when it was
the only batch) — instead of that one package being skipped silently.

- **scan honors the repo's socket.yml.** `projectIgnorePaths` (the
scanner's key) now also keeps `scan` from patching the matching projects,
in every mode and in the in-memory engine, whether or not the file has a
`patches` block (malformed values there only warn
`socket_yml_ignored_value`). See "socket.yml patch policy" in
CLI_CONTRACT.md.
- **Test and fixture trees are skipped by default when scan discovers
projects.** `test/ tests/ fixtures/ __fixtures__/ testdata/` (any case)
are built-in `ignorePaths` for discovered roots: hosted/vendored
PATH-glob matches (`scan 'services/*'`) and the in-memory engine's
detected roots (which used to skip them through a hard-coded, case-
sensitive segment list). A directory you name (`--cwd`, a literal PATH,
`projectRoots`) is not affected; `ignorePaths: ["!/e2e/tests/"]`
re-includes one, in memory too.
- **An invalid socket.yml fails scan.** An unparseable file, a misspelled
top-level `patches` key (`Patches`, `patchs`), a top-level merge or
aliased key, an invalid `patches` block (unknown key, wrong type, bad glob, `patches`
without `version: 2`), or `socket.yml` and `socket.yaml` that disagree
now fail `scan` before any request or write: exit 1, `errorCode:
socket_yml_invalid` / `socket_yml_ambiguous`, the key path and the fix
in the message. `--no-socket-yml` ignores the file for one run.
- **scan rejects a PATH outside the repository root** (exit 2): one socket.yml
policy per invocation.

### Added

- **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`,
`--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
the policy: it is held and reported under `policy.retained[]`. New flags
`--min-severity` / `SOCKET_MIN_SEVERITY` and `--no-socket-yml` /
`SOCKET_NO_SOCKET_YML`; every successful `scan --json` result gains a
top-level `policy` block (`source`, `sha256`, `minSeverity`, `filtered[]`,
`retained[]`) and the human output a `Policy (socket.yml): …` line that
names every skipped project and every critical/high patch the severity
floor held back. In memory, selection is two-phase:
`selectHostedScanPaths` takes the root policy files' text
(`policyFiles`) and `noSocketYml`, applies the full path policy and
returns `policyPaths`, `policySha256` and `policyError`; the session
takes `noSocketYml` / `minSeverity` / `policyPaths` / `policySha256` and
its result carries `policy` or `policyError`.
`get` ignores the policy and warns `policy_bypassed`.

- **`scan --package <name|purl>`** (repeatable or comma-separated, env
`SOCKET_SCAN_PACKAGES`) scopes a scan to the named packages: a name
(`lodash`, `@scope/pkg`, `group:artifact`) or a purl with or without its
Expand Down
127 changes: 125 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ serial_test = "=3.4.0"
napi = { version = "=3.13.0", features = ["napi8", "tokio_rt"] }
napi-derive = "=3.6.9"
napi-build = "=2.5.0"
serde-saphyr = { version = "=1.3.0", default-features = false, features = ["deserialize"] }
ignore = "=0.4.33"

[profile.release]
strip = true
Expand Down
72 changes: 72 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,10 @@ socket-patch scan 'services/*' # directory glo
hosted and vendored mode each PATH is a project directory, scanned as if it were
`--cwd` under an `== <dir> ==` header; the worst exit code wins.

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).

### Patch one specific CVE or advisory

```bash
Expand Down Expand Up @@ -647,6 +651,8 @@ socket-patch scan [PATHS]... [options]
| `--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. |
| `--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). |
| `--all-releases` | `SOCKET_ALL_RELEASES` | Store patches for every release/distribution variant, not just the installed one — PyPI wheel/sdist, RubyGems platform, Maven classifier. Makes the manifest portable across environments (e.g. cross-platform CI caches). |
| `--vex <path>` | `SOCKET_VEX` | On a successful scan, also write an OpenVEX 0.2.0 document to this path. See [Inline VEX](#inline-vex-on-apply--scan--vendor). |
| `--vex-product`, `--vex-no-verify`, `--vex-doc-id`, `--vex-compact` | `SOCKET_VEX_*` | Passthrough to the embedded VEX builder; mirror the standalone [`vex`](#vex) knobs. Inert unless `--vex` is set. |
Expand Down Expand Up @@ -692,6 +698,72 @@ socket-patch scan --vex socket.vex.json
> artifact is the patch); a newer available patch still appears in `updates[]` — re-run
> `scan --mode vendored` to take it.

#### Roll out gradually with socket.yml

A `patches` block in the repo-root `socket.yml` (the file the Socket scanner already
reads; keep `version: 2`) narrows what `scan` may patch, for every mode and for the
in-memory engine behind the Socket autopatch bot. It can only narrow: nothing in it can
name an endpoint or token, pick a mode, or turn off a safety check.

```yaml
# Critical first: widen by editing one line
version: 2
patches:
minSeverity: critical # later: high, then low, then remove the key
# (low still skips patches whose severity is unknown)
```

```yaml
# One directory first (monorepo)
version: 2
patches:
includePaths:
- "/services/payments/"
# add "/services/checkout/" next sprint
```

```yaml
# One ecosystem, hold one package
version: 2
patches:
ecosystems: [npm]
ignorePackages: ["pkg:npm/left-pad"]
```

```yaml
# Pause: report only; existing patches stay in place
version: 2
patches:
enabled: false
```

- Paths are gitignore patterns (the same rules as `projectIgnorePaths`, which scan now
honors too), matched against each project's lockfiles: `"/services/payments/"`,
`"**/yarn.lock"`, `"examples/**"`. `test/`, `tests/`, `fixtures/`, `__fixtures__/`
and `testdata/` directories are skipped by default when scan discovers projects
(a directory glob such as `scan 'services/*'`); re-include one with a negation
(`ignorePaths: ["!/e2e/tests/"]`). A directory you name yourself is always scanned.
(The autopatch bot's tree listing skips those directories before it reads
socket.yml, so there a negation cannot bring one back.)
- `packages` / `ignorePackages` take `--package` specs; prefer purls (`pkg:npm/core`),
because a bare name also matches other ecosystems and scoped packages (`core`
matches `@babel/core`).
- Narrowing never removes a patch: a package that already carries one and is now
filtered out is left exactly as it is (reported under `policy.retained[]`). Use
`rollback` or `remove` to take a patch out.
- A broken file fails the scan (exit 1, `errorCode: socket_yml_invalid`) before anything
is written, with the key and the fix in the message — a typo never widens the
rollout. `--no-socket-yml` ignores the file for one run.
- `scan --json` reports what the policy did in a top-level `policy` block
(`jq '.policy.counts'`); the human output adds a `Policy (socket.yml): …` line that
names every skipped project and every critical/high patch the severity floor held
back (`--verbose` lists everything). `get` ignores the policy (explicit
intent) and warns `policy_bypassed`.

Every key: `enabled`, `includePaths`, `ignorePaths`, `ecosystems`, `packages`,
`ignorePackages`, `minSeverity`, `maxNewPatches` — see CLI_CONTRACT.md "socket.yml patch
policy" for the full grammar, precedence and validation rules.

### `vex`

Generate an [OpenVEX](https://github.com/openvex) 0.2.0 attestation describing the
Expand Down
Loading
Loading