From 15ccae2b52417d0f8987dbb8f7a616f8ad5747f6 Mon Sep 17 00:00:00 2001 From: cschlaefke Date: Tue, 3 Nov 2026 11:16:13 +0100 Subject: [PATCH] ci(e2e): seed mail templates in dind before supabase start Refs #38 Co-Authored-By: Claude Sonnet 5.5 --- .../scripts/fix-remote-template-mounts.sh | 49 --------------- .forgejo/scripts/remote-templates.sh | 59 +++++++++++++++++++ .forgejo/workflows/ci.yml | 11 ++-- 3 files changed, 66 insertions(+), 53 deletions(-) delete mode 100755 .forgejo/scripts/fix-remote-template-mounts.sh create mode 100755 .forgejo/scripts/remote-templates.sh diff --git a/.forgejo/scripts/fix-remote-template-mounts.sh b/.forgejo/scripts/fix-remote-template-mounts.sh deleted file mode 100755 index 8fe90c3..0000000 --- a/.forgejo/scripts/fix-remote-template-mounts.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash -# Mailvorlagen unter einem entfernten Docker-Daemon (dind) bereitstellen (Issue #38, CI-Lauf 27). -# -# Ursache: Die Supabase CLI bindet supabase/templates/*.html per Bind-Mount (Host-Pfad des Job-Containers) -# in einen ihrer Container ein; GoTrue holt die Vorlage per URL von dort (/email/.html). Im dind -# existiert der Host-Pfad nicht, Docker legt stattdessen ein leeres VERZEICHNIS an, der Webserver liefert -# "Index of /email/confirmation.html/" und GoTrue verschickt diese Seite statt der Vorlage (stiller Fallback, -# der Betreff kommt weiter aus der config.toml). Dieses Skript ersetzt solche Verzeichnisse im dind durch die -# echten Dateien (per Helfer-Container, Inhalt ueber stdin) und startet den betroffenen Container neu. -# Die Auslieferung bleibt eine URL, wie in Staging/Prod geplant (GOTRUE_MAILER_TEMPLATES_*). -# Keine Secrets: es werden nur Container-, Pfad- und Dateinamen ausgegeben. -set -euo pipefail - -PROJECT_ID="${SUPABASE_PROJECT_ID:-shuffle}" -TEMPLATE_DIR="${TEMPLATE_DIR:-supabase/templates}" -fixed=0 - -for c in $(docker ps --format '{{.Names}}' | grep -E "_${PROJECT_ID}\$"); do - while IFS='|' read -r type src dst; do - [ "$type" = bind ] || continue - name=$(basename "$src") - [ -f "$TEMPLATE_DIR/$name" ] || continue - echo "Mount in $c: $src -> $dst" - image=$(docker inspect "$c" --format '{{.Config.Image}}') - # Exit 3 = Quelle ist schon eine Datei (alles in Ordnung) - set +e - docker run --rm -i --user 0 --entrypoint sh -v "$(dirname "$src"):/t" "$image" \ - -c "[ -d '/t/$name' ] || exit 3; rmdir '/t/$name' && cat > '/t/$name'" < "$TEMPLATE_DIR/$name" - rc=$? - set -e - case "$rc" in - 0) echo " $name war ein leeres Verzeichnis, durch Datei ersetzt"; fixed=$((fixed + 1)); restart="${restart:-} $c" ;; - 3) echo " $name ist bereits eine Datei" ;; - *) echo "Fehler beim Ersetzen von $name (Exit $rc)" >&2; exit 1 ;; - esac - done < <(docker inspect "$c" --format '{{range .Mounts}}{{.Type}}|{{.Source}}|{{.Destination}}{{"\n"}}{{end}}') -done - -for c in $(printf '%s\n' ${restart:-} | sort -u); do - echo "Neustart $c" - docker restart "$c" >/dev/null -done -echo "Vorlagen-Mounts korrigiert: $fixed" -if [ "$fixed" -eq 0 ]; then - echo "Hinweis: kein Verzeichnis-Mount ersetzt. Bind-Mounts der Projekt-Container (nur Typ, Quelle, Ziel):" - for c in $(docker ps --format '{{.Names}}' | grep -E "_${PROJECT_ID}\$"); do - docker inspect "$c" --format '{{range .Mounts}}{{if eq .Type "bind"}}'"$c"' {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}{{end}}' - done -fi diff --git a/.forgejo/scripts/remote-templates.sh b/.forgejo/scripts/remote-templates.sh new file mode 100755 index 0000000..5a522b2 --- /dev/null +++ b/.forgejo/scripts/remote-templates.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# Mailvorlagen unter einem entfernten Docker-Daemon (dind) bereitstellen (Issue #38, CI-Laeufe 27/28). +# +# Ursache: Die Supabase CLI bindet supabase/templates/*.html per Bind-Mount mit dem Pfad des Job-Containers +# (z. B. /workspace//Shuffle/supabase/templates/confirmation.html) in den Kong-Container ein +# (-> /home/kong/templates/email/.html); GoTrue holt die Vorlagen per URL von Kong. Im dind existiert +# der Pfad nicht. Docker legt dann ein leeres VERZEICHNIS an, Kong zeigt "Index of /email/confirmation.html/", +# und GoTrue verschickt diese Seite still statt der Vorlage (Spec R5). Ein nachtraegliches Ersetzen hilft nicht: +# das Mount-Ziel im Container-Rootfs ist dann ein Verzeichnis, ein Neustart scheitert (runc). +# +# Deshalb: VOR `supabase start` die Dateien im dind unter genau diesem Pfad anlegen (Helfer-Container, +# Inhalt per stdin), dann entstehen von Anfang an Datei-Mounts. Die Auslieferung bleibt eine URL +# (wie in Staging/Prod: GOTRUE_MAILER_TEMPLATES_*). +# +# remote-templates.sh seed vor `supabase start` +# remote-templates.sh verify nach `start`/`db reset`: Datei-Mounts und Inhalt pruefen, sonst Exit 1 +# Keine Secrets: Ausgabe nur Pfade und Dateinamen. +set -euo pipefail + +PROJECT_ID="${SUPABASE_PROJECT_ID:-shuffle}" +HELPER_IMAGE="${HELPER_IMAGE:-public.ecr.aws/docker/library/busybox:1.37.0}" +SRC_DIR="$(pwd)/supabase/templates" # Pfad, den die CLI als Mount-Quelle verwendet +KONG="supabase_kong_${PROJECT_ID}" + +seed() { + ls "$SRC_DIR"/*.html >/dev/null 2>&1 || { echo "Keine Vorlagen in $SRC_DIR" >&2; exit 1; } + for f in "$SRC_DIR"/*.html; do + name=$(basename "$f") + # Reste frueherer Laeufe (leeres Verzeichnis) werden ersetzt. + docker run --rm -i -v "$SRC_DIR:/t" "$HELPER_IMAGE" \ + sh -c "[ ! -d '/t/$name' ] || rmdir '/t/$name'; cat > '/t/$name'" < "$f" \ + || { echo "Vorlage $name konnte im dind nicht angelegt werden (Image $HELPER_IMAGE, Pfad $SRC_DIR)" >&2; exit 1; } + echo "Vorlage im dind angelegt: $SRC_DIR/$name" + done +} + +verify() { + ok=1 + for f in "$SRC_DIR"/*.html; do + name=$(basename "$f") + if ! docker exec "$KONG" sh -c "[ -f '/home/kong/templates/email/$name' ] && [ -s '/home/kong/templates/email/$name' ]" 2>/dev/null; then + echo "FEHLER: $KONG: /home/kong/templates/email/$name ist keine nicht-leere Datei." >&2 + ok=0 + fi + done + if [ "$ok" -ne 1 ]; then + echo "Bind-Mounts von $KONG (Quelle -> Ziel):" >&2 + docker inspect "$KONG" --format '{{range .Mounts}}{{if eq .Type "bind"}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}{{end}}' >&2 || true + echo "Ohne gueltige Vorlagen verschickt GoTrue still eine Fehlerseite statt der Mail (Spec R5)." >&2 + exit 1 + fi + echo "Mailvorlagen in $KONG vorhanden" +} + +case "${1:-}" in + seed) seed ;; + verify) verify ;; + *) echo "Aufruf: $0 seed|verify" >&2; exit 2 ;; +esac diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index b440379..423c16f 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -236,6 +236,11 @@ jobs: echo "DOCKER_HOST=tcp://${gw}:${DIND_PORT}" >> "$GITHUB_ENV" DOCKER_HOST="tcp://${gw}:${DIND_PORT}" docker version --format 'dind {{.Server.Version}}' + - name: Mailvorlagen im dind anlegen + # Unter dind existiert der Bind-Mount-Pfad der Vorlagen nicht; sie müssen VOR `supabase start` dort liegen, + # sonst entstehen leere Verzeichnis-Mounts und GoTrue verschickt still eine Fehlerseite. Details im Skript. + run: bash .forgejo/scripts/remote-templates.sh seed + - name: Supabase starten (mit Mailpit, ohne Studio u. a.) # Ausgabe nicht ins Log: Die Zusammenfassung von `start` enthält die lokalen Schlüssel (noch nicht maskiert). run: | @@ -249,10 +254,8 @@ jobs: - name: Datenbank zurücksetzen run: npx --yes supabase@${{ env.SUPABASE_CLI_VERSION }} db reset - - name: Mailvorlagen im dind bereitstellen - # Unter dind existiert der Bind-Mount-Pfad der Vorlagen nicht; ohne diesen Schritt liefert die CLI eine leere - # Seite statt supabase/templates/*.html aus (GoTrue verschickt sie still). Details im Skript. - run: bash .forgejo/scripts/fix-remote-template-mounts.sh + - name: Mailvorlagen im dind prüfen + run: bash .forgejo/scripts/remote-templates.sh verify - name: Lokale Schlüssel lesen # Öffentliche Demo-Schlüssel der CLI; trotzdem wird die Maske gesetzt, bevor sie irgendwo ausgegeben werden.