This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
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
|
||||
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||
curl -fsSL https://github.com/getsops/sops/releases/latest/download/sops-v3.x.linux.amd64 \
|
||||
-o /usr/local/bin/sops
|
||||
chmod +x /usr/local/bin/sops
|
||||
curl -fsSL https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 \
|
||||
-o /usr/local/bin/yq
|
||||
chmod +x /usr/local/bin/yq
|
||||
|
||||
# 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 ApplicationSet is also a CRD. It stays dormant until bootstrap
|
||||
# is enabled, but once enabled we validate it with an explicit schema.
|
||||
mkdir -p .ci-schemas/argoproj.io
|
||||
curl -fsSL https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/argoproj.io/applicationset_v1alpha1.json \
|
||||
-o .ci-schemas/argoproj.io/applicationset_v1alpha1.json
|
||||
cp .ci-schemas/argoproj.io/applicationset_v1alpha1.json .ci-schemas/argoproj.io/ApplicationSet_v1alpha1.json
|
||||
cp .ci-schemas/argoproj.io/applicationset_v1alpha1.json .ci-schemas/argoproj.io/ApplicationSet.json
|
||||
cp .ci-schemas/argoproj.io/applicationset_v1alpha1.json .ci-schemas/argoproj.io/applicationset.json
|
||||
|
||||
- name: Helm lint
|
||||
run: |
|
||||
found=0
|
||||
|
||||
for parent in helm custom-charts; do
|
||||
[ -d "$parent" ] || continue
|
||||
|
||||
for chart in "$parent"/*; do
|
||||
[ -d "$chart" ] || continue
|
||||
found=1
|
||||
echo "Linting $chart"
|
||||
helm lint "$chart"
|
||||
done
|
||||
done
|
||||
|
||||
if [ "$found" -eq 0 ]; then
|
||||
echo "No Helm charts found"
|
||||
fi
|
||||
|
||||
- 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 '*.enc.yaml' \
|
||||
! -name '*.secret.yaml' \
|
||||
! -name '*kustomization.yaml' \
|
||||
! -name 'secret-generator.yaml' \
|
||||
! -path './bootstrap/config.yaml' \
|
||||
| sort
|
||||
)
|
||||
|
||||
if [ "$bootstrap_enabled" != "true" ]; then
|
||||
filtered=()
|
||||
for manifest in "${manifests[@]}"; do
|
||||
[ "$manifest" = "./bootstrap/applicationset.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: Check SOPS sync
|
||||
env:
|
||||
SOPS_SYNC_HMAC_KEY: ${{ secrets.SOPS_SYNC_HMAC_KEY }}
|
||||
run: scripts/ci/check-sops-sync
|
||||
|
||||
- name: Apply bootstrap ApplicationSet
|
||||
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 "KUBECONFIG_B64 secret is required to apply bootstrap/applicationset.yaml"
|
||||
exit 1
|
||||
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/applicationset.yaml
|
||||
Reference in New Issue
Block a user