The operator ruled the implementation repo's main (50c8719) the latest and accepted state. Sync the spec to it. Accepted changes are reflected: one bare-metal environment, TrueNAS bulk storage, R2 off-cluster backup, CloudNativePG, single-node VPN gateway with Cilium fail-closed, inbound WireGuard, per-app auth sidecars, Renovate, the CI gate as approver, and the pm-agent. New ADR-0017..0025; ADR-0016 corrected and accepted; R-* IDs unchanged, eight amended. Where the implementation has simply not met a requirement, the requirement stands and the shortfall is recorded in docs/16-known-gaps.md. Co-Authored-By: Claude Opus 5.5 <[email protected]>
4.1 KiB
ADR-0023 — Automated updates: Renovate for images and charts, every change PR-gated
- Status: Accepted
- Date: 2026-11-08
- Serves: R-UPD-01, R-UPD-02, R-UPD-03, R-TEST-03
- Supersedes: ADR-0009 (the VM guest mechanism stands and is restated below)
- Accepted by: operator ruling of 2026-11-08 that the implementation is the accepted state; effective on merge.
Context
ADR-0009 split updates by artifact: Flux image-update-automation for container image tags, Renovate for charts and manifests. The image half could not be delivered on this platform's terms:
- It bypasses the merge gate. Image automation commits and pushes rather than opening a pull
request. Aimed at
mainit writes past the PR flow; aimed at a side branch, nothing closes the loop. - It cannot write here.
mainis protected against direct pushes for every account, and Flux's source is anonymous and read-only. Enabling write-back means an in-cluster git write credential for the repository that defines the cluster, a far larger blast radius than a CI-scoped token. - Renovate already opens PRs, so every change it proposes goes through the gate with no extra machinery.
The controller was authored but never enabled, and no image-policy objects ever existed in the
cluster. Meanwhile plain image: tags were maintained by nothing at all, and pins drifted many minor
versions behind. This ADR closes a path that was never taken and changes no running state.
Decision
Renovate owns container images, Helm charts and manifest versions. It runs on a schedule as a Gitea Actions job and every change it proposes is a machine-authored pull request through the merge gate.
- Minor, patch and digest updates auto-merge on a green gate.
- Majors never auto-merge; they wait for human review of the machine-authored PR.
- Operator-designated blast-radius components never auto-merge, not even a patch, because a green static gate says nothing about whether a bump breaks them, or because they are the merge gate itself. The list and each reason are data in the Renovate configuration.
- The platform's own CI-built images are pinned by digest and follow a moving tag through a marker comment; Renovate proposes the digest bump.
- Per-service policy is declared in git. Renovate does not read the ServiceDefinition, so ceilings and cadences take effect through per-package rules in its configuration.
- VM guests → in-guest auto-update, declared in cloud-init, unchanged from ADR-0009.
Flux image-update-automation stays disabled. Flux itself stands (ADR-0004); its native image automation is no longer a load-bearing part of that choice, and native SOPS decryption and reconciliation remain so.
Alternatives considered
- Flux image automation writing to
main— bypasses the required gate; needs an in-cluster write credential. Rejected. - Flux image automation writing to a side branch — nothing opens or merges the PR; bumps accumulate unseen. Rejected.
- Auto-merge everything on green — the gate is static for these changes and cannot see whether a bump breaks the storage plane, the IdP or the gate itself. Rejected for the blast-radius set.
- Digest-tracking a mutable stable tag — loses version visibility and semver guardrails; ADR-0009 already held this as an escape hatch only. Not adopted.
Consequences
- Every update is auditable as a PR and is held to the same gate as a human change (R-TEST-03).
- R-UPD-02 is amended to match: allowed classes are hands-off; majors and blast-radius components MAY wait for human review of the machine-authored change. No human or AI authors a version bump.
- Update-failure signals and verification written around the Flux controller must move to Renovate's path (known gaps).
- Renovate is a CI job with a scoped token; its own version never auto-merges, because nothing re-validates its configuration against a new release before it takes effect.
- The update cadence is bounded by CI capacity, so PR concurrency and hourly rates are capped.