diff --git a/.github/scripts/kubeconform.sh b/.github/scripts/kubeconform.sh new file mode 100644 index 00000000..7c4660f9 --- /dev/null +++ b/.github/scripts/kubeconform.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -o errexit +set -o pipefail + +KUBERNETES_DIR=$1 + +[[ -z "${KUBERNETES_DIR}" ]] && echo "Kubernetes location not specified" && exit 1 + +kustomize_args=("--load-restrictor=LoadRestrictionsNone") +kustomize_config="kustomization.yaml" +kubeconform_args=( + "-strict" + "-ignore-missing-schemas" + "-skip" + "Secret,ConfigMap" + "-schema-location" + "default" + "-schema-location" + "https://kubernetes-schemas.pages.dev/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json" + "-verbose" +) + + +echo "=== Validating standalone manifests in ${KUBERNETES_DIR} ===" +find "${KUBERNETES_DIR}" -maxdepth 1 -type f -name '*.yaml' -print0 | while IFS= read -r -d $'\0' file; +do + kubeconform "${kubeconform_args[@]}" "${file}" + if [[ ${PIPESTATUS[0]} != 0 ]]; then + exit 1 + fi +done + +echo "=== Validating all namespace.yaml files in ${KUBERNETES_DIR} ===" +find "${KUBERNETES_DIR}" -type f -name 'namespace.yaml' -print0 | while IFS= read -r -d $'\0' file; +do + echo "Validating ${file}" + kubeconform "${kubeconform_args[@]}" "${file}" + if [[ ${PIPESTATUS[0]} != 0 ]]; then + exit 1 + fi +done + +echo "=== Validating all helm-release.yaml files in ${KUBERNETES_DIR} ===" +find "${KUBERNETES_DIR}" -type f -name 'helm-release.yaml' -print0 | while IFS= read -r -d $'\0' file; +do + echo "Validating ${file}" + kubeconform "${kubeconform_args[@]}" "${file}" + if [[ ${PIPESTATUS[0]} != 0 ]]; then + exit 1 + fi +done + + +echo "=== Validating kustomizations in ${KUBERNETES_DIR}/ ===" +find "${KUBERNETES_DIR}" -type f -name $kustomize_config -print0 | while IFS= read -r -d $'\0' file; +do + echo "=== Validating kustomizations in ${file/%$kustomize_config} ===" + kustomize build "${file/%$kustomize_config}" "${kustomize_args[@]}" | kubeconform "${kubeconform_args[@]}" + if [[ ${PIPESTATUS[0]} != 0 ]]; then + exit 1 + fi +done \ No newline at end of file diff --git a/.github/workflows/kubeconform.yaml b/.github/workflows/kubeconform.yaml new file mode 100644 index 00000000..396fb343 --- /dev/null +++ b/.github/workflows/kubeconform.yaml @@ -0,0 +1,49 @@ +name: "Kubeconform" + +on: + pull_request: + +concurrency: + group: ${{ github.head_ref }}-pr-validate + cancel-in-progress: true + +env: + KUBERNETES_DIR: ./embed/generic/kubernetes + +jobs: + kubeconform: + name: Kubeconform + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + - name: Setup Homebrew + uses: Homebrew/actions/setup-homebrew@master + - name: Setup Workflow Tools + run: brew install fluxcd/tap/flux kubeconform kustomize + - name: Create dummy deploykey secret (CI only) + shell: bash + run: | + SECRET_PATH="embed/generic/kubernetes/flux-system/flux/deploykey.secret.yaml" + + if [[ ! -f "$SECRET_PATH" ]]; then + echo "Creating dummy deploykey.secret.yaml for kubeconform" + mkdir -p "$(dirname "$SECRET_PATH")" + touch "$SECRET_PATH" + fi + - name: Inject ConfigMap data for CI + shell: bash + run: | + CONFIG_PATH="embed/generic/kubernetes/flux-system/flux/clustersettings.secret.yaml" + + if [[ -f "$CONFIG_PATH" ]]; then + echo "Replacing REPLACEWITHENV in clustersettings.secret.yaml" + + # Example: replace with dummy key-values for CI + sed -i "s|REPLACEWITHENV| dummyKey: dummyValue|" "$CONFIG_PATH" + fi + - name: Run kubeconform + shell: bash + run: bash ./.github/scripts/kubeconform.sh ${{ env.KUBERNETES_DIR }} \ No newline at end of file