Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,23 @@ jobs:
echo "Changed files:"
echo "${FILES}"

renovate-annotations:
name: Templated chart versions are visible to Renovate
# GitHub-hosted, nicht kind-testing-labda: der Job braucht weder Cluster
# noch machineshop, und auf den self-hosted Runnern scheitert
# actions/checkout beim Aufraeumen des Workspace an
# .claude/skills — das Verzeichnis ist im Repo getrackt und liegt dort
# aus einem frueheren Container-Job root:root, waehrend checkout als
# gh-runner laeuft (EACCES beim rmdir). Gleiche Konvention wie der
# validate-Gate in stuttgart-things/flux.
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v7
- name: Check "# renovate:" annotations
run: ./hack/check-chart-annotations.sh

yaml-lint:
name: Lint yaml files
uses: stuttgart-things/github-workflow-templates/.github/workflows/call-yaml-lint.yaml@main
Expand Down
9 changes: 9 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,12 @@ repos:
language: python
# for backward compatibility
files: .* # all files

- repo: local
hooks:
- id: check-chart-annotations
name: Templated chart versions carry a renovate annotation
entry: hack/check-chart-annotations.sh
language: script
pass_filenames: false
files: ^(apps|cicd|database|infra|monitoring)/.*\.ya?ml(\.gotmpl)?$
68 changes: 67 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,75 @@ helmfile -f apps/grafana.yaml template \
- **Commit messages**: Follow [Angular commit convention](https://www.conventionalcommits.org/) — semantic-release uses `@semantic-release/commit-analyzer` with Angular preset (`.releaserc`)
- **Branch naming**: `feature/**`, `feat/**`, `fix/**`, `renovate/**`
- **Releases**: Automated via `npx semantic-release` on `main` branch with tag format `v${version}`
- **Dependency updates**: Renovate bot manages Helm chart version updates across all `.yaml` and `.yaml.gotmpl` files (`renovate.json`)
- **Dependency updates**: Renovate manages Helm chart version updates (`renovate.json`) — see [Dependency Management](#dependency-management) for the annotation every templated chart version needs
- **Domain sanitization**: A pre-commit hook replaces `.sva.de` domains with `.example.com` in committed files

## Dependency Management

Renovate is configured in `renovate.json` with the `helmfile` manager matching every
`.yaml` / `.yaml.gotmpl` file, plus two `customManagers` for the templated versions
described below. `.k2n/**` and `tests/**` are in `ignorePaths` — the k2n examples are
generation input, not deployed state.

### Templated chart versions need a `# renovate:` annotation

Renovate's `helmfile` manager reads `releases[].version`. It cannot resolve Go
templates — `version: {{ .Values.version }}` is skipped with
`skipReason: contains-variable` and produces **no PR, no warning, no log entry**.

Since the helmfiles keep their versions in `environments.default.values`, that hid
every chart in this repo from Renovate. Each such value therefore carries a comment
naming the datasource, and a `customManager` updates the default in place:

```yaml
environments:
default:
values:
# renovate: datasource=helm depName=cert-manager registryUrl=https://charts.jetstack.io
- version: v1.21.0
```

Derive the annotation from the `repositories` entry the release's `chart:` points at:

| repositories entry | Annotation |
|---|---|
| `oci: true`, `url: ghcr.io/<path>` | `datasource=docker depName=ghcr.io/<path>/<chart>` |
| plain HTTPS repo | `datasource=helm depName=<chart> registryUrl=<url>` |

A `chart:` that is itself a full `oci://` URL (e.g. the gha-runner helmfiles) uses that
URL verbatim as `depName`.

**When adding a release, add the annotation too** — without it the chart is silently
invisible to Renovate and will never be updated. `task check-renovate` (also wired into
pre-commit and the CI workflow) fails on any templated chart version that is missing one.

```bash
task check-renovate # fail on a missing annotation
task lint-renovate # validate renovate.json against the Renovate schema
task preview-renovate # dry-run Renovate against the working tree, writing nothing
```

### Never set `extractVersion` / `extractVersionTemplate`

`extractVersion` does not only normalise the version for comparison — Renovate writes
the **extracted** value back. With `^v?(?<version>.*)$` a registry tag of `v0.2.2` is
written as `0.2.2`, and `ghcr.io/stuttgart-things/homerun`, `cert-manager` and
`vcluster` are all tagged **with** the `v`, so the default would resolve to no chart at
all. Leave the field off and each datasource's own versioning writes the tag back
exactly as published.

### Known lookup failure

`docker-registry` (`database/registry.yaml.gotmpl`, `twuni` → https://helm.twun.io) is
reported on the Dependency Dashboard as `Failed to look up helm package
docker-registry: no-result`. Its version is hard-coded, so this is unrelated to the
annotations — fixing it means repointing the helmfile at a repository that resolves.

Worth re-checking with `task preview-renovate` after any change: `harbor` points at
https://charts.bitnami.com/bitnami, which Bitnami has been winding down in favour of
`oci://registry-1.docker.io/bitnamicharts`. If the lookup comes back empty, the
helmfile's `repositories` entry needs repointing, not the annotation.

## Key Tools

- **helmfile** — Declarative Helm chart deployment
Expand Down
15 changes: 15 additions & 0 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -545,3 +545,18 @@ tasks:
--src "$SRC" \
--helmfile-ref "$HELMFILE_NAME" \
--progress plain -vv

check-renovate:
desc: Fail if a templated chart version lacks its "# renovate:" annotation
cmds:
- ./hack/check-chart-annotations.sh

lint-renovate:
desc: Validate renovate.json against the current Renovate schema
cmds:
- npx --yes --package renovate renovate-config-validator

preview-renovate:
desc: Dry-run Renovate locally and list the updates it would propose
cmds:
- LOG_LEVEL={{ .LOG_LEVEL | default "info" }} npx --yes --package renovate renovate --platform=local --dry-run=full
1 change: 1 addition & 0 deletions apps/awx.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
environments:
default:
values:
# renovate: datasource=helm depName=awx-operator registryUrl=https://ansible-community.github.io/awx-operator-helm/
- version: 3.2.0
- namespace: awx
- installOperator: true
Expand Down
1 change: 1 addition & 0 deletions apps/backstage.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
environments:
default:
values:
# renovate: datasource=docker depName=ghcr.io/backstage/charts/backstage
- version: "2.6.3"
- namespace: backstage
- clusterDomain: "172.18.0.3.nip.io"
Expand Down
1 change: 1 addition & 0 deletions apps/gitea.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
environments:
default:
values:
# renovate: datasource=helm depName=gitea registryUrl=https://dl.gitea.com/charts
- version: 12.1.3
- namespace: gitea
- enableIngress: false
Expand Down
2 changes: 2 additions & 0 deletions apps/harbor.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
environments:
default:
values:
# renovate: datasource=helm depName=harbor registryUrl=https://charts.bitnami.com/bitnami
- version: 27.0.3
- namespace: harbor
- enablePersistence: true
Expand All @@ -19,6 +20,7 @@ environments:
- createCertificateResource: false
- deployHttpRoute: false
- deployProjectProxy: false
# renovate: datasource=docker depName=ghcr.io/hiddenmarten/harbor-project-proxy
- projectProxyVersion: 0.0.1
- gatewayName: cilium-gateway
- gatewayNamespace: default
Expand Down
1 change: 1 addition & 0 deletions apps/homerun-base-stack.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
environments:
default:
values:
# renovate: datasource=docker depName=ghcr.io/stuttgart-things/homerun
- version: {{ .Values.version | default "v0.2.1" }}
- namespace: {{ .Values.namespace | default "homerun" }}
- redisStackEnabled: {{ .Values.redisStackEnabled | default true }}
Expand Down
1 change: 1 addition & 0 deletions apps/kyverno.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: kyverno
# renovate: datasource=helm depName=kyverno registryUrl=https://kyverno.github.io/kyverno/
- version: 3.5.1
---
releases:
Expand Down
1 change: 1 addition & 0 deletions apps/minio.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: minio
# renovate: datasource=docker depName=ghcr.io/stuttgart-things/charts/minio/minio
- version: 16.0.10
- clusterIssuer: selfsigned
- issuerKind: cluster-issuer
Expand Down
1 change: 1 addition & 0 deletions apps/rancher.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: cattle-system
# renovate: datasource=helm depName=rancher registryUrl=https://releases.rancher.com/server-charts/latest
- version: 2.13.0
- hostname: rancher-things
- domain: example.com
Expand Down
2 changes: 2 additions & 0 deletions apps/vault.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: vault
# renovate: datasource=docker depName=ghcr.io/stuttgart-things/charts/vault/vault
- version: 1.9.0
- deployCertificate: false
- deployAutounseal: false
Expand All @@ -25,6 +26,7 @@ environments:
- osShellRepository: stuttgart-things/os-shell
- osShellTag: 12-debian-12-r50
- osShellPullPolicy: IfNotPresent
# renovate: datasource=helm depName=vault-autounseal registryUrl=https://pytoshka.github.io/vault-autounseal
- autounsealVersion: 0.5.3
- autounsealVaultUrl: http://vault-server.vault.svc:8200
- autounsealLabelSelector: app.kubernetes.io/component=server
Expand Down
1 change: 1 addition & 0 deletions cicd/argocd.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ environments:
- serviceType: ClusterIP
- adminPassword: ""
- adminPasswordMTime: ""
# renovate: datasource=docker depName=ghcr.io/argoproj/argo-helm/argo-cd
- version: 9.4.15
- namespace: argocd
- hostname: argocd
Expand Down
1 change: 1 addition & 0 deletions cicd/crossplane.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: crossplane-system
# renovate: datasource=helm depName=crossplane registryUrl=https://charts.crossplane.io/stable
- version: 2.3.3
# Providers are installed as Provider CRs (with RBAC) by
# crossplane-providers.yaml.gotmpl, not via the upstream chart's
Expand Down
1 change: 1 addition & 0 deletions cicd/flux-operator.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: flux-system
# renovate: datasource=docker depName=ghcr.io/controlplaneio-fluxcd/charts/flux-operator
- version: 0.28.0
- installOperator: true
---
Expand Down
1 change: 1 addition & 0 deletions cicd/gha-runner-controller.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: arc-systems
# renovate: datasource=docker depName=ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
- version: 0.12.1
---
releases:
Expand Down
1 change: 1 addition & 0 deletions cicd/gha-runner-scale-set.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: arc-runner
# renovate: datasource=docker depName=ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set
- version: 0.12.1
- repoName: ansible
- ghaControllerNamespace: arc-systems
Expand Down
1 change: 1 addition & 0 deletions cicd/komoplane.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: crossplane-system
# renovate: datasource=helm depName=komoplane registryUrl=https://helm-charts.komodor.io
- version: 0.1.6
- enableIngress: true
- clusterIssuer: selfsigned
Expand Down
1 change: 1 addition & 0 deletions cicd/tekton.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ environments:
- imagePullPolicy: Always
- disableInlineSpec: ""
- enableTektonPipeline: true
# renovate: datasource=docker depName=ghcr.io/stuttgart-things/tekton/tekton
- version: 0.77.5
- enableTektonPruner: false
---
Expand Down
1 change: 1 addition & 0 deletions cicd/vcluster.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ environments:
values:
- namespace: vcluster
- clusterName: vcluster
# renovate: datasource=helm depName=vcluster registryUrl=https://charts.loft.sh
- version: v0.28.0
---
releases:
Expand Down
1 change: 1 addition & 0 deletions database/keycloak.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ environments:
- storageClass: standard
- issuerKindAnnotation: "cluster-issuer"
- createCertificateResource: false
# renovate: datasource=docker depName=ghcr.io/stuttgart-things/charts/keycloak/keycloak
- version: 25.2.0
- imageRegistry: ghcr.io
- imageRepository: stuttgart-things/keycloak
Expand Down
1 change: 1 addition & 0 deletions database/postgres.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: postgres
# renovate: datasource=helm depName=cloudnative-pg registryUrl=https://cloudnative-pg.github.io/charts
- version: 0.24.0
---
repositories:
Expand Down
1 change: 1 addition & 0 deletions database/postgresdb.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ environments:
default:
values:
- namespace: postgres
# renovate: datasource=docker depName=ghcr.io/stuttgart-things/charts/postgresql/postgresql
- version: 16.7.26
- postgresPassword: "platformEngineer" # pragma: allowlist secret
- username: "dev"
Expand Down
1 change: 1 addition & 0 deletions database/redis-stack.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
environments:
default:
values:
# renovate: datasource=docker depName=ghcr.io/stuttgart-things/charts/redis/redis
- chartVersion: 17.1.4
- namespace: redis-stack
- serviceType: ClusterIP
Expand Down
1 change: 1 addition & 0 deletions database/zot.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
environments:
default:
values:
# renovate: datasource=helm depName=zot registryUrl=https://zotregistry.dev/helm-charts/
- version: 0.1.75
- ingressEnabled: true
- ingressClass: nginx
Expand Down
73 changes: 73 additions & 0 deletions hack/check-chart-annotations.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
#
# Fail if a helmfile release takes its chart version from an environment value
# without a "# renovate:" annotation on that value.
#
# Renovate's helmfile manager reads releases[].version. A Go template such as
# version: {{ .Values.version }}
# is skipped with skipReason "contains-variable" -- no PR, no warning, no log
# entry. The annotation plus the customManager in renovate.json is what makes
# the default in environments.default.values visible again.
#
set -euo pipefail

cd "$(dirname "$0")/.."

fail=0

mapfile -t files < <(
git ls-files 'apps/*' 'cicd/*' 'database/*' 'infra/*' 'monitoring/*' \
| grep -E '\.ya?ml(\.gotmpl)?$' \
| grep -v '/values/'
)

for f in "${files[@]}"; do
grep -q '^releases:' "$f" || continue

# value keys referenced as a chart version, e.g. "version: {{ .Values.foo }}"
mapfile -t keys < <(
grep -oE '^[[:space:]]+version:[[:space:]]*\{\{[[:space:]]*\.Values\.[A-Za-z0-9_]+' "$f" \
| sed 's/.*\.Values\.//' | sort -u
)

for key in "${keys[@]:-}"; do
[ -n "$key" ] || continue

line=$(grep -nE "^[[:space:]]*-[[:space:]]+${key}:" "$f" | head -1 | cut -d: -f1 || true)
if [ -z "$line" ]; then
echo "ERROR: $f: chart version uses .Values.${key}, but no '- ${key}:' default exists in this file"
fail=1
continue
fi

if [ "$line" -lt 2 ] || ! sed -n "$((line - 1))p" "$f" | grep -q '# renovate:'; then
echo "ERROR: $f:${line}: '- ${key}:' has no '# renovate:' annotation -- Renovate will never update this chart"
fail=1
fi
done
done

if [ "$fail" -ne 0 ]; then
cat <<'HINT'

Add the annotation directly above the value, derived from the repositories entry
the release's chart points at:

OCI repo (oci: true) -> # renovate: datasource=docker depName=<host>/<path>/<chart>
plain HTTPS repo -> # renovate: datasource=helm depName=<chart> registryUrl=<url>

Example:

environments:
default:
values:
# renovate: datasource=helm depName=cert-manager registryUrl=https://charts.jetstack.io
- version: v1.21.0

Never add extractVersion / extractVersionTemplate: Renovate writes the extracted
value back, so stripping a leading "v" produces a default that resolves to no tag.
HINT
exit 1
fi

echo "OK: every templated chart version carries a '# renovate:' annotation"
Loading
Loading