patch
Render an Ansible role that bumps exactly the packages a cve-scan found still vulnerable to their vendor-fixed version, staying on the same release — no cross-distro translation. It reuses the scan/narrow path directly, then groups findings by package: when one package has several CVEs with different fixed versions, it is bumped to the highest one so a single task clears them all. With --apply it also executes the role over SSH against the same host and re-scans to confirm.
Needs credentials — the advisory lookup and any --sign go to the API. Like cve-scan, the underlying scan is license-gated and never metered; patch itself adds no billable charge. rpm/dpkg only — Portage has no reliable exact-version pin via ansible.builtin.package, so patch refuses rather than emit a task that might not pin the version it claims.
vrtmv patch --root /mnt/snap/web01 --all-fixable --sign -o patch/
vrtmv patch --root /mnt/snap/web01 --cve CVE-2026-1234 --cve CVE-2026-5678 -o patch/
vrtmv patch --ssh deploy@web01.corp --all-fixable --apply -o patch/
| Flag | Purpose |
|---|---|
--root / --image / --ssh | Exactly one source (see Sources). --apply requires --ssh. |
--ssh-port, --ssh-key, --jump, --sudo | SSH collection options. |
--cve <id> | Patch only this CVE (repeatable). Mutually exclusive with --all-fixable. |
--all-fixable | Patch every CVE the scan finds still unfixed. |
--arch <arch> | Scope arch-specific advisories (e.g. x86_64). |
--sign | Ask the API to Ed25519-sign the patch plan. Needs credentials. |
--apply | Execute the role over SSH against the same host, then re-scan to confirm. Requires --ssh. |
-o, --out <path> | Output directory for the role + report (default vrtmv-patch). |
--json | Emit the plan as JSON instead of a text summary. |
A requested --cve that matches no current finding — not applicable to the release, not installed, or already fixed — is reported in unmatched_cves, never silently dropped.
--apply
Runs the patch immediately over SSH against the exact host it was scanned from (the same ansible-playbook invocation run uses), then re-scans fresh and diffs against what was targeted. It never claims a fix worked because ansible-playbook exited 0 — it re-checks, and its exit code reflects the confirmed outcome: it fails if the playbook reported failures or if the re-scan still finds any targeted CVE.
Three things --apply does that render-only does not:
- Requires
--ssh. A mounted--root/--imageis a static filesystem, not a running system to execute against, and refuses--apply. - Excludes epoch-ambiguous packages from what it auto-applies (a non-zero-epoch rpm's pinned spec is a documented best-effort gap). These are named in
excluded_epoch_ambiguousand left for manual patching. - Always renders a rollback role alongside (
roles/vrtmv_patch_rollback/), targeting the pre-patch version. It is not run automatically — it is there so a bad patch has an immediate undo. Rolling back reintroduces the CVEs the forward patch fixed; it is not itself a security action.
The executed role also appends a non-blocking, reported restart-recommendation check (needs-restarting -r on rpm, /var/run/reboot-required on Debian/Ubuntu): a package can be upgraded on disk while the running process keeps the old code loaded, and the package database cannot see that.