From 14cf9318ea8650d3b63e724a50388ea696967a64 Mon Sep 17 00:00:00 2001 From: Thore Cimbal Date: Tue, 18 Aug 2026 12:00:00 +0000 Subject: [PATCH] ci(canonize): skip superseded rotation branches instead of conflicting forever The daily canonize_rotation job had been red for nine days. Cause: the branch turn-secret-rotation-20260728-192656 was merged on Gitea back in July but never deleted, so the job kept trying to merge it into a main that had moved on. Its merge base is ancient, so the merge conflicts in ten files - not only docs but coturn-secret.yaml, synapse-turn-secret.yaml and element-server-suite.yaml. That made the failure worse than noise. The job's own advice is "resolve by hand", and a careless resolution there rolls the TURN shared secret back to the July value; Synapse and coturn would then disagree and TURN would be dead. main already carries a newer rotation (2026-08-01 against 2026-07-28), so there was never anything to gain from the merge. The job now reads the SOPS lastmodified stamp - metadata, not a secret - from both sides and skips a branch whose rotation is not newer than main's, naming it as cleanup. It stays green while doing so, deliberately: AGENTS.md makes this red pipeline the only alarm channel for the Gitea exception, and a pipeline that is red every day for housekeeping is not an alarm any more. A genuine conflict still fails, now with an explicit warning never to take the older secret. Verified both directions against the real repository state, not just the happy path: the leftover branch is detected as superseded, and with the roles swapped a real rotation is still recognised as needing canonization. Co-Authored-By: Claude Opus 5 --- .gitlab-ci.yml | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9fa65eb..82f314b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -77,23 +77,56 @@ canonize_rotation: # CI_COMMIT_SHA ist der Stand von main beim Anlegen der Pipeline. - git checkout -B main "$CI_COMMIT_SHA" - | + # Zeitpunkt der Rotation aus dem SOPS-Metadatenblock lesen. 'lastmodified' + # ist Metadatum, kein Geheimnis - es steht im Klartext neben den ENC[]-Werten. + rotationszeit() { + git show "$1:apps/production/coturn-secret.yaml" 2>/dev/null \ + | sed -n 's/^[[:space:]]*lastmodified:[[:space:]]*"\(.*\)".*/\1/p' | head -1 + } MERGED=0 + UEBERHOLT="" 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 + # Ueberholte Zweige NICHT mergen. Ein Zweig, dessen Rotation aelter ist als + # der Stand in main, bringt nichts Neues, konfliktiert aber mit allem, was + # seither passiert ist - inklusive coturn-secret.yaml und + # synapse-turn-secret.yaml. Eine unbedachte Hand-Aufloesung wuerde das + # TURN-Shared-Secret ZURUECKDREHEN; Synapse und coturn waeren dann uneins + # und TURN tot. Real passiert: der Zweig vom 2026-07-28 blieb nach dem Merge + # auf Gitea liegen und hat diesen Job neun Tage lang taeglich rot gefaerbt - + # womit die rote Pipeline als Alarm wertlos wurde (AGENTS.md: sie IST der + # einzige Meldeweg). Deshalb ist ein Ueberbleibsel hier Aufraeumarbeit und + # kein Vorfall: gemeldet ja, rot nein. + NEU=$(rotationszeit "$SHA"); IST=$(rotationszeit HEAD) + if [ -n "$NEU" ] && [ -n "$IST" ] \ + && [ "$(printf '%s\n%s\n' "$NEU" "$IST" | sort | head -1)" = "$NEU" ]; then + echo "ueberholt: $ref traegt die Rotation vom $NEU, main steht auf $IST." + UEBERHOLT="$UEBERHOLT ${ref#gitea/}" + 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)." + echo "⚠️ Beim Aufloesen NIEMALS die aeltere Fassung von coturn-secret.yaml oder" + echo " synapse-turn-secret.yaml uebernehmen: beide muessen dasselbe Shared" + echo " Secret tragen, sonst faellt TURN aus. Im Zweifel main behalten." + echo "Siehe CLAUDE.md (Abschnitt Repo Topology)." exit 1 fi MERGED=1 done + if [ -n "$UEBERHOLT" ]; then + echo + echo "AUFRAEUMEN: diese Zweige sind ueberholt und koennen auf Gitea geloescht werden:" + for b in $UEBERHOLT; do echo " - $b"; done + echo "(Der Job bleibt gruen - liegengebliebene Zweige sind kein Vorfall.)" + fi echo "MERGED=$MERGED" > .canonize_state - | . ./.canonize_state