Der Probelauf des neuen Jobs ist an genau der Stelle gescheitert, an der man es nicht vermutet: 'git fetch gitea' lief durch (Gitea ist oeffentlich lesbar), 'git fetch origin main' dagegen brach ab mit 'unable to get local issuer certificate'. Der Runner stellt die Lab-CA nur seinem eigenen Klon-Schritt bereit, nicht dem Job-Script - der Klon oben im Log gelingt, der eigene git-Aufruf zwei Zeilen spaeter nicht. Zwei Aenderungen: 1. Die CA-Kette liegt jetzt als ci/lab-ca-chain.crt im Repo und wird per GIT_SSL_CAINFO gesetzt (CI_SERVER_TLS_CA_FILE zuerst, falls ein spaeterer Runner sie doch liefert). Ein CA-Zertifikat ist oeffentlich, kein Geheimnis - dieselbe Loesung wie im wiki-bookstack-Repo. Verifiziert: die Kette (aXionLabs Root + Intermediate) validiert https://git.lab. 2. 'git fetch origin main' faellt ganz weg. Der Runner hat main mit voller Historie schon ausgecheckt, CI_COMMIT_SHA ist dessen Stand - ein Netzaufruf weniger und eine Fehlerquelle weniger. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PKhFj1S3UdD6xL2fbWPeYj
120 lines
6.0 KiB
YAML
120 lines
6.0 KiB
YAML
# Leichter Verifikations-Job, portiert aus .gitea/workflows/deploy-on-push.yml
|
|
# (Gitea-CI-Rueckbau, CFGMON-11, erledigt 2026-08-01). Deployt nichts - Flux reconciled
|
|
# weiterhin selbststaendig aus dem Gitea-Mirror. Repo-Topologie: git.lab ist
|
|
# kanonisch, rohana/Gitea ist Push-Mirror und Flux-Quelle.
|
|
|
|
verify:
|
|
image: alpine:3.20
|
|
rules:
|
|
- if: $CI_COMMIT_BRANCH == "main"
|
|
changes:
|
|
- apps/**/*
|
|
- clusters/**/*
|
|
- .gitlab-ci.yml
|
|
script:
|
|
- apk add --no-cache git >/dev/null
|
|
- |
|
|
echo "YAML-Manifest-Check..."
|
|
find apps clusters -name "*.yaml" -type f | while read f; do
|
|
grep -q "^apiVersion:" "$f" || echo "WARN: $f enthaelt kein apiVersion - evtl. kein K8s-Manifest"
|
|
done
|
|
- |
|
|
echo "SOPS-Check der in diesem Push geaenderten Secret-Dateien..."
|
|
for f in $(git diff --name-only HEAD~1..HEAD -- '**/secret*.yaml' '**/credentials*.yaml' 2>/dev/null || true); do
|
|
if grep -q "ENC\[" "$f"; then echo "OK: $f ist verschluesselt"; else echo "WARNUNG: $f ist moeglicherweise NICHT verschluesselt!"; fi
|
|
done
|
|
- echo "Flux reconciled die Aenderungen innerhalb ~1 Minute (Quelle Gitea-Mirror)."
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# TURN-Rotation kanonisieren (laeuft NUR als Pipeline-Schedule)
|
|
#
|
|
# Der Rotations-CronJob laeuft im Cluster und erreicht git.lab nicht - er pusht
|
|
# seinen Branch deshalb nach Gitea. Von dort muss die Rotation ueber git.lab
|
|
# zurueck, sonst ueberschreibt der naechste Mirror-Push sie und Flux spielt still
|
|
# das ALTE Shared Secret wieder ein. Frueher war das ein monatlicher Handgriff;
|
|
# dieser Job erledigt ihn.
|
|
#
|
|
# Einrichtung (einmalig, braucht Rechte - siehe CLAUDE.md):
|
|
# 1. Project Access Token, Rolle Maintainer, Scope write_repository
|
|
# -> CI/CD-Variable CANONIZE_TOKEN (masked + protected)
|
|
# 2. Pipeline-Schedule anlegen, taeglich, z. B. "17 5 * * *"
|
|
#
|
|
# Warum taeglich statt monatlich zum Rotationstermin: ein monatlicher Schedule
|
|
# hat genau einen Versuch. Faellt der Runner an dem Tag aus, faellt die
|
|
# Kanonisierung ein Monat lang aus. Taeglich holt der Job jede offene Rotation
|
|
# spaetestens am Folgetag nach und ist ansonsten in Sekunden fertig.
|
|
# ---------------------------------------------------------------------------
|
|
canonize_rotation:
|
|
image: alpine:3.20
|
|
rules:
|
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
variables:
|
|
GIT_DEPTH: "0" # volle Historie: wir brauchen merge-base
|
|
script:
|
|
- apk add --no-cache git ca-certificates >/dev/null
|
|
- |
|
|
# Lab-CA. Der Runner stellt sie nur seinem eigenen Klon-Schritt bereit, nicht
|
|
# dem Job-Script - ein 'git fetch origin' im Script scheiterte deshalb an
|
|
# "unable to get local issuer certificate" (live gesehen, Pipeline 159).
|
|
# Deshalb liegt die Kette hier im Repo; sie ist ein oeffentliches Zertifikat,
|
|
# kein Geheimnis. CI_SERVER_TLS_CA_FILE zuerst, falls der Runner sie doch liefert.
|
|
if [ -n "$CI_SERVER_TLS_CA_FILE" ] && [ -f "$CI_SERVER_TLS_CA_FILE" ]; then
|
|
export GIT_SSL_CAINFO="$CI_SERVER_TLS_CA_FILE"
|
|
else
|
|
export GIT_SSL_CAINFO="$CI_PROJECT_DIR/ci/lab-ca-chain.crt"
|
|
fi
|
|
echo "CA: $GIT_SSL_CAINFO"
|
|
test -f "$GIT_SSL_CAINFO" || { echo "ABBRUCH: CA-Datei fehlt."; exit 1; }
|
|
- git config --global user.email "ci@axion1337.chat"
|
|
- git config --global user.name "TURN-Rotation (automatische Kanonisierung)"
|
|
- git remote add gitea https://rohana.axion1337.de/sorb/axion1337.chat-gitops.git
|
|
- git fetch --quiet gitea
|
|
# Kein 'fetch origin' noetig: der Runner hat main schon ausgecheckt (GIT_DEPTH 0),
|
|
# CI_COMMIT_SHA ist der Stand von main beim Anlegen der Pipeline.
|
|
- git checkout -B main "$CI_COMMIT_SHA"
|
|
- |
|
|
MERGED=0
|
|
for ref in $(git for-each-ref --format='%(refname:short)' 'refs/remotes/gitea/turn-secret-rotation-*'); do
|
|
SHA=$(git rev-parse "$ref")
|
|
if git merge-base --is-ancestor "$SHA" HEAD; then
|
|
echo "bereits kanonisiert: $ref"
|
|
continue
|
|
fi
|
|
echo "kanonisiere: $ref ($SHA)"
|
|
SUBJ="chore(coturn): TURN-Rotation aus ${ref#gitea/} uebernommen"
|
|
BODY="Automatisch kanonisiert: der Rotations-CronJob im Cluster erreicht git.lab nicht und pusht nach Gitea; dieser Commit bringt die Rotation auf den kanonischen Weg zurueck, bevor der Mirror sie ueberschreiben kann."
|
|
if ! git merge --no-ff -m "$SUBJ" -m "$BODY" "$SHA"; then
|
|
echo "MERGE-KONFLIKT in $ref - es wird nichts gepusht."
|
|
echo "Von Hand aufloesen, siehe CLAUDE.md (Abschnitt Repo Topology)."
|
|
exit 1
|
|
fi
|
|
MERGED=1
|
|
done
|
|
echo "MERGED=$MERGED" > .canonize_state
|
|
- |
|
|
. ./.canonize_state
|
|
if [ "$MERGED" = "0" ]; then
|
|
echo "Keine offene Rotation - nichts zu tun."
|
|
exit 0
|
|
fi
|
|
# Token erst hier pruefen, nicht am Jobanfang: solange nichts zu pushen ist,
|
|
# soll der taegliche Lauf gruen durchgehen und die Gitea-Strecke verifizieren.
|
|
# Fehlt er, wenn es wirklich etwas zu tun gibt, ist Abbruch richtig.
|
|
if [ -z "$CANONIZE_TOKEN" ]; then
|
|
echo "ABBRUCH: Es gibt eine offene Rotation, aber CANONIZE_TOKEN ist nicht gesetzt."
|
|
echo "Siehe Kopf dieser Datei, Einrichtungsschritt 1."
|
|
exit 1
|
|
fi
|
|
# Sicherheitsnetz: die Rotation fasst genau diese Secrets an. Kaeme hier
|
|
# etwas Unverschluesseltes durch, waere das Shared Secret im Klartext in Git.
|
|
for f in apps/production/coturn-secret.yaml apps/production/synapse-turn-secret.yaml; do
|
|
if ! grep -q "ENC\[" "$f"; then
|
|
echo "ABBRUCH: $f ist nicht SOPS-verschluesselt - es wird nichts gepusht."
|
|
exit 1
|
|
fi
|
|
echo "OK: $f ist verschluesselt"
|
|
done
|
|
git push "https://oauth2:${CANONIZE_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" HEAD:main
|
|
echo "Gepusht. Der Mirror traegt es nach Gitea zurueck, der PR schliesst sich dort selbst;"
|
|
echo "der Rotations-Branch existiert dann nur noch auf Gitea und wird vom Mirror entfernt."
|