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:
co-authored by
Claude Opus 5
parent
0d9cc03bfd
commit
14cf9318ea
+34
-1
@@ -77,23 +77,56 @@ canonize_rotation:
|
|||||||
# CI_COMMIT_SHA ist der Stand von main beim Anlegen der Pipeline.
|
# CI_COMMIT_SHA ist der Stand von main beim Anlegen der Pipeline.
|
||||||
- git checkout -B main "$CI_COMMIT_SHA"
|
- 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
|
MERGED=0
|
||||||
|
UEBERHOLT=""
|
||||||
for ref in $(git for-each-ref --format='%(refname:short)' 'refs/remotes/gitea/turn-secret-rotation-*'); do
|
for ref in $(git for-each-ref --format='%(refname:short)' 'refs/remotes/gitea/turn-secret-rotation-*'); do
|
||||||
SHA=$(git rev-parse "$ref")
|
SHA=$(git rev-parse "$ref")
|
||||||
if git merge-base --is-ancestor "$SHA" HEAD; then
|
if git merge-base --is-ancestor "$SHA" HEAD; then
|
||||||
echo "bereits kanonisiert: $ref"
|
echo "bereits kanonisiert: $ref"
|
||||||
continue
|
continue
|
||||||
fi
|
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)"
|
echo "kanonisiere: $ref ($SHA)"
|
||||||
SUBJ="chore(coturn): TURN-Rotation aus ${ref#gitea/} uebernommen"
|
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."
|
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
|
if ! git merge --no-ff -m "$SUBJ" -m "$BODY" "$SHA"; then
|
||||||
echo "MERGE-KONFLIKT in $ref - es wird nichts gepusht."
|
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
MERGED=1
|
MERGED=1
|
||||||
done
|
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
|
echo "MERGED=$MERGED" > .canonize_state
|
||||||
- |
|
- |
|
||||||
. ./.canonize_state
|
. ./.canonize_state
|
||||||
|
|||||||
Reference in New Issue
Block a user