# ADR-0027 — Vulnerability visibility: scheduled digest scanning with a Renovate-shaped bot - Status: Accepted - Date: 2026-11-09 - Serves: R-VULN-01..09, R-OBS-02, R-OBS-03, R-C2-02, R-UPD-02, R-SEC-02, R-IDP-06 - Supersedes: — - Accepted by: operator merge of this change; effective on merge. ## Context The operator has no view of the vulnerabilities in what production runs. Renovate moves versions forward on a schedule, but it knows nothing about CVEs, and nothing in the platform assesses a running image. Measured on 2026-11-09: - 259 containers run from 98 unique digests, across eight or more registries, with no scanner present. - Prometheus holds 427k head series, using about 2.75 GiB of its 3 GiB limit. - etcd and Longhorn share a partition on every node (accepted risk, [docs/02](../docs/02-environments-and-provisioning.md)), and etcd's own metrics are not scraped, so the headroom for added etcd writes cannot be measured. - CI holds no cluster credential by decision, and has two runner slots that also serve the merge gate. - The implementation repository is readable without authentication. - Trivy's release pipeline was compromised in March 2026 (CVE-2026-33634). ## Decision **A small scheduled scanner runs in the cluster, built on the Trivy CLI, and a Renovate-shaped CI bot turns its results into action.** The full contract is [docs/17](../docs/17-vulnerability-visibility.md). - **Scanner.** Takes its inventory from the Kubernetes API, scans each unique digest with Trivy, and stores one versioned report on a small dedicated volume, outside etcd and Prometheus. - **Page.** Served from that report behind SSO and restricted to `platform-admins`. - **Metrics.** Aggregates only. - **Bot.** A scheduled Gitea Actions workflow using the existing CI-scoped Renovate credential. It maintains a counts-only dashboard issue and requests Renovate PRs through Renovate's own dashboard approval mechanism. - **Renovate stays the sole author of version changes.** No second bot edits a tag. - **Delivery tooling, not a catalog service.** Its cluster-wide read role is something a ServiceDefinition cannot express, so it is hand-authored under `platform/` with its own non-gating Flux tier, as in ADR-0025. ## Alternatives considered - **Trivy Operator.** The obvious choice, and rejected on measurement. It stores one report per workload as a CRD, adding write load to an etcd we cannot currently measure and which shares its disk with Longhorn; the largest images produce the largest reports, so size-limit failures would hide exactly the worst offenders. It needs broad cluster permissions and job-creation rights. It would also still need a bespoke aggregator, because the per-CVE page cannot be fed from Prometheus. - **Grafana table over per-CVE Prometheus metrics.** Needs no new page, but adds tens of thousands of long-labelled series to a Prometheus at about 92% of its memory limit. Raising the limit treats the symptom; a CVE inventory is not time-series data. - **Scanning from Gitea Actions.** Closest to Renovate literally, but CI has no view of what is running, and a long scan would occupy one of the two runner slots that gate merges. - **A third-party Trivy dashboard.** Assumes the operator's CRDs, and adds a further small-maintainer supply-chain dependency to a sensitive surface. - **An in-cluster bot with a Gitea token.** Puts a git-writing credential in the cluster, which ADR-0023 rejects. - **A CVE dashboard issue listing the findings.** The most Renovate-like, and rejected because the repository is publicly readable and the list would be an attack map. - **A bot that authors bump PRs itself.** A package's fixed version does not identify the image tag containing it, and two version authors would contend. Rejected in favour of driving Renovate. ## Consequences - Scanning and its output are hands-off, and "not scanned" is visible rather than silent. - The bot reuses the Renovate token, so both act as `renovate-bot`. This avoids a new credential; splitting them later changes one workflow secret. - The platform carries a small custom component that it must maintain and test. The report schema isolates the scanner, so Trivy can be replaced without touching the page or the bot. - Findings for private-registry images, VMs and nodes remain unassessed, and are shown as such ([known gaps](../docs/16-known-gaps.md)). - The critical-fix alert will fire on first deployment. That is the backlog becoming visible. - A tick can only open a Renovate PR. Remediation of majors and blast-radius components still waits for human review.