# ============================================ # 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 (Sat 02: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 ", "repositories": ["admin/homelab-manifests"], "onboarding": false, "requireConfig": "optional", "dependencyDashboard": true, "dependencyDashboardTitle": "Renovate Dependency Dashboard", "prHourlyLimit": 16, "prConcurrentLimit": 16, "enabledManagers": ["kubernetes", "helm-values", "custom.regex"], "kubernetes": { "managerFilePatterns": ["/.+\\.ya?ml$/"] }, "customManagers": [ { "description": "termix uses a release-X.Y.Z prefixed tag that the kubernetes manager's docker-versioning pre-check rejects (so no PRs are ever created). This customManager extracts the image directly, redirects the version lookup to GitHub Releases at Termix-SSH/Termix (which exposes timestamps the 3-day stability gate needs), and uses extractVersion to strip the `release-` prefix so loose semver can parse it.", "customType": "regex", "managerFilePatterns": ["/termix-system/.+\\.ya?ml$/"], "matchStrings": [ "image:\\s+(?ghcr\\.io/lukegus/termix):(?release-\\d+\\.\\d+\\.\\d+)" ], "datasourceTemplate": "github-releases", "packageNameTemplate": "Termix-SSH/Termix", "versioningTemplate": "loose", "extractVersionTemplate": "^release-(?.+)$" } ], "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": "wanderer: db + web update together in one PR", "matchPackageNames": ["flomp/wanderer-db", "flomp/wanderer-web"], "groupName": "wanderer" }, { "description": "termix: kubernetes manager would extract the image with versioning=docker and silently skip it (release-1.11.0 fails the docker pre-check). Disable that extraction; customManagers above does the real work via github-releases.", "matchManagers": ["kubernetes"], "matchPackageNames": ["ghcr.io/lukegus/termix"], "enabled": false } ], "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: # Sat 02:00 Europe/Budapest — leaves the full weekend for troubleshooting # if a Renovate-merged update breaks something. schedule: "0 2 * * 6" 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.209.3 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