name: Validate manifests on: push: pull_request: jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install tools run: | curl -sL https://github.com/yannh/kubeconform/releases/latest/download/kubeconform-linux-amd64.tar.gz \ | tar xz -C /usr/local/bin # Traefik IngressRoute is a CRD, so kubeconform needs an extra schema source. mkdir -p .ci-schemas/traefik.io curl -fsSL https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/traefik.io/ingressroute_v1alpha1.json \ -o .ci-schemas/traefik.io/ingressroute_v1alpha1.json cp .ci-schemas/traefik.io/ingressroute_v1alpha1.json .ci-schemas/traefik.io/IngressRoute_v1alpha1.json cp .ci-schemas/traefik.io/ingressroute_v1alpha1.json .ci-schemas/traefik.io/IngressRoute.json cp .ci-schemas/traefik.io/ingressroute_v1alpha1.json .ci-schemas/traefik.io/ingressroute.json # ArgoCD Application is also a CRD. mkdir -p .ci-schemas/argoproj.io curl -fsSL https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/argoproj.io/application_v1alpha1.json \ -o .ci-schemas/argoproj.io/application_v1alpha1.json cp .ci-schemas/argoproj.io/application_v1alpha1.json .ci-schemas/argoproj.io/Application_v1alpha1.json cp .ci-schemas/argoproj.io/application_v1alpha1.json .ci-schemas/argoproj.io/Application.json cp .ci-schemas/argoproj.io/application_v1alpha1.json .ci-schemas/argoproj.io/application.json - name: kubeconform - raw YAML run: | bootstrap_enabled=false if [ -f bootstrap/config.yaml ] && grep -Eq '^[[:space:]]*enabled:[[:space:]]*true[[:space:]]*$' bootstrap/config.yaml; then bootstrap_enabled=true fi mapfile -t manifests < <( find . -type f -name '*.yaml' \ ! -path './.gitea/*' \ ! -name '.sops.yaml' \ ! -name '*.secret.yaml' \ ! -name 'kustomization.yaml' \ ! \( -name 'secret*.yaml' \) \ ! \( -path '*/config/*' -prune \) \ ! -path './bootstrap/config.yaml' \ | sort ) if [ "$bootstrap_enabled" != "true" ]; then filtered=() for manifest in "${manifests[@]}"; do [ "$manifest" = "./bootstrap/application.yaml" ] && continue filtered+=("$manifest") done manifests=("${filtered[@]}") fi if [ "${#manifests[@]}" -eq 0 ]; then echo "No manifests found" exit 0 fi printf '%s\n' "${manifests[@]}" \ | xargs kubeconform \ -strict \ -kubernetes-version 1.35.0 \ -schema-location default \ -schema-location '.ci-schemas/{{.Group}}/{{.ResourceKind}}{{.KindSuffix}}.json' \ -schema-location '.ci-schemas/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \ -summary - name: SOPS - check no secret files committed unencrypted run: | fail=0 while IFS= read -r file; do if ! grep -q 'sops:' "$file"; then echo "ERROR: $file appears to be unencrypted" fail=1 fi done < <( find . -type f \( -name '*.secret.yaml' -o -name '*.enc.yaml' \) | sort ) exit "$fail" - name: Apply bootstrap Application env: KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} run: | if [ "${GITHUB_EVENT_NAME:-}" != "push" ] || [ "${GITHUB_REF:-}" != "refs/heads/main" ]; then echo "Skipping bootstrap apply: only push events on main may apply" exit 0 fi if [ ! -f bootstrap/config.yaml ] || ! grep -Eq '^[[:space:]]*enabled:[[:space:]]*true[[:space:]]*$' bootstrap/config.yaml; then echo "Skipping bootstrap apply: bootstrap/config.yaml is not enabled" exit 0 fi if [ -z "${KUBECONFIG_B64:-}" ]; then echo "Warning: KUBECONFIG_B64 secret not set — skipping bootstrap apply" exit 0 fi curl -fsSL https://dl.k8s.io/release/$(curl -fsSL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl \ -o /usr/local/bin/kubectl chmod +x /usr/local/bin/kubectl mkdir -p "${HOME}/.kube" printf '%s' "$KUBECONFIG_B64" | base64 -d > "${HOME}/.kube/config" kubectl apply -f bootstrap/application.yaml