Files
cc-ci-orchestrator/.claude/skills/cve-check-and-upgrade/SKILL.md
T
autonomic-bot b0bdce2c15 add /cve-check and /cve-check-and-upgrade
/cve-check answers 'what are we exposed to that an upgrade would fix?' without
running an upgrade: per-recipe, resolve the available window for EVERY image
(sidecars included), run the advisory scan over it, adjudicate whatever pass 1
could not decide, publish a report. Read-only — no PRs, no CI, no merges.

/cve-check-and-upgrade does that sweep, then runs /recipe-upgrade only on the
recipes whose upgrade actually closes a CVE, worst severity first, and reports
on both. --min-severity high for just the urgent ones; --dry-run prints the
queue and stops. Never merges.

Deliberate choices, each written into the skills:
- externals are SWEPT but never upgraded here — a security sweep that skipped
  deployed software would misreport exposure, but we don't maintain them.
- an unknown count never justifies an upgrade AND is never treated as clean;
  it goes to the Addendum.
- no upgrade available means 0 CVEs, not '?'.
- subagents are told which CVEs justify their upgrade, so the PR says why it
  exists — a PR naming the RCE it closes gets reviewed sooner.

recipe-report.py grows a page kind: 'cve' files as cve-DATE.html so a sweep
can't overwrite a weekly edition, while BOTH appear in the same archive index,
suffixed 'full report' / 'CVE check'.

/help and /cc-ci-status updated to route to them.
2026-08-11 04:04:59 +00:00

92 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: cve-check-and-upgrade
description: Security-driven upgrade run. Does a full /cve-check sweep first (per-image advisory scan of every recipe's available upgrade, with adjudication), then runs /recipe-upgrade ONLY on the recipes whose upgrade fixes at least one CVE — worst severity first — opening a verified recipe PR for each, and finally publishes one report covering both the sweep and the PRs. Recipes with no CVEs are left alone; that is the point. NEVER merges. Invoke as /cve-check-and-upgrade [recipe ...] [--min-severity high] [--capacity N] [--dry-run].
---
# cve-check-and-upgrade
`/upgrade-all` upgrades everything that *has* an upgrade. **This upgrades what has a reason.** It runs
the `/cve-check` sweep, then spends CI time only on the recipes where an upgrade actually closes a
vulnerability, handling the worst first.
Use it when you want to act on security rather than churn the whole fleet: after a vendor announcement,
when CI capacity is short, or between weekly runs. When you only want to *know*, use `/cve-check`. When
you want everything current regardless of CVEs, use `/upgrade-all`.
**Creates PRs. Never merges.** Every PR is verified green on cc-ci and left for a human.
## Arguments
- `<recipe> …` — restrict the whole run to these recipes.
- `--min-severity critical|high|medium|low` — only upgrade recipes whose fixed CVEs reach this
severity. Default **`low`** (any CVE at all justifies the upgrade). `--min-severity high` is the
useful "just the urgent ones" setting.
- `--capacity N` — subagent pool size; defaults to the live `DRONE_RUNNER_CAPACITY` (the drone
runner's slots), matching `/upgrade-all`'s rolling-pool behaviour.
- `--dry-run` — do the whole sweep and print exactly which recipes *would* be upgraded and why, then
stop without spawning a single upgrade. **Publishes no report and opens no PR.**
## Procedure
### 1. Sweep — run `/cve-check` in full
Follow `.claude/skills/cve-check/SKILL.md` steps 1–5 exactly: candidate list, per-image upgrade windows,
the advisory scan per recipe, pass-2 adjudication of anything undecided, and the severity classification.
**Do not publish its report** — this run produces one combined report at the end instead.
Keep, per recipe: the windows scanned, the CVE count, the CVE ids with severities, and whether the count
is a floor (undetermined advisories remain) or unknown.
### 2. Decide what to upgrade
`RECIPES_TO_UPGRADE` = recipes where **the scan found ≥1 CVE** at or above `--min-severity`.
Deliberate exclusions, each recorded in the report with its reason:
- **0 CVEs** — an upgrade may exist, but nothing security-relevant. Left alone; that is the point of
this skill. `/upgrade-all` is what sweeps those up.
- **`external` tier** — swept for visibility, **never upgraded here**; someone else maintains it. Flag
it loudly in the report if it has a critical, since the action is to tell them, not to open a PR.
- **`UPTODATE`** — nothing available.
- **count `?` / UNKNOWN** — do **not** upgrade blind, and do **not** treat it as clean. Put it in the
Addendum as needing a look. An unknown is a gap in our knowledge, not evidence of safety.
Order the queue by **worst severity first** (critical → high → …), count breaking ties. If `--dry-run`,
print this queue with each recipe's CVE ids and severities, and STOP here.
### 3. Upgrade each one — via `/recipe-upgrade` subagents
Run `/recipe-upgrade <recipe>` per queued recipe as a **subagent**, in the queue order above, as a
**rolling pool** keeping `--capacity` (default `DRONE_RUNNER_CAPACITY`) running at once and starting the
next as each finishes — the same concurrency discipline as `/upgrade-all` §3, and safe for the same
reason (per-run recipe trees + app-domain locks).
Each subagent does the full job: plan, implement the bump, verify green on cc-ci with `!testme`, and
open a recipe PR. **Default mode — no `--with-tests`**: a genuinely stale test gets an explanatory PR
comment, not a test edit.
**Tell each subagent which CVEs justify its upgrade**, with ids and severities, so the PR description
says why it exists. That is most of this skill's value to a reviewer: a PR that names the CVSS-9.8 RCE
it closes gets merged today, an unexplained version bump waits a fortnight.
Collect per recipe: PR url + number, the `!testme` verdict and build number, and any failure.
### 4. Report — one page covering sweep AND PRs
Write `/tmp/cve-spec-<DATE>.json` per `/cve-check` step 6, with these differences:
- Rows for upgraded recipes carry the real `ci` (`build N ✓` / `RED N · <stage>`) + `ci_url`, and
`pr`/`pr_url`. `status` is the CI verdict (`GREEN`/`FAILED`/`STALE`); the live PR-status column
derives itself from `recipe` + `pr`.
- Rows for swept-but-not-upgraded recipes keep `PENDING`/`UPTODATE` with empty `ci`/`pr`, and a
`notes` reason (`0 CVEs — not upgraded`, `external — maintained elsewhere`, `below --min-severity`).
- Include `changes[]` — one entry per recipe that got a PR, describing what the upgrade changes **and
the CVEs it closes**.
- Keep `"kind": "cve"`: it titles the page "The Recipe Report — CVE check" and files it as
`cve-<DATE>.html`, alongside the weekly editions in the same archive index.
Then render + publish exactly as `/cve-check` step 7, and verify as its step 8. Print the report URL,
`N swept · M upgraded · K PRs green · J failed`, and `CVE CHECK AND UPGRADE COMPLETE`.
## Guardrails
- **NEVER merge.** Create and verify; a human merges. Never push to true upstream.
- **Never weaken a test** to make a PR green, and never edit a test without `--with-tests`.
- **Never upgrade a recipe whose CVE count is unknown** on the assumption it is fine — surface it.
- **Never upgrade an `external` recipe** here, even with a critical; report it instead.
- **Public-safe report only** — no secrets, tokens, internal hostnames, raw logs, or spend figures.
- If the sweep finds **nothing** at or above `--min-severity`, that is a good outcome: publish the
report saying so and open no PRs. Do not manufacture work.