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 <noreply@anthropic.com>
This commit is contained in:
Thore Cimbal
2026-08-18 12:00:00 +00:00
co-authored by Claude Opus 5
parent 0d9cc03bfd
commit 14cf9318ea
+34 -1
View File
@@ -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