feat: initial scaffold from helm-template
Validate login GitOps repo / validate (push) Successful in 9s

- Keycloak Operator v26 deployed to keycloak-system namespace
- Keycloak HA instance (2 replicas, jdbc-ping cluster discovery)
- Dedicated CNPG cluster (local-postgres storage, 2 instances)
- KeycloakRealmImport: home-lab realm with groups and traefik-oidc client
- Traefik IngressRoute: login.olb42.com (CF Access bypass)
- Admin credentials placeholder (seal before first deploy)
- ArgoCD ApplicationSets: login-operator + login
This commit is contained in:
2026-05-10 22:32:49 +01:00
commit 6f29be2987
21 changed files with 750 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Copied from helm-template; update GITEA_API_URL and repo details as needed.
set -euo pipefail
GITEA_API_URL="${GITEA_API_URL:-https://git.olb42.com/api/v1}"
REPO_OWNER="${REPO_OWNER:-olb42}"
REPO_NAME="${REPO_NAME:-login}"
PR_BRANCH="dormant/$(date +%Y%m%d-%H%M%S)"
BASE_BRANCH="main"
if [[ -z "${GITEA_TOKEN:-}" ]]; then
echo "GITEA_TOKEN is required"
exit 1
fi
git config user.email "[email protected]"
git config user.name "CI Automation"
git checkout -b "$PR_BRANCH"
# Swap production overlay for dormant in the ArgoCD ApplicationSet
# This is handled by ArgoCD dormant logic; just open the PR.
git push origin "$PR_BRANCH"
curl -s -X POST "$GITEA_API_URL/repos/$REPO_OWNER/$REPO_NAME/pulls" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"Propose dormant mode for login\",
\"body\": \"Automated PR to switch login Keycloak to dormant overlay.\",
\"head\": \"$PR_BRANCH\",
\"base\": \"$BASE_BRANCH\"
}"
echo "Dormant PR created"
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -euo pipefail
event_name="${GITHUB_EVENT_NAME:-}"
git_ref="${GITHUB_REF:-}"
if [[ "$event_name" != "push" || "$git_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"
if ! kubectl config current-context >/dev/null 2>&1; then
echo "Skipping bootstrap apply: kubeconfig secret is not usable in this runner"
exit 0
fi
# Apply both ApplicationSets (multi-document YAML)
kubectl apply -f bootstrap/applicationset.yaml
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env bash
set -euo pipefail
mkdir -p .ci-schemas/argoproj.io .ci-schemas/traefik.io .ci-schemas/bitnami.com .ci-rendered
download_schema() {
local url="$1" dir="$2" base="$3"
mkdir -p "$dir"
if curl -fsSL "$url" -o "$dir/${base}_v1alpha1.json" 2>/dev/null; then
cp "$dir/${base}_v1alpha1.json" "$dir/${base}.json"
else
echo "Warning: could not download schema $url"
fi
}
validate_yaml_syntax() {
echo "==> Validating YAML syntax"
find . -type f \( -name '*.yaml' -o -name '*.yml' \) \
! -path './.git/*' ! -path './.ci-*/*' \
-print0 | while IFS= read -r -d '' file; do
python3 - "$file" <<'PY'
import sys, yaml
with open(sys.argv[1]) as f:
list(yaml.safe_load_all(f))
PY
done
}
validate_kustomize_overlays() {
echo "==> Building Kustomize overlays"
for overlay in manifest/overlays/*/; do
[[ -f "${overlay}kustomization.yaml" ]] || continue
name="$(basename "$overlay")"
echo " Building $name overlay"
if command -v kustomize &>/dev/null; then
kustomize build "$overlay" > ".ci-rendered/kustomize-${name}.yaml" 2>&1 || \
echo " Warning: kustomize build failed for $name (remote resources may require network)"
else
kubectl kustomize "$overlay" > ".ci-rendered/kustomize-${name}.yaml" 2>&1 || \
echo " Warning: kubectl kustomize failed for $name"
fi
done
}
prepare_crd_schemas() {
echo "==> Preparing CRD schemas"
download_schema \
"https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/argoproj.io/applicationset_v1alpha1.json" \
".ci-schemas/argoproj.io" "applicationset"
download_schema \
"https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/traefik.io/ingressroute_v1alpha1.json" \
".ci-schemas/traefik.io" "ingressroute"
download_schema \
"https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/bitnami.com/sealedsecret_v1alpha1.json" \
".ci-schemas/bitnami.com" "sealedsecret"
}
validate_kubernetes_manifests() {
echo "==> Validating Kubernetes manifests with kubeconform"
local bootstrap_enabled=false
if grep -Eq '^[[:space:]]*enabled:[[:space:]]*true' bootstrap/config.yaml 2>/dev/null; then
bootstrap_enabled=true
fi
find . -type f \( -name '*.yaml' -o -name '*.yml' \) \
! -path './.git/*' ! -path './.gitea/*' ! -path './.ci-*/*' \
! -name '*kustomization.yaml' ! -name 'config.yaml' \
! -name '*.plain.yaml' ! -name '*.example.yaml' \
$( [[ "$bootstrap_enabled" != "true" ]] && echo "! -name 'applicationset.yaml'" ) \
| sort | xargs kubeconform \
-strict \
-kubernetes-version 1.35.0 \
-schema-location default \
-schema-location 'https://git.olb42.com/olb042/kubeconform/raw/branch/main/crdSchemas/{{ .ResourceKind }}_{{ .ResourceAPIVersion }}.json' \
-ignore-missing-schemas \
-summary
}
if ! command -v python3 &>/dev/null; then echo "python3 required"; exit 1; fi
if ! command -v kubeconform &>/dev/null; then echo "kubeconform required"; exit 1; fi
validate_yaml_syntax
prepare_crd_schemas
validate_kustomize_overlays
validate_kubernetes_manifests
echo "Validation completed"