From 759a0e51c8b2ea78a47c53ec834172ccabf37dcd Mon Sep 17 00:00:00 2001 From: Keith Jackson Date: Sun, 8 Nov 2026 00:05:49 -0600 Subject: [PATCH] chore(renovate): hand-migrate docker key, track gitea/runner, keep range lower bounds - Replace the deprecated top-level `docker` key with the packageRule Renovate's own migration produced (matchCategories docker, enabled true), keeping every comment. Supersedes #139, which dropped all comment lines. - Add gitea/runner (act_runner's upstream rename) to the blast-radius rule. - rangeStrategy bump for flux/helm `>=A =1.12.0 <1.13.0` into `<1.14.0` (#131, #130, #115). In-range `bump` updates are disabled; Flux adopts those unaided. - Restore headlamp's lower bound: `<0.47.0` -> `>=0.46.0 <0.47.0` (live 0.46.0). Co-Authored-By: Claude Opus 5.5 --- .../2026-11-08-renovate-config-cleanup.md | 65 +++++++++++++++++ platform/headlamp/helmrelease.yaml | 6 +- renovate.json5 | 73 ++++++++++++++++--- 3 files changed, 133 insertions(+), 11 deletions(-) create mode 100644 decisions/2026-11-08-renovate-config-cleanup.md diff --git a/decisions/2026-11-08-renovate-config-cleanup.md b/decisions/2026-11-08-renovate-config-cleanup.md new file mode 100644 index 0000000..23b11ea --- /dev/null +++ b/decisions/2026-11-08-renovate-config-cleanup.md @@ -0,0 +1,65 @@ +--- +date: 2026-11-08 +branch: chore/renovate-config-cleanup +title: Renovate config — hand-migrate the docker key, track gitea/runner, keep HelmRelease range lower bounds +--- + +## What changed + +- **`renovate.json5`: the deprecated top-level `"docker": {"enabled": true}` is hand-migrated** to + `packageRules[0] = {"matchCategories": ["docker"], "enabled": true}`, the exact shape Renovate's + own migration produced on `origin/renovate/migrate-config` (PR #139). Its comment moved with it. + This replaces #139, which was closed because its rewrite deleted every comment in the file. No + other comment was removed or reflowed (diff is additions plus the moved block). +- **`gitea/runner` added to the blast-radius rule** beside `gitea/act_runner`, with a comment: + act_runner was renamed upstream to gitea/runner after 0.6.1; Renovate does not follow renames, + so the actual image migration is a separate manual PR. +- **Two new packageRules for flux/helm `>=A enabled: false`, so in-range releases (which Flux adopts on its + own) do not become PRs. Cause of the bug, from the 44.167.0 source: rangeStrategy is unset + (`auto`); the flux manager has no `getRangeStrategy`/`updateLockedDependency`, so + `lib/modules/manager/index.ts getRangeStrategy` resolves `auto` to `replace`; helm versioning is + the npm api verbatim, and npm `getNewValue` under `replace` turns `>=1.12.0 <1.13.0` into + `<1.14.0` (what PRs #131, #130 and #115 did). +- **`platform/headlamp/helmrelease.yaml`: `version: "<0.47.0"` -> `">=0.46.0 <0.47.0"`**, comment + refreshed. The live chart is 0.46.0, so the set of installable charts is unchanged. + +## What I verified + +- **Semantic diff of #139:** I parsed `renovate.json5` on `origin/renovate/migrate-config` and on its + parent `5b484f6` with json5 (the copy inside the renovate image). With `docker` removed from the + parent and `packageRules[0]` removed from the migrated file, the two are identical. So the only + change was `{"matchCategories":["docker"],"enabled":true}`, inserted at packageRules[0]. +- **Validator, `ghcr.io/renovatebot/renovate:44.167.0`** (the tag that `.gitea/workflows/renovate.yaml` + pins as `container.image`): `renovate-config-validator` gives `Config validated successfully` + (rc 0), and so does `--strict` (rc 0), both as a file path and in repo mode. **`--strict` on + origin/main's file gives rc 1** and prints the `docker` migration diff. Nothing is left to migrate. +- **`getNewValue` called in the 44.167.0 image** (helm versioning), currentValue + `>=1.12.0 <1.13.0`, newVersion 1.13.0: replace `<1.14.0`, widen `>=1.12.0 <1.14.0`, + bump `>=1.13.0 <1.14.0`, pin/update-lockfile `<1.14.0`. On `<0.47.0`, bump returns the value + unchanged, so it would never propose anything for that range. That is why the rule is scoped to + the `>=A =1.9.0 <1.10.0` -> + `>=1.13.0 <1.14.0` (minor). kube-prometheus-stack `>=88.0.0 <89.0.0` -> `>=93.1.0 <94.0.0` + (major). The in-range bump `>=88.6.5 <89.0.0` was dropped (`Filtered out 1 disabled update(s)`). + headlamp `>=0.46.0 <0.47.0` and `<0.47.0`: no update. + - Control run with origin/main's config: `Config migration necessary`, longhorn -> `<1.14.0`, + kube-prometheus-stack -> `<94.0.0`. This reproduces the reported bug. +- Live headlamp HelmRelease (read-only kubectl, k3s-prod): spec `<0.47.0`, history chartVersion + `0.46.0`, Ready `True`. + +## What I did NOT verify + +- **I have not seen a real scheduled Renovate run against this repo with this config.** The claim that + Renovate stops reopening the migrate-config PR rests on the validator and on `No config migration + necessary` in the local dry run, not on the Gitea bot. After merge, watch the next run, and if + `renovate/migrate-config` is still on the remote, delete it. +- **Under bump, the new lower bound is the release Renovate proposes**, e.g. `>=1.13.2 <1.14.0`, not + `>=1.13.0`. Flux still installs the newest release in the window. Ranges with other shapes keep the + default `replace`: `3.9.x`, `~`, ceiling-only, and exact pins. +- **The open PRs #131, #115 and any others still carry unbounded `=0.41.0 <0.42.0` to the unbounded-below `<0.47.0`; the lower bound is restored here at the + # chart that was live when it merged (0.46.0). renovate.json5 now bumps `>=A =0.47.x <0.48.0` rather than `<0.48.0`. + version: ">=0.46.0 <0.47.0" sourceRef: kind: HelmRepository name: headlamp diff --git a/renovate.json5 b/renovate.json5 index 21214e4..6810b6b 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -37,6 +37,8 @@ // renovate-config-validator /tmp/renovate.json5 // (Not `--strict`: that also fails on a pending migration of the pre-existing top-level // `"docker": {"enabled": true}` block at the bottom, which is a warning, not an error.) +// RESOLVED 2026-11-08: that block is now hand-migrated to the first packageRule (`matchCategories: +// ["docker"]`), the exact shape Renovate's own migration produced, so no migration is pending. // // `regex` vs `custom.regex` in enabledManagers, RESOLVED FROM SOURCE (Renovate 39.264.0 and // later): both work. lib/config/migrations/custom/enabled-managers-migration.ts rewrites @@ -196,6 +198,22 @@ } ], "packageRules": [ + // The `docker` manager (Dockerfiles, docker-compose) and the `kubernetes` manager above were + // BOTH previously `enabled: false`, solely so Renovate would not fight Flux image-automation + // over a running tag. That controller was never enabled and never will be here (see _comment), + // so the only thing those two flags were achieving was leaving every plain `image:` tag in the + // repo unmanaged. `docker` is left out of enabledManagers because this repo contains no + // Dockerfile that ships to the cluster; `kubernetes` is now ON and is the one that matters. + // MOVED HERE 2026-11-08 from a top-level `"docker": {"enabled": true}` key, which Renovate + // deprecated (the top-level language objects became `matchCategories` rules). Hand-migrated to + // the exact output of Renovate's own config migration (branch renovate/migrate-config, PR #139: + // a json5 semantic diff of that file against its parent shows THIS rule, inserted at + // packageRules[0], as the ONLY change). #139 itself was closed unmerged because its rewrite + // dropped every comment in this file. With nothing left to migrate, Renovate stops reopening it. + { + "matchCategories": ["docker"], + "enabled": true + }, { "description": "Auto-merge the allowed low-risk classes on green CI \u2014 no human authoring (R-UPD-02). The Gitea merge gate (make -C ci gate) is the required check.", "matchUpdateTypes": [ @@ -252,6 +270,11 @@ // Keycloak's (the IdP) included, now that imageName is tracked. "gitea/gitea", "gitea/act_runner", + // ADDED 2026-11-08. act_runner was RENAMED upstream to gitea/runner after 0.6.1 + // (https://gitea.com/gitea/runner/releases). Renovate does not follow a rename — it will + // never propose gitea/act_runner -> gitea/runner — so that migration is a manual PR. Listed + // now so the new name is blast-radius from its first reference, not after an auto-merge. + "gitea/runner", "ghcr.io/cloudnative-pg/postgresql" ], "automerge": false, @@ -368,6 +391,45 @@ "automerge": false, "addLabels": ["needs-review", "range-widen"] }, + // ADDED 2026-11-08 — KEEP THE LOWER BOUND WHEN A MINOR-LOCKED RANGE MOVES. MEASURED PROBLEM: + // PRs #131 (longhorn), #130 (headlamp) and #115 (kube-prometheus-stack) turned + // `">=1.12.0 <1.13.0"` into `"<1.14.0"` — an UNBOUNDED-below range that also admits every + // older chart (and #130 merged: platform/headlamp/helmrelease.yaml carried `<0.47.0`). WHY, + // from the 44.167.0 source this file is validated against: no rangeStrategy is set, so it is + // `auto`; the flux manager has no getRangeStrategy and no updateLockedDependency, so + // lib/modules/manager/index.ts getRangeStrategy resolves `auto` -> `replace`. The helm + // datasource's defaultVersioning is `helm`, which is the npm versioning api verbatim + // (lib/modules/versioning/helm/index.ts: `api = { ...npm }`), and npm getNewValue under + // `replace` rewrites `>=A =1.12.0 <1.13.0`, newVersion 1.13.0: + // replace -> `<1.14.0` widen -> `>=1.12.0 <1.14.0` bump -> `>=1.13.0 <1.14.0` + // Only `bump` keeps a one-minor window. (widen keeps the bound but grows the window by a minor + // on every PR — the opposite of minor-locking.) Under bump the new lower bound is the release + // proposed (e.g. 1.13.2 -> `>=1.13.2 <1.14.0`); Flux still picks the newest that satisfies it. + // Scoped to the bounded `>=A =A =1.13.0 <1.14.0`, not `<1.14.0`. See the comment above for the measured cause.", + "matchManagers": ["flux"], + "matchDatasources": ["helm"], + "matchCurrentValue": "/^>=\\S+ <\\S+$/", + "rangeStrategy": "bump" + }, + // ...AND DO NOT LET bump ADD NOISE. Under bump Renovate also raises the lower bound for a + // release ALREADY INSIDE the range (lib/workers/repository/process/lookup/generate.ts sets + // isBump; e.g. 1.12.5 against `>=1.12.0 <1.13.0` -> `>=1.12.5 <1.13.0`), which `replace` never + // proposed. Flux already installs that release with no PR, and the range-widen rule above + // would hold every one for review. util/package-rules/update-types.ts matches isBump as + // updateType `bump`, so exactly those updates are switched off here; out-of-range moves are + // ordinary minor/major updates and are unaffected. + { + "description": "ADDED 2026-11-08. No PR for a chart release the HelmRelease range already admits — Flux adopts it on its own.", + "matchManagers": ["flux"], + "matchDatasources": ["helm"], + "matchCurrentValue": "/^>=\\S+ <\\S+$/", + "matchUpdateTypes": ["bump"], + "enabled": false + }, { "description": "ADDED 2026-10-30. velero-plugin-for-aws is pinned to a RELEASE CANDIDATE (v1.14.3-rc.2) and Renovate proposed NOTHING for it, although v1.14.3 and v1.14.4 are stable on Docker Hub. Docker versioning treats everything after the first `-` as a compatibility SUFFIX, so only other `*-rc.2` tags qualify and the RC is a fossil forever. Semver versioning reads it as a prerelease, and a prerelease upgrades to the stable release.", "matchPackageNames": ["velero/velero-plugin-for-aws"], @@ -439,14 +501,5 @@ "conformance/tests/**", "platform/image-automation/per-service/**", "platform/kyverno/tests/**" - ], - // The `docker` manager (Dockerfiles, docker-compose) and the `kubernetes` manager above were - // BOTH previously `enabled: false`, solely so Renovate would not fight Flux image-automation - // over a running tag. That controller was never enabled and never will be here (see _comment), - // so the only thing those two flags were achieving was leaving every plain `image:` tag in the - // repo unmanaged. `docker` is left out of enabledManagers because this repo contains no - // Dockerfile that ships to the cluster; `kubernetes` is now ON and is the one that matters. - "docker": { - "enabled": true - } + ] } -- 2.54.0