Files
homelab-manifests/admin-system/renovate.yaml
T
admin 628a63da83 renovate: revert global timestamp-optional; narrowly bypass age gate for termix
Last commit's global `minimumReleaseAgeBehaviour: timestamp-optional` did
two unwanted things:

  1) Dry-run showed 0 "Would commit" branches (was 33 before). The flag
     appears to alter Renovate's filtering more broadly than expected and
     is not the right knob here.
  2) Automated security review correctly flagged the global form as
     fail-open: a missing timestamp on ANY package would bypass the
     stability gate, weakening supply-chain protection across the fleet.

Narrow fix instead:
  - Revert the global setting (back to default `timestamp-required`).
  - Add `minimumReleaseAge: "0 days"` ONLY to the termix packageRule.
    ghcr.io OCI manifests for ghcr.io/lukegus/termix don't expose a
    release timestamp Renovate can read, so the global 3-day gate would
    otherwise hold updates indefinitely (this is the same class of issue
    that's been keeping reloader/homepage/headlamp on "Pending Status
    Checks" for 8+ days). Major bumps still gated by the global major
    rule (`dependencyDashboardApproval: true`).

Other ghcr.io packages with the same issue (reloader, homepage, headlamp)
remain on the dashboard's "Pending Status Checks" list and can be
force-approved per-update via the checkbox UX. That's a slower but safer
manual-approval path that preserves the supply-chain gate's intent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-05 07:43:37 +02:00

190 lines
6.9 KiB
YAML

# ============================================
# Renovate Bot - Self-hosted dependency updater
# ============================================
# https://docs.renovatebot.com
# Image: renovate/renovate (plain tag = minimal image, "formerly slim";
# -slim suffix was retired after v37.440.x, so we pin the plain tag)
#
# PILOT SCOPE (intentionally narrow):
# Runs weekly (Sun 04:00 Europe/Budapest) as a CronJob and opens
# dependency-update PRs against admin/homelab-manifests on Gitea.
# Only the `kubernetes` and `helm-values` managers are enabled, and a
# default-deny packageRule limits updates to exactly four pilot images:
# - ghcr.io/thomiceli/opengist
# - louislam/uptime-kuma
# - f0rc3/gokapi
# - docker.io/calcom/cal.com
# minor/patch -> PR with Gitea native auto-merge; major -> waits for
# manual approval via a checkbox on the Dependency Dashboard issue.
#
# Stateless & ephemeral: no Service, Ingress, or PVC. Writable /tmp is an
# emptyDir (root FS is read-only); Renovate uses it for git clones + cache.
#
# Secrets (created manually, NOT in git) come from Secret `renovate-secrets`:
# - RENOVATE_TOKEN (Gitea PAT)
# - RENOVATE_GITHUB_COM_TOKEN (GitHub PAT, for release notes)
# ============================================
---
apiVersion: v1
kind: ConfigMap
metadata:
name: renovate-config
namespace: admin-system
labels:
app.kubernetes.io/instance: renovate
app.kubernetes.io/name: renovate
data:
config.json: |
{
"platform": "gitea",
"endpoint": "https://gitea.dooplex.hu/api/v1",
"gitAuthor": "Renovate Bot <renovate@dooplex.hu>",
"repositories": ["admin/homelab-manifests"],
"onboarding": false,
"requireConfig": "optional",
"dependencyDashboard": true,
"dependencyDashboardTitle": "Renovate Dependency Dashboard",
"prHourlyLimit": 8,
"prConcurrentLimit": 8,
"enabledManagers": ["kubernetes", "helm-values"],
"kubernetes": {
"managerFilePatterns": ["/.+\\.ya?ml$/"]
},
"packageRules": [
{
"description": "All apps: 3-day stability gate before any PR opens",
"matchPackageNames": ["*"],
"minimumReleaseAge": "3 days"
},
{
"description": "Auto-merge minor/patch after the stability window",
"matchUpdateTypes": ["minor", "patch"],
"automerge": true,
"automergeType": "pr",
"platformAutomerge": true
},
{
"description": "Major bumps wait for dashboard approval (catches breaking/schema migrations)",
"matchUpdateTypes": ["major"],
"automerge": false,
"dependencyDashboardApproval": true
},
{
"description": "k3s-bundled components: never touch, they ride k3s upgrades",
"matchPackageNames": [
"rancher/local-path-provisioner",
"rancher/mirrored-coredns/coredns",
"rancher/mirrored-metrics-server"
],
"enabled": false
},
{
"description": "Critical core: PR opens with changelog but Viktor merges manually (deploy pipeline + SSO + DB operator). Some entries are no-ops if the image isn't pinned in this repo (ArgoCD bootstrap, authentik outpost images inherit chart defaults).",
"matchPackageNames": [
"gitea/gitea",
"quay.io/argoproj/argocd",
"ghcr.io/goauthentik/server",
"ghcr.io/goauthentik/ldap",
"ghcr.io/goauthentik/proxy",
"ghcr.io/cloudnative-pg/cloudnative-pg"
],
"automerge": false
},
{
"description": "termix: regex versioning parses the release-X.Y.Z prefix; minimumReleaseAge:0 bypasses the stability gate because ghcr.io OCI manifests for this image don't expose a release timestamp (timestamp-required mode otherwise holds it forever). Major bumps still queue for dashboard approval via the global major rule.",
"matchPackageNames": ["ghcr.io/lukegus/termix"],
"versioning": "regex:^release-(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)$",
"minimumReleaseAge": "0 days"
},
{
"description": "wanderer: db + web update together in one PR",
"matchPackageNames": ["flomp/wanderer-db", "flomp/wanderer-web"],
"groupName": "wanderer"
}
],
"labels": ["renovate"]
}
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: renovate
namespace: admin-system
labels:
app.kubernetes.io/instance: renovate
app.kubernetes.io/name: renovate
app.kubernetes.io/version: "43.197.0"
spec:
schedule: "0 4 * * 0"
timeZone: "Europe/Budapest"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
startingDeadlineSeconds: 600
jobTemplate:
metadata:
labels:
app.kubernetes.io/instance: renovate
app.kubernetes.io/name: renovate
app.kubernetes.io/version: "43.197.0"
spec:
template:
metadata:
labels:
app.kubernetes.io/instance: renovate
app.kubernetes.io/name: renovate
app.kubernetes.io/version: "43.197.0"
annotations:
# Renovate uses plain X.Y.Z semver tags (no -slim suffix anymore)
match-regex.version-checker.io/renovate: '^\d+\.\d+\.\d+$'
spec:
enableServiceLinks: false
restartPolicy: OnFailure
containers:
- name: renovate
image: renovate/renovate:43.197.0
imagePullPolicy: IfNotPresent
envFrom:
- secretRef:
name: renovate-secrets
env:
- name: TZ
value: Europe/Budapest
- name: LOG_LEVEL
value: info
- name: RENOVATE_CONFIG_FILE
value: /config/config.json
# Renovate needs a writable tmp for git clones + cache;
# root FS is read-only so point it at the emptyDir below.
- name: TMPDIR
value: /tmp
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 2000m
memory: 2Gi
securityContext:
runAsNonRoot: true
runAsUser: 12021
runAsGroup: 0
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: config
mountPath: /config
readOnly: true
- name: tmp
mountPath: /tmp
volumes:
- name: config
configMap:
name: renovate-config
- name: tmp
emptyDir:
sizeLimit: 2Gi