Files
FireAdministration/.gitea/workflows/pruefung.yml
T
Florian WildeandClaude Opus 5 9156dcc144
Pruefung / pruefung (pull_request) Canceled after 0s
Pruefung / oberflaeche (pull_request) Canceled after 0s
Phase 11: Freigabereife
Kein Modul, sondern die drei Software-Voraussetzungen fuer 1.0.0:
Auskunft nach Art. 15 DSGVO, ein geprueftes Sicherungskonzept und eine
Pipeline.

Das Auskunftsrecht war ein Versprechen ohne Umsetzung: `person.export`
stand seit Phase 0 im Katalog und war dem Kommandanten zugewiesen,
implementiert war nichts. Ohne Auskunftsseite ist ein Loeschkonzept nicht
abnehmbar. Jetzt sammelt FLORIAN dreizehn Abschnitte ueber eine Person,
mit dem Zweck ueber jedem - Art. 15 verlangt nicht nur die Daten, sondern
auch Zwecke und Rechte, und eine blosse Liste erfuellt die Pflicht nicht.
Ein Durchgang liefert Anzeige, PDF und JSON nach Art. 20.

Die Trennlinie ist "ueber mich" gegen "von mir": was ueber die Person
gespeichert ist, steht vollstaendig drin, auch das Unangenehme. Was sie
getan hat, steht als Zahl drin - die Pruefprotokolle gehoeren zum
Nachweisbestand der Wehr, und vollstaendig ausgeliefert kaeme jeder ueber
eine Selbstauskunft an die Geraeteakten.

Die Rueckspielprobe hat sich sofort bezahlt gemacht: der erste Versuch
lief sauber durch und hatte dabei saemtliche Unveraenderlichkeitsgarantien
der Datenbank entfernt. Die Vorgabeprivilegierung aus dem Init-Skript gibt
jeder von pg_restore neu angelegten Tabelle wieder alle Rechte, und GRANT
kann nur hinzufuegen. Die Anwendungsrolle durfte danach das Audit-Log
aendern, Wiki-Fassungen loeschen, Kiosk-Vorgaenge umschreiben - und nichts
haette darauf hingewiesen. Gefunden haben es vier Datenbanktests
unmittelbar nach der Probe, also genau die Probe, wegen der 1.0.0 sie
verlangt.

Die Pipeline ist geschrieben, aber NICHT erprobt: in Gitea ist kein
act_runner registriert. Das steht so im README und im Devlog, damit sich
niemand auf eine Pruefung verlaesst, die nicht stattfindet.

601 Unit-Tests gruen; Sicherung und Wiederherstellung einmal vollstaendig
durchgefuehrt und die Tests danach erneut gruen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-05 17:16:08 +02:00

185 lines
6.4 KiB
YAML

# =============================================================================
# Die Pruefung bei jedem Push.
#
# Bis Phase 10 gab es 581 Unit- und 266 E2E-Tests — und nichts, was sie
# ausfuehrte ausser einem Menschen, der daran dachte. In der Sitzung, in der
# die Kassenverwaltung entstand, haben die Tests vier echte Fehler gefunden,
# zwei davon in Code, der eine Stunde alt war. Genau das soll hier von allein
# passieren.
#
# Zwei Auftraege, bewusst getrennt:
#
# pruefung typecheck, lint und die Unit-Tests. Braucht eine Datenbank,
# weil ein Teil der Tests die Trigger und RLS gegen echtes
# Postgres prueft — mit einer Attrappe waeren sie wertlos.
#
# oberflaeche die E2E-Tests. Dauern eine Dreiviertelstunde und brauchen den
# halben Stack, deshalb laufen sie nur auf main und in Pull
# Requests, nicht bei jedem Zwischenstand auf einem Zweig.
# =============================================================================
name: Pruefung
on:
push:
branches: [main]
pull_request:
env:
# Dieselben Werte wie in .env.example. Es sind Testdaten in einem
# Wegwerf-Container; echte Geheimnisse haben in einer Pipeline nichts zu
# suchen und stehen im Betrieb in der .env.
POSTGRES_USER: florian
POSTGRES_PASSWORD: pruefung
POSTGRES_DB: florian
POSTGRES_APP_PASSWORD: pruefung_app
DATABASE_URL: postgresql://florian_app:pruefung_app@localhost:5432/florian?schema=public
DIRECT_DATABASE_URL: postgresql://florian:pruefung@localhost:5432/florian?schema=public
AUTH_SECRET: nur-fuer-die-pruefung-nicht-fuer-den-betrieb
AUTH_TRUST_HOST: "true"
APP_URL: http://localhost:3100
S3_ENDPOINT: localhost
S3_PORT: "9000"
S3_USE_SSL: "false"
S3_ACCESS_KEY: florian
S3_SECRET_KEY: pruefung_minio
S3_BUCKET: florian
REDIS_URL: redis://localhost:6379
TZ: Europe/Berlin
jobs:
pruefung:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
# Das eigene Postgres-Image statt eines fertigen: FLORIAN braucht
# PostGIS **und** pgvector, und kein oeffentliches Image bringt beides
# mit. Ein Dienst-Container mit postgres:17 wuerde die Migrationen
# durchlassen und erst bei der ersten Umkreissuche scheitern.
- name: Datenbank bauen und starten
run: |
docker build -t florian-postgres:pruefung ./docker/postgres
docker run -d --name postgres -p 5432:5432 \
-e POSTGRES_USER=$POSTGRES_USER \
-e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
-e POSTGRES_DB=$POSTGRES_DB \
-e POSTGRES_APP_PASSWORD=$POSTGRES_APP_PASSWORD \
-e POSTGRES_INITDB_ARGS="--locale-provider=icu --icu-locale=de-DE --locale=C.UTF-8 --encoding=UTF8" \
-v "$(pwd)/docker/postgres:/docker-entrypoint-initdb.d:ro" \
florian-postgres:pruefung
- name: Redis und MinIO starten
run: |
docker run -d --name redis -p 6379:6379 redis:7-alpine
docker run -d --name minio -p 9000:9000 \
-e MINIO_ROOT_USER=$S3_ACCESS_KEY \
-e MINIO_ROOT_PASSWORD=$S3_SECRET_KEY \
minio/minio:latest server /data
- run: npm ci
- name: Auf die Datenbank warten
run: |
for i in $(seq 1 60); do
docker exec postgres pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" && exit 0
sleep 2
done
echo "Postgres kam nicht hoch:"
docker logs postgres
exit 1
- run: npx prisma generate
- run: npm run typecheck
- run: npm run lint
- name: Migrationen einspielen
run: npm run db:migrate
# Der Seed gehoert dazu: er ist selbst ein Test. Faellt eine Migration
# oder ein Standardwert um, merkt man es hier und nicht erst, wenn eine
# Wehr ihn zum ersten Mal ausfuehrt.
- name: Beispielbestand anlegen
run: npm run db:seed
- run: npm run test
- name: Aufraeumen
if: always()
run: docker rm -f postgres redis minio || true
oberflaeche:
runs-on: ubuntu-latest
# Nur wo es sich lohnt: ein voller Lauf dauert etwa 45 Minuten.
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Dienste starten
run: |
docker build -t florian-postgres:pruefung ./docker/postgres
docker run -d --name postgres -p 5432:5432 \
-e POSTGRES_USER=$POSTGRES_USER \
-e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
-e POSTGRES_DB=$POSTGRES_DB \
-e POSTGRES_APP_PASSWORD=$POSTGRES_APP_PASSWORD \
-e POSTGRES_INITDB_ARGS="--locale-provider=icu --icu-locale=de-DE --locale=C.UTF-8 --encoding=UTF8" \
-v "$(pwd)/docker/postgres:/docker-entrypoint-initdb.d:ro" \
florian-postgres:pruefung
docker run -d --name redis -p 6379:6379 redis:7-alpine
docker run -d --name minio -p 9000:9000 \
-e MINIO_ROOT_USER=$S3_ACCESS_KEY \
-e MINIO_ROOT_PASSWORD=$S3_SECRET_KEY \
minio/minio:latest server /data
docker run -d --name gotenberg -p 3001:3000 gotenberg/gotenberg:8
- run: npm ci
- run: npx playwright install --with-deps chromium
- name: Auf die Datenbank warten
run: |
for i in $(seq 1 60); do
docker exec postgres pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" && exit 0
sleep 2
done
docker logs postgres
exit 1
- run: npx prisma generate
- run: npm run db:migrate
# Die E2E-Tests laufen seit Phase 8 gegen eine eigene Wehr, nicht gegen
# den Beispielbestand. Das Skript legt beide an.
- name: Testwehr anlegen
run: npm run db:test-reset
- run: npm run build
- run: npx playwright test
env:
GOTENBERG_URL: http://localhost:3001
- name: Fehlerbilder sichern
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-bericht
path: |
playwright-report/
test-results/
retention-days: 7
- name: Aufraeumen
if: always()
run: docker rm -f postgres redis minio gotenberg || true