go-bananas/hack/helm-matrix.sh
Daniel Noulet 951dd8d26b
Some checks failed
ci / go (push) Has been cancelled
ci / admin-ui (push) Has been cancelled
ci / runtime-sdk (push) Has been cancelled
ci / helm (push) Has been cancelled
ci / openapi (push) Has been cancelled
ci / container (push) Has been cancelled
ci / release-config (push) Has been cancelled
ci / shared styling (push) Has been cancelled
ci / security (push) Has been cancelled
ci / all green (push) Has been cancelled
initial commit
2026-10-07 15:11:35 +02:00

135 lines
No EOL
5.2 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Renders the chart across a matrix of configurations and checks each result.
#
# Two things are being verified, and `helm lint` only covers the first:
#
# 1. Every configuration that should work renders to YAML that *parses*. A
# template bug that only triggers under a non-default value produces valid
# YAML in review and an unapplyable manifest in production, so each render is
# fed back through a YAML parser rather than trusted because helm exited zero.
#
# 2. Every configuration that should be refused is refused, and the refusal says
# which value to change. A validation guard that silently accepts a bad value
# is worse than no guard, because it moves the failure to run time.
#
# The matrix lives in a script rather than in the Makefile because it is a list of
# cases, and a list is easier to read, review and extend as shell than as make.
set -uo pipefail
CHART="${CHART:-deploy/helm/go-bananas}"
RELEASE="${RELEASE:-go-bananas}"
pass=0
fail=0
work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT
# yaml_ok verifies that a rendered file is parseable YAML.
yaml_ok() {
python3 -c '
import sys
try:
import yaml
except ImportError:
sys.exit(3)
list(yaml.safe_load_all(open(sys.argv[1])))
' "$1" 2>/dev/null
}
# ok renders a configuration that must succeed.
ok() {
local desc="$1"
shift
if ! helm template "$RELEASE" "$CHART" "$@" >"$work/out.yaml" 2>"$work/err.txt"; then
printf 'FAIL %s (should have rendered)\n' "$desc"
sed -n '1,3p' "$work/err.txt" | sed 's/^/ /'
fail=$((fail + 1))
return
fi
yaml_ok "$work/out.yaml"
case $? in
0) printf 'ok %s\n' "$desc"; pass=$((pass + 1)) ;;
3) printf 'ok %s (PyYAML absent, skipped the parse check)\n' "$desc"; pass=$((pass + 1)) ;;
*) printf 'FAIL %s (rendered output is not valid YAML)\n' "$desc"; fail=$((fail + 1)) ;;
esac
}
# rejected renders a configuration that must fail, and requires the message to name
# the problem rather than being a bare stack trace.
rejected() {
local desc="$1"
shift
if helm template "$RELEASE" "$CHART" "$@" >"$work/out.yaml" 2>"$work/err.txt"; then
printf 'FAIL %s (should have been refused but rendered)\n' "$desc"
fail=$((fail + 1))
return
fi
if grep -qE 'execution error|Error:' "$work/err.txt"; then
printf 'ok %s (refused: %s)\n' "$desc" \
"$(grep -oE '(execution error.*|Error: .*)' "$work/err.txt" | head -1 | cut -c1-100)"
pass=$((pass + 1))
else
printf 'FAIL %s (refused, but without an actionable message)\n' "$desc"
sed -n '1,3p' "$work/err.txt" | sed 's/^/ /'
fail=$((fail + 1))
fi
}
echo "== configurations that must render =="
ok "default values"
ok "oidc with an existing secret" \
--set identity.oidc.generateSecret=false \
--set identity.oidc.existingSecret=go-bananas-oidc
ok "oidc with a generated secret" \
--set identity.mode=oidc \
--set config.publicBaseUrl=https://themes.example.com
ok "production over https" \
--set config.environment=production \
--set config.publicBaseUrl=https://themes.example.com
ok "identity disabled" --set identity.mode=disabled
ok "development bypass" --set identity.mode=dev
ok "ingress with TLS" \
--set ingress.enabled=true \
--set ingress.hosts[0].host=themes.example.com \
--set ingress.tls[0].secretName=themes-tls \
--set ingress.tls[0].hosts[0]=themes.example.com
ok "ephemeral storage" --set persistence.type=emptyDir
ok "existing claim" --set persistence.existingClaim=bananas-data
ok "autoscaling and disruption budget" \
--set autoscaling.enabled=true --set podDisruptionBudget.enabled=true
ok "network policy" --set networkPolicy.enabled=true
ok "service monitor" --set metrics.serviceMonitor.enabled=true
ok "image pinned by digest" --set image.digest=sha256:deadbeef
ok "image in another registry" --set image.repository=quay.io/urpi/go-bananas
ok "base path" --set config.basePath=/themes
ok "extra environment" --set 'extraEnv[0].name=FOO' --set 'extraEnv[0].value=bar'
ok "snapshot cronjob" --set persistence.snapshot.enabled=true
echo
echo "== configurations that must be refused =="
rejected "both an existing and a generated secret" \
--set identity.oidc.existingSecret=go-bananas-oidc
rejected "neither an existing nor a generated secret" \
--set identity.oidc.generateSecret=false
rejected "an empty public base URL" \
--set config.publicBaseUrl=
rejected "a public base URL with a trailing slash" \
--set config.publicBaseUrl=https://themes.example.com/
rejected "a public base URL that is not a URL" \
--set config.publicBaseUrl=themes.example.com
rejected "TLS verification disabled in production" \
--set identity.oidc.skipTLSVerify=true --set config.environment=production
rejected "an unknown identity mode" --set identity.mode=nonsense
rejected "an OIDC mode with no issuer" --set identity.mode=oidc --set identity.oidc.issuer=
rejected "a shutdown timeout longer than the grace period" \
--set config.shutdownTimeoutMs=60000 --set deployment.terminationGracePeriodSeconds=30
rejected "an unknown top-level value" --set thisKeyDoesNotExist=1
echo
if [ "$fail" -gt 0 ]; then
printf '%d of %d checks failed\n' "$fail" "$((pass + fail))"
exit 1
fi
printf 'all %d chart checks passed\n' "$pass"