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]>
373 lines
23 KiB
JSON
373 lines
23 KiB
JSON
// =================================================================================================
|
|
// Renovate configuration — JSON5, so the rationale can live NEXT TO what it explains.
|
|
// =================================================================================================
|
|
// THIS FILE WAS `renovate.json` AND IT WAS INVALID. It carried five `_comment` / `_*_comment`
|
|
// pseudo-comment keys, because JSON has no comments. Renovate REJECTS unknown top-level options, so
|
|
// the whole config failed validation and the first manual run of the workflow ERRORED OUT. Proven
|
|
// with the official validator (`ghcr.io/renovatebot/renovate renovate-config-validator`):
|
|
//
|
|
// ERROR: Found errors in configuration
|
|
// Invalid configuration option: _comment
|
|
// Invalid configuration option: _docker_comment
|
|
// Invalid configuration option: _ignorePaths_comment
|
|
// Invalid configuration option: _kubernetes_comment
|
|
// Invalid configuration option: _unmanageable_comment
|
|
//
|
|
// Renovate discovers `renovate.json5` natively (no RENOVATE_CONFIG_FILE needed, and nothing in
|
|
// .gitea/ or ci/ pins the old filename — only prose in comments), and JSON5 permits real `//`
|
|
// comments. So the fix keeps every word of the original rationale, positioned, instead of
|
|
// flattening it into a `description` string.
|
|
//
|
|
// VALIDATE BEFORE COMMITTING — it is one command and it is the only thing that catches this class:
|
|
// podman run --rm -v "$PWD/renovate.json5:/tmp/renovate.json5:ro,Z" \
|
|
// ghcr.io/renovatebot/renovate renovate-config-validator /tmp/renovate.json5
|
|
//
|
|
// CORRECTION (2026-10-29): THE VALIDATOR ABOVE WAS NOT THE RENOVATE THE WORKFLOW RUNS. The bare
|
|
// `ghcr.io/renovatebot/renovate` tag is `latest` (44.167.0 when this was measured), while
|
|
// renovatebot/[email protected] defaults `renovate-version` to `39` (its action.yml), i.e.
|
|
// 39.264.0. Validated against THAT, this file failed with five errors — every
|
|
// `managerFilePatterns` key ("Custom Manager contains disallowed fields", "Invalid configuration
|
|
// option: flux.managerFilePatterns", ...), because 39.x only knows `fileMatch`; the rename landed
|
|
// in 40.2.0. So even after the workflow found this file, every run would have stopped at
|
|
// CONFIG_VALIDATION. renovate.yaml now pins the exact release this file is validated against —
|
|
// since 2026-10-30 as the job's `container.image` tag (the action is gone: it needed a Docker
|
|
// daemon jobs here do not get). VALIDATE WITH THAT SAME TAG:
|
|
// podman run --rm -v "$PWD/renovate.json5:/tmp/renovate.json5:ro,Z" \
|
|
// ghcr.io/renovatebot/renovate:<container.image tag in renovate.yaml> \
|
|
// 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.)
|
|
//
|
|
// `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
|
|
// `regex` -> `custom.regex`, and that migration runs on every real repository run
|
|
// (lib/workers/repository/init/merge.ts -> migrateAndValidate), not only in the validator;
|
|
// lib/modules/manager/index.ts getEnabledManagersList accepts either spelling. `custom.regex` is
|
|
// the canonical name (introduced in 37.51.1, renovatebot/renovate#24079), so it is used below and
|
|
// nothing depends on the migration any more.
|
|
{ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
// Renovate config — Phase 4 automated updates (ADR-0009, R-UPD-01/02). AS OF 2026-10-17
|
|
// RENOVATE OWNS BOTH HALVES: Helm chart/dependency bumps AND per-service container image tags.
|
|
// It opens PRs for everything; allowed low-risk classes auto-merge on green CI. The ADR-0009
|
|
// split that gave image tags to Flux image-automation is formally closed — see
|
|
// .gitea/workflows/renovate.yaml for the three measured reasons (it pushes commits rather than
|
|
// opening PRs, so it bypasses the CLAUDE.md §1 gate; `main` is protected with
|
|
// user_can_push:false and the flux-system GitRepository has no secretRef, so it cannot write
|
|
// anyway; and enabling it would need an in-cluster git WRITE credential for the repo that
|
|
// defines the cluster). image-automation has been commented out at
|
|
// platform/kustomization.yaml:52 since it was authored and the cluster holds zero
|
|
// ImagePolicy/ImageRepository/ImageUpdateAutomation objects, so nothing is being torn down.
|
|
// CONSEQUENCE: the `docker` and `kubernetes` managers, previously disabled ONLY to avoid
|
|
// fighting that controller, are now ENABLED — without them every plain `image: repo/name:tag`
|
|
// line in this repo was maintained by nothing at all, which is how the oauth2-proxy auth
|
|
// sidecars reached 7 minors behind the oauth2-proxy running in the same cluster. RUNNER:
|
|
// .gitea/workflows/renovate.yaml (scheduled daily); platform/endpoint are set there, not here.
|
|
"extends": ["config:recommended", ":dependencyDashboard", ":semanticCommits", "helpers:pinGitHubActionDigests"],
|
|
"timezone": "America/New_York",
|
|
"schedule": ["after 3am and before 6am"],
|
|
"prConcurrentLimit": 5,
|
|
"prHourlyLimit": 2,
|
|
"commitMessagePrefix": "chore(deps):",
|
|
"labels": ["dependencies", "automated-update"],
|
|
"ignoreUnstable": true,
|
|
"respectLatest": true,
|
|
"enabledManagers": ["flux", "kustomize", "helmv3", "kubernetes", "custom.regex", "github-actions"],
|
|
"flux": {
|
|
"managerFilePatterns": [
|
|
"/(^|/)platform/.+\\.ya?ml$/",
|
|
"/(^|/)apps/.+\\.ya?ml$/"
|
|
]
|
|
},
|
|
"kustomize": {
|
|
"managerFilePatterns": [
|
|
"/(^|/)kustomization\\.ya?ml$/"
|
|
]
|
|
},
|
|
// ADDED 2026-10-17. The `kubernetes` manager reads plain `image:` fields out of Kubernetes
|
|
// manifests, and it is NOT auto-detected — it only looks at files matched here, which is why
|
|
// this block is as broad as it is. Scope covers every place this repo writes a container image:
|
|
// platform components, the rendered app waves, the ServiceDefinition catalog that generates
|
|
// them, the runbooks web server and the pm-agent job template. `catalog/` matters as much as
|
|
// `apps/`: apps/wave-*/*.yaml are GENERATED by catalog/render.py, so a bump applied only to the
|
|
// rendered output is reverted by the next render and would also fail ci/render-golden.sh.
|
|
// Renovate will raise BOTH, and both must land together.
|
|
"kubernetes": {
|
|
"managerFilePatterns": [
|
|
"/(^|/)platform/.+\\.ya?ml$/",
|
|
"/(^|/)platform-config/.+\\.ya?ml$/",
|
|
"/(^|/)apps/.+\\.ya?ml$/",
|
|
"/(^|/)catalog/.+\\.ya?ml$/",
|
|
"/(^|/)runbooks/serving/.+\\.ya?ml$/",
|
|
"/(^|/)infra/agent/.+\\.ya?ml$/"
|
|
]
|
|
},
|
|
"customManagers": [
|
|
{
|
|
"customType": "regex",
|
|
"description": "Inline `# renovate: datasource=... depName=...` markers on pinned URLs / version literals (e.g. platform/kubevirt/kustomization.yaml release URLs, ci/versions.env, infra/devcontainer/versions.env).",
|
|
"managerFilePatterns": [
|
|
"/(^|/)kustomization\\.ya?ml$/",
|
|
"/(^|/)versions\\.env$/"
|
|
],
|
|
"matchStrings": [
|
|
"#\\s*renovate:\\s*datasource=(?<datasource>\\S+)\\s+depName=(?<depName>\\S+)(?:\\s+versioning=(?<versioning>\\S+))?\\s*\\n.*?(?<currentValue>v?[0-9]+\\.[0-9]+\\.[0-9]+)"
|
|
],
|
|
"versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}"
|
|
},
|
|
// ADDED 2026-10-29 — THIS REPO'S OWN IMAGES (toolbox, agent-runner, conformance-runner).
|
|
// CI publishes them (.gitea/workflows/images.yaml) under an immutable `sha-<commit>` tag and a
|
|
// moving `main` tag, and never writes to git. Every reference to them is DIGEST-ONLY
|
|
// (`<repo>@sha256:<hex>`, no tag), because the admission policies
|
|
// (platform/kyverno/admission/pm-agent-job-shape.yaml, conformance-trigger-job-shape.yaml)
|
|
// admit exactly that form. A digest alone gives Renovate nothing to follow, so the tag to
|
|
// follow rides in a marker comment on the line ABOVE the reference:
|
|
//
|
|
// # renovate-digest: image=<registry>/<namespace>/<image> tag=main
|
|
// <anything>sha256:<64 hex>
|
|
//
|
|
// `main` is not a version, so Renovate skips the release lookup and proposes a `digest`
|
|
// update whenever the tag's digest moves (lib/workers/repository/process/lookup/index.ts:
|
|
// an unversioned currentValue WITH a currentDigest yields updateType `digest`). The
|
|
// `sha256:` prefix is INSIDE currentDigest on purpose: Renovate replaces that capture
|
|
// verbatim with the new digest, which carries the prefix.
|
|
//
|
|
// DELIBERATELY NOT TRACKED: infra/agent/worker-job-template.yaml. It is baked INTO
|
|
// agent-runner, so bumping it would rebuild agent-runner and loop forever; pm-dispatch
|
|
// overwrites that field from PM_WORKER_IMAGE at runtime anyway.
|
|
// REGISTRY AUTH: the Gitea registry answers 401 to anonymous reads, and the platform token is
|
|
// scoped to hostType `gitea`, which a docker lookup never matches
|
|
// (lib/util/host-rules.ts find). renovate.yaml supplies a hostType `docker` rule.
|
|
{
|
|
"customType": "regex",
|
|
"description": "This repo's own CI-published images, pinned by digest, following the tag named in a `# renovate-digest:` marker on the previous line.",
|
|
"managerFilePatterns": [
|
|
"/(^|/)versions\\.env$/",
|
|
"/(^|/)platform/pm-agent/.+\\.ya?ml$/"
|
|
],
|
|
"matchStrings": [
|
|
"#\\s*renovate-digest:\\s*image=(?<depName>\\S+)\\s+tag=(?<currentValue>\\S+)\\s*\\n[^\\n]*?(?<currentDigest>sha256:[a-f0-9]{64})"
|
|
],
|
|
"datasourceTemplate": "docker",
|
|
"versioningTemplate": "docker"
|
|
},
|
|
// ADDED 2026-10-30 — THE CATALOG IS THE SOURCE; apps/wave-*/*.yaml IS GENERATED FROM IT.
|
|
// First real dry run (dispatch runs 353/354): EVERY app-image update edited only the rendered
|
|
// apps/wave-*/*.yaml and NONE edited catalog/. The `kubernetes` manager lists catalog/ above
|
|
// but extracts nothing there: a ServiceDefinition has no `apiVersion`, so it is not a
|
|
// Kubernetes manifest to that manager (measured: 0 deps from catalog/). Every such PR would
|
|
// fail ci/render-golden.sh (the canonical render reverts the bump), sit red and hold a
|
|
// prConcurrentLimit slot. These two managers read the SOURCES, under the SAME depName as the
|
|
// rendered line, so both land in ONE branch and render==golden holds: `source.image` in each
|
|
// ServiceDefinition, and render.py's OAUTH2_PROXY_IMAGE (the six auth sidecars).
|
|
{
|
|
"customType": "regex",
|
|
"description": "ServiceDefinition `source.image: <repo>:<tag>` (catalog/*.yaml) — the source of the rendered apps/wave-* image.",
|
|
"managerFilePatterns": ["/(^|/)catalog/[^/]+\\.ya?ml$/"],
|
|
"matchStrings": [
|
|
"\\n\\s+image:\\s*(?<depName>[^\\s:@#\"']+):(?<currentValue>[^\\s@#\"']+)"
|
|
],
|
|
"datasourceTemplate": "docker"
|
|
},
|
|
{
|
|
"customType": "regex",
|
|
"description": "catalog/render.py OAUTH2_PROXY_IMAGE — the per-app oauth2-proxy sidecar every forward-auth app is rendered with.",
|
|
"managerFilePatterns": ["/(^|/)catalog/render\\.py$/"],
|
|
"matchStrings": [
|
|
"\\nOAUTH2_PROXY_IMAGE\\s*=\\s*\"(?<depName>[^\":@]+):(?<currentValue>[^\"@]+)\""
|
|
],
|
|
"datasourceTemplate": "docker"
|
|
},
|
|
// ADDED 2026-10-30 — CNPG `Cluster.spec.imageName`. The `kubernetes` manager reads `image:` only,
|
|
// so the three database Clusters (platform/keycloak/postgres-cluster.yaml, apps/wave-0/
|
|
// nextcloud-db.yaml, apps/wave-0/semaphore-db.yaml) were untracked, while the grant Job in
|
|
// nextcloud-db.yaml — whose comment says "keep the tag in step with spec.imageName" — WAS. A real
|
|
// run would have bumped the Job and left the database behind. Same depName, so one branch.
|
|
{
|
|
"customType": "regex",
|
|
"description": "CloudNativePG Cluster `imageName: <repo>:<tag>`.",
|
|
"managerFilePatterns": [
|
|
"/(^|/)platform/.+\\.ya?ml$/",
|
|
"/(^|/)apps/.+\\.ya?ml$/"
|
|
],
|
|
"matchStrings": [
|
|
"\\n\\s+imageName:\\s*(?<depName>[^\\s:@#\"']+):(?<currentValue>[^\\s@#\"']+)"
|
|
],
|
|
"datasourceTemplate": "docker"
|
|
}
|
|
],
|
|
"packageRules": [
|
|
{
|
|
"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": [
|
|
"minor",
|
|
"patch",
|
|
"digest"
|
|
],
|
|
"automerge": true,
|
|
"automergeType": "pr",
|
|
"platformAutomerge": true
|
|
},
|
|
{
|
|
"description": "MAJOR / potentially-breaking bumps require human review (docs/11 safety rail). Never auto-merged.",
|
|
"matchUpdateTypes": [
|
|
"major"
|
|
],
|
|
"automerge": false,
|
|
"addLabels": [
|
|
"needs-review",
|
|
"breaking"
|
|
]
|
|
},
|
|
{
|
|
"description": "Keep the KubeVirt + CDI operator pair on a compatible track \u2014 grouped so they bump together (platform/kubevirt/kustomization.yaml).",
|
|
"matchDepNames": [
|
|
"kubevirt/kubevirt",
|
|
"kubevirt/containerized-data-importer"
|
|
],
|
|
"groupName": "kubevirt-cdi"
|
|
},
|
|
{
|
|
"description": "Pinned tool versions (ci/versions.env, infra/devcontainer/versions.env) are a deliberate change surface \u2014 label but do not auto-merge; a version bump there changes CI reproducibility.",
|
|
"matchFileNames": [
|
|
"ci/versions.env",
|
|
"infra/devcontainer/versions.env"
|
|
],
|
|
"automerge": false,
|
|
"addLabels": [
|
|
"ci-tooling"
|
|
]
|
|
},
|
|
{
|
|
"description": "ADDED 2026-10-17. NEVER AUTO-MERGE THE BLAST-RADIUS COMPONENTS, not even a patch. The default rule above auto-merges minor/patch/digest on a green gate, which is right for an app image: a bad Sonarr bump inconveniences one pod. It is wrong for these five, because the gate is a STATIC check \u2014 it renders manifests and lints them, it does not boot a node, drain a volume or form an etcd quorum (vars.CLUSTER_AVAILABLE is unset, so L2/L3 conformance does not run in CI at all). So for anything whose failure mode is the CLUSTER rather than a service, a green gate is not evidence and a human must read the changelog. kured is here because it reboots control-plane nodes; longhorn because a storage-engine bump migrates live volume data; cilium because it is the CNI and a bad bump is a total partition (and its version is DUAL-PINNED in infra/ansible/roles/cilium/defaults/main.yml, which Renovate does not see, so the two would silently desync); cloudnative-pg because it drives Postgres switchovers; kube-prometheus-stack because ci/versions.env asserts an exact promtool/Prometheus lockstep and a chart bump that moves Prometheus fails the gate until that file moves with it.",
|
|
"matchPackageNames": [
|
|
"kured",
|
|
"longhorn",
|
|
"cilium",
|
|
"cloudnative-pg",
|
|
"kube-prometheus-stack",
|
|
// ADDED 2026-10-30. gitea and act_runner ARE the merge gate: a bad auto-merged bump takes
|
|
// down the very check that would have to approve its revert (the dry run proposed gitea
|
|
// 1.24.3 -> 1.27.3 and act_runner 0.2.11 -> 0.6.1, both as auto-mergeable "minor"; a 0.x
|
|
// minor is a breaking line by semver). The postgresql image restarts every CNPG database,
|
|
// Keycloak's (the IdP) included, now that imageName is tracked.
|
|
"gitea/gitea",
|
|
"gitea/act_runner",
|
|
"ghcr.io/cloudnative-pg/postgresql"
|
|
],
|
|
"automerge": false,
|
|
"addLabels": [
|
|
"needs-review",
|
|
"blast-radius"
|
|
]
|
|
},
|
|
{
|
|
"description": "ADDED 2026-10-29. This repo's own images are followed ONLY through the `# renovate-digest:` markers above. The `kubernetes` manager also sees platform/pm-agent/deployment.yaml and infra/agent/worker-job-template.yaml, where the image has a digest and no tag; left on, it would look those up as `latest` (a tag CI never pushes) and, for the template, re-open the self-referential loop the custom manager deliberately avoids.",
|
|
"matchManagers": ["kubernetes"],
|
|
"matchPackageNames": [
|
|
"gitea.home.keithjackson.dev/home-network/toolbox",
|
|
"gitea.home.keithjackson.dev/home-network/agent-runner",
|
|
"gitea.home.keithjackson.dev/home-network/conformance-runner"
|
|
],
|
|
"enabled": false
|
|
},
|
|
{
|
|
"description": "ADDED 2026-10-29. Digest bumps for this repo's own images: the image was built and verified by CI before it was published, so these auto-merge on a green gate like any digest (rule 1). Labelled so they are easy to find. NOTE: the conformance-runner bump edits conformance/versions.env, a sensitive path (infra/gitea/approval-policy.json), so it will wait for an administrator's /approve-override regardless of this rule.",
|
|
"matchManagers": ["custom.regex"],
|
|
"matchPackageNames": [
|
|
"gitea.home.keithjackson.dev/home-network/toolbox",
|
|
"gitea.home.keithjackson.dev/home-network/agent-runner",
|
|
"gitea.home.keithjackson.dev/home-network/conformance-runner"
|
|
],
|
|
"addLabels": ["own-image"]
|
|
},
|
|
{
|
|
"description": "ADDED 2026-10-30. The `flux` manager also extracts `image:` lines inside HelmRelease values, which the `kubernetes` manager already owns. Measured: exactly two (alpine in platform/oauth2-proxy/helmrelease.yaml, velero-plugin-for-aws in platform/velero/helmrelease.yaml), each extracted twice; the second rewrite of the same line logged `Cannot find replaceString in current file content` in runs 353/354. Flux keeps its charts (datasource helm).",
|
|
"matchManagers": ["flux"],
|
|
"matchDatasources": ["docker"],
|
|
"enabled": false
|
|
},
|
|
{
|
|
"description": "ADDED 2026-10-30. MIRRORS catalog/<svc>.yaml `update.range` — the operator's declared per-service policy (schemas/servicedefinition.schema.json), which Renovate does not read. Without it the dry run proposed gitea 28.2.0, qbittorrent 20.04.1 (both stale/odd tags, not real successors), radarr 6.x and nextcloud 35 (four majors past 31; Nextcloud cannot skip majors). KEEP IN STEP with the catalog ranges.",
|
|
"matchPackageNames": ["gitea/gitea"],
|
|
"allowedVersions": "<2.0.0"
|
|
},
|
|
{ "matchPackageNames": ["nextcloud"], "allowedVersions": "<32.0.0" },
|
|
{ "matchPackageNames": ["lscr.io/linuxserver/qbittorrent"], "allowedVersions": "<6.0.0" },
|
|
{ "matchPackageNames": ["lscr.io/linuxserver/radarr"], "allowedVersions": "<6.0.0" },
|
|
{ "matchPackageNames": ["lscr.io/linuxserver/sonarr"], "allowedVersions": "<5.0.0" },
|
|
{ "matchPackageNames": ["semaphoreui/semaphore"], "allowedVersions": "<3.0.0" },
|
|
{
|
|
"description": "ADDED 2026-10-30. A CNPG Postgres MAJOR is a migration (new cluster + import), not an image bump; the dry run proposed 16.4 -> 18.6. Minors stay (and are blast-radius, above).",
|
|
"matchPackageNames": ["ghcr.io/cloudnative-pg/postgresql"],
|
|
"allowedVersions": "<17.0.0"
|
|
},
|
|
{
|
|
"description": "ADDED 2026-10-30. A HelmRelease semver RANGE is a policy ceiling, and Renovate does not respect it — it WIDENS it (dry run: external-dns `<1.22.0` -> `<1.24.0`, headlamp `<0.42.0` -> `<0.47.0`), and the default rule would then auto-merge that as a 'minor', silently letting Flux adopt every new minor. Raising a ceiling is deliberate per-component work: propose it, never auto-merge it.",
|
|
"matchManagers": ["flux"],
|
|
"matchCurrentValue": "/^[<>=~^]|\\.x$/",
|
|
"automerge": false,
|
|
"addLabels": ["needs-review", "range-widen"]
|
|
},
|
|
{
|
|
"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"],
|
|
"versioning": "semver"
|
|
},
|
|
{
|
|
"description": "ADDED 2026-10-30. A python MINOR is a language-runtime release (the dry run proposed 3.13 -> 3.15 for the Keycloak reconcilers), and the gate does not execute those scripts. Review it; patches still auto-merge.",
|
|
"matchPackageNames": ["python"],
|
|
"matchUpdateTypes": ["minor"],
|
|
"automerge": false,
|
|
"addLabels": ["needs-review"]
|
|
},
|
|
{
|
|
"description": "ADDED 2026-10-30. MAJORS WAIT FOR A TICK ON THE DEPENDENCY DASHBOARD instead of opening a PR. They are never auto-merged anyway, and with prConcurrentLimit 5 the dry run's 10 majors would hold every PR slot open indefinitely, starving the patch/minor/digest PRs that can merge on green.",
|
|
"matchUpdateTypes": ["major"],
|
|
"dependencyDashboardApproval": true
|
|
}
|
|
],
|
|
// WHAT RENOVATE STILL CANNOT FIX, so nobody mistakes a working bot for full coverage. A
|
|
// FLOATING tag has no version to compare, so Renovate skips it silently — it does not pin it
|
|
// and does not warn. As of 2026-10-17 that is: plexinc/pms-docker:latest,
|
|
// lscr.io/linuxserver/jackett:latest, pihole/pihole (NO TAG AT ALL), quay.io/keycloak/keycloak
|
|
// (no tag), nextcloud:31-apache and docker:27-dind. Those must be pinned BY HAND to a concrete
|
|
// version before any automation can maintain them, and until then they drift on every pull with
|
|
// nothing recording what is running. CORRECTED 2026-10-30: nextcloud:31-apache and docker:27-dind
|
|
// ARE maintained (the first dry run proposed 35-apache and 29-dind; the suffix is kept).
|
|
// Separately, the HelmRelease minor-locking ranges (9 of 12, e.g. `>=88.0.0 <89.0.0` on
|
|
// kube-prometheus-stack): THIS FILE USED TO SAY they cap Renovate at patches. They do not —
|
|
// Renovate WIDENS the range (runs 353/354). The `range-widen` rule above keeps that a reviewed
|
|
// PR rather than an auto-merge. Both lists are in decisions/2026-10-17-automated-upgrades.md.
|
|
// platform/kyverno/tests/** ADDED 2026-10-17: those Kyverno policy fixtures pin `alpine:latest`
|
|
// and a `conformance-runner:latest`, which are test inputs whose whole point is to be a fixed
|
|
// shape, not software to keep current. `conformance/**` was already ignored for the same
|
|
// reason; this closes the matching hole that enabling the `kubernetes` manager would otherwise
|
|
// have opened.
|
|
// conformance/** NARROWED 2026-10-29 to its subdirectories: ignorePaths applies to custom
|
|
// managers too (lib/workers/repository/extract/file-match.ts getMatchingFiles ->
|
|
// filterIgnoredFiles), so the blanket glob also hid conformance/versions.env, which now carries
|
|
// the conformance-runner digest Renovate must maintain. Everything else under conformance/
|
|
// stays ignored, for the original reason (test fixtures with deliberately fixed shapes).
|
|
"ignorePaths": [
|
|
"**/*.example",
|
|
"**/*.sops.yaml",
|
|
"conformance/config/**",
|
|
"conformance/incluster/**",
|
|
"conformance/lib/**",
|
|
"conformance/requirements/**",
|
|
"conformance/runs/**",
|
|
"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
|
|
}
|
|
}
|