Files
home-network-k3s-impl/decisions/2026-10-30-renovate-run-hygiene.md
T
jakman85andClaude Opus 5.5 d9571fc6d8
gate / gate (pull_request) Successful in 2m55s
gate / conformance (pull_request) Has been skipped
fix(renovate): edit catalog sources, track CNPG imageName, honour update.range, guard real-run auto-merges
Audit of the first completed dry runs (353/354) plus a debug-level local reproduction:

- App-image updates edited only the generated apps/wave-*. A ServiceDefinition has no apiVersion,
  so the kubernetes manager extracts nothing from catalog/, and every such PR would fail
  render-golden (reproduced: GOLDEN DRIFT). New regex managers for catalog source.image and
  render.py OAUTH2_PROXY_IMAGE put the source and generated edits in one branch (render-golden
  rc 0, reproduced).
- CNPG Cluster imageName was untracked (3 Clusters), while the grant Job was tracked. New manager.
- allowedVersions mirror catalog update.range: this drops gitea 28.x, qbittorrent 20.x, radarr 6,
  nextcloud 35 and postgresql 18.
- Never auto-merge: gitea, act_runner, postgresql (blast radius), flux range widening, python
  minors. Majors wait for a Dependency Dashboard tick.
- velero plugin RC: semver versioning (v1.14.3-rc.2 -> v1.14.4 now proposed).
- flux docker duplicates disabled (the "Cannot find replaceString" line). Two false comments
  corrected.

Local dry run: regex deps 7 -> 20, branches 33 -> 29. The validator passes on 44.167.0.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 02:35:33 -05:00

9.1 KiB
Raw Blame History

date, branch, title
date branch title
2026-10-30 fix/renovate-run-hygiene Renovate's first completed dry runs, audited; it would have opened red PRs for every app and missed the databases. Config fixed

What changed

renovate.json5 only. Each change carries a comment quoting the measurement behind it.

  1. Three new regex managers, so updates edit the SOURCE.

    • catalog/*.yaml source.image.
    • catalog/render.py OAUTH2_PROXY_IMAGE.
    • CNPG imageName: under platform/ and apps/.

    The first two match the rendered line's depName, so the catalog edit and the generated apps/wave-* edit land in one branch.

  2. allowedVersions mirroring each ServiceDefinition's update.range:

    • gitea/gitea <2.0.0
    • nextcloud <32.0.0
    • qbittorrent <6.0.0
    • radarr <6.0.0
    • sonarr <5.0.0
    • semaphore <3.0.0

    Plus CNPG postgresql <17.0.0, because a Postgres major is a migration, not a bump.

  3. The blast-radius never-automerge list gains gitea/gitea, gitea/act_runner and ghcr.io/cloudnative-pg/postgresql.

  4. HelmRelease range widening (matchManagers: flux, ranged currentValue) is never auto-merged and is labelled range-widen.

  5. Majors need a Dependency Dashboard tick (dependencyDashboardApproval) before a PR opens.

  6. flux manager docker deps are disabled. These are duplicates of kubernetes manager extractions.

  7. velero/velero-plugin-for-aws uses semver versioning, so its RC pin can reach a stable release.

  8. python minors are not auto-merged.

  9. Two false comments are corrected.

    • Ranges "cap Renovate at patches": false, Renovate widens them.
    • nextcloud:31-apache and docker:27-dind "cannot be maintained": false, they were.

PR #85 is merged, so nothing here overlaps an open branch.

The audit: dispatch runs 353 (07:12 UTC) and 354 (07:23 UTC), on 593d0fa

Both runs ended success, Renovate "result": "done", exitCode 0. Both were at info level, so I reproduced the per-dependency detail with a debug-level local dry run of the same commit (see below).

The runs were inside the 03:00–06:00 America/New_York window, so branches were processed:

  • run 353: 37 "Would commit" branches;
  • run 354: 40, because the operator had added RENOVATE_GITHUB_COM_TOKEN 9 s before it.

Gitea's router log for the act-runner pod during both runs shows 317 2xx responses. The only non-2xx were all expected:

  • /v2/ 401: the registry challenge;
  • /admin/orgs 403: the #85 scope probe, by design;
  • 6× HEAD …/manifests/sha256:000… 404: the placeholder digests.
# Class Count Cause Severity Fix
1 App-image PRs edit only generated apps/wave-* 9 branches A ServiceDefinition has no apiVersion, so the kubernetes manager extracts 0 deps from catalog/. The oauth2-proxy sidecar is a Python constant (catalog/render.py:132) Real problem. Every such PR fails ci/render-golden.sh (reproduced: rc 1 "GOLDEN DRIFT"), stays red and holds a PR slot git (1)
2 CNPG imageName untracked 3 Clusters The kubernetes manager reads image: only. The one tracked postgres line was the grant Job (nextcloud-db.yaml:303, "keep in step with spec.imageName") Real problem. A real run bumps the Job and leaves the databases behind git (1)
3 Bogus or out-of-policy majors 5 branches: gitea 28.2.0, qbittorrent 20.04.1, radarr 6.x, nextcloud 35, postgresql 18.6 Odd legacy tags, plus update.range in catalog/ not being read by Renovate Risk if run for real: unmergeable PRs, which hold slots git (2)
4 Auto-merge of the merge gate's own host gitea 1.24.3→1.27.3, act_runner 0.2.11→0.6.1, both "minor" Not in the blast-radius list. A 0.x minor is breaking by semver Risk if run for real git (3)
5 Range widening auto-merged external-dns, headlamp (minor); longhorn (blast radius); kube-prometheus-stack (major) Renovate widens >=a <b. The config's comment claimed the opposite Risk if run for real: silently lets Flux adopt new minors git (4, 9)
6 Majors hold PR slots 10 majors in run 354 against prConcurrentLimit: 5 Majors never auto-merge, so they stay open Risk: starves auto-mergeable PRs git (5)
7 Cannot find replaceString … alpine:3.22 (INFO) 1 per run The same HelmRelease image: line is extracted by flux and kubernetes (also the velero plugin) Cosmetic. The branch is still right git (6)
8 velero-plugin-for-aws stuck on v1.14.3-rc.2 1 dep, 0 updates Docker versioning treats -rc.2 as a suffix, so stable v1.14.3 and v1.14.4 never qualify Real problem (silent) git (7)
9 python 3.13→3.15 as auto-mergeable "minor" 2 files Language runtime minor Risk if run for real git (8)
10 WARN GitHub token is required run 353: 5 packages, 17 deps No github.com token Real (they were unmaintained) operator, done: run 354 has no WARN and adds pin-dependencies, kubevirt-cdi, actions-checkout-7.x, major-github-artifact-actions
11 Floating or untagged images (invalid-value) 4: jackett, plex latest; pihole, keycloak no tag No version to compare Real, already documented none in git. Pinning by hand is an operator/PM decision
12 runs-on: ubuntu-latest invalid-version 11 The github-actions manager extracts runner labels Cosmetic, debug-only none
13 Docker Manifest is unknown (debug) 3 HEAD on the all-zero placeholder digests Expected. Clears when the own-image digest PRs merge none
14 Docker: error fetching data from DockerHub 403 (debug) 5 Hub refuses page=11. Renovate already has the tags Cosmetic. Updates were still found none
15 Config migration necessary 1 Top-level "docker": {"enabled": true} Cosmetic, pre-existing none (as before)

Checked and fine:

  • The 3 own-image digest updates were found in both runs. All 4 # renovate-digest: markers parse.
  • No marker failed to parse.
  • No package file is under conformance/runs or tests, nor is DECISIONS-LOG.md, decisions/ or any *.sops.yaml (77 package files checked).
  • kubevirt-cdi grouping works.
  • The schedule window behaved as designed.
  • Vulnerability alerts: none in either log.

What I verified

  • I read both job logs in full (132 and 129 lines), and the router log for 10.0.0.38 during both runs.
  • renovate-config-validator on 44.167.0: Config validated successfully. The migration diff is only the pre-existing docker block.
  • Local dry runs. Pinned image, --platform=local, debug, origin/main snapshot. "Before" is 593d0fa and "after" is this config; the GitHub-hosted deps were skipped in both.
    • Extraction: regex went from 6 files / 7 deps to 19 files / 20 deps. Every other manager is unchanged: flux 15, github-actions 24, kubernetes 131, kustomize 2.
    • Branches: 33 before, 29 after. Removed: gitea-28.x, qbittorrent-20.x, radarr-6.x, nextcloud-35.x and postgresql-18.x. Added: velero v1.14.3-rc.2 → v1.14.4 (patch).
    • Gitea, qbittorrent, radarr, sonarr, semaphore and seerr branches now each carry catalog/<svc>.yaml + apps/wave-*/<svc>.yaml.
    • The oauth2-proxy branch carries catalog/render.py plus the 5 rendered apps and platform/crafty.
    • The postgresql-16.x branch carries all three Clusters.
    • The 2 flux docker duplicates report disabled.
  • render==golden holds for the new branch shape.
    • In the toolbox, I applied the gitea branch edit (catalog + apps) and the oauth2-proxy branch edit (render.py constant + 5 apps) textually. ./ci/render-golden.sh reported all 10 onboarded service golden(s) reproduce, rc 0.
    • Negative control, the old shape with only apps/wave-0/gitea.yaml bumped: rc 1, GOLDEN DRIFT.
    • Both edits were reverted afterwards.

What I did NOT verify

  • The effect of the automerge, label and dashboard-approval rules (3, 4, 5, 8). UNVERIFIED in a run. --platform=local stops before branch processing, so I saw only which updates exist, not their merged flags. The matchers are standard (matchPackageNames, matchManagers, matchCurrentValue, matchUpdateTypes). The next dispatch's debug log shows them per branch.
  • allowedVersions under docker versioning used Renovate's "Falling back to npm semver syntax" path (16 debug lines). That it filters is shown by the five removed branches.
  • render==golden for the other app branches (qbittorrent, radarr, sonarr, semaphore, seerr). I proved it only for gitea and oauth2-proxy. They have the same shape: one source.image line ↔ one rendered image: line.
  • The allowedVersions rules duplicate catalog/*/update.range and can drift from it. Nothing checks them against each other. A lint comparing the two is the obvious follow-up.
  • Any real (non-dry) run. None has happened. PR creation, labels, auto-merge through Gitea's API and the Dependency Dashboard issue are all unobserved.
  • Sensitive path? renovate.json5 is not in infra/gitea/approval-policy.json, as far as I know. CI's approval-policy result on the PR is the measurement.