Files
home-network-k3s/decisions/adr-0023-automated-updates-renovate.md
jakman85andClaude Opus 5.5 250fb54154 docs: bring the specification in line with the accepted implementation
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]>
2026-11-08 22:46:00 -06:00

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:

  1. It bypasses the merge gate. Image automation commits and pushes rather than opening a pull request. Aimed at main it writes past the PR flow; aimed at a side branch, nothing closes the loop.
  2. It cannot write here. main is 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.
  3. 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.