# Tessera CI/CD Setup Runbook fuer die Einrichtung der Gitea-basierten CI/CD-Pipeline. ## Voraussetzungen - Docker und Docker Compose installiert - Gitea-Instanz mit aktivierten Actions - Zugriff auf die Gitea-Administrationsoberflaeche ## 1. Gitea-Repository einrichten 1. In Gitea ein neues Repository erstellen (z.B. `tessera-ctl`) 2. Das Repository als Git-Remote hinzufuegen: ```bash git remote add origin https:////tessera-ctl.git ``` 3. In den Repository-Einstellungen unter **Settings > Actions** sicherstellen, dass Actions aktiviert ist. ## 2. act_runner registrieren Der act_runner fuehrt Gitea Actions Workflow-Jobs in Docker-Containern aus. ### Runner-Token generieren 1. In Gitea navigieren zu: **Repository > Settings > Actions > Runners** (oder Admin-Panel > Actions > Runners fuer globale Runner) 2. **Create registration token** klicken 3. Token kopieren ### Runner starten Die Umgebungsvariablen setzen (z.B. in `.env` im Projektverzeichnis oder direkt in der Shell): ```bash export GITEA_INSTANCE_URL=https://git.vicolab.de export GITEA_RUNNER_REGISTRATION_TOKEN= ``` Runner starten: ```bash docker compose -f docker-compose.ci.yml up -d ``` Runner-Status pruefen: ```bash docker compose -f docker-compose.ci.yml logs act_runner ``` Der Runner registriert sich automatisch bei Gitea und ist bereit, Jobs auszufuehren. ### Bestehender Runner Wenn bereits ein act_runner als separater Docker-Container laeuft (z.B. `gitea-runner`), kann `docker-compose.ci.yml` als Dokumentation und Vorlage fuer eine Neueinrichtung verwendet werden. Der bestehende Runner muss nicht ersetzt werden. Bestehenden Runner pruefen: ```bash docker ps --filter name=gitea-runner ``` ## 3. Erforderliche Konfiguration ### Umgebungsvariablen | Variable | Beschreibung | Wo setzen | |----------|-------------|-----------| | `GITEA_INSTANCE_URL` | URL der Gitea-Instanz | `.env` oder Systemumgebung | | `GITEA_RUNNER_REGISTRATION_TOKEN` | Runner-Registrierungstoken | `.env` oder Systemumgebung | ### Gitea Secrets (fuer die CI-Pipeline) In Gitea unter **Repository > Settings > Actions > Secrets** werden die Secrets fuer die Pipeline konfiguriert. Benoetigt wird genau eines: | Secret | Beschreibung | |--------|--------------| | `REGISTRY_TOKEN` | Gitea-Zugangstoken (Access Token) mit Schreibrecht auf Pakete (`package: write`). Wird im Job `publish` fuer `docker login localhost:3002 --password-stdin` verwendet. | Das Token erscheint nie im Log: es wird per `--password-stdin` uebergeben und Gitea maskiert Secret-Werte in der Job-Ausgabe. Das Veroeffentlichungs-Skript `.gitea/scripts/publish-images.sh` kennt das Token nicht; der Login bleibt im Workflow. Der Push geht ueber `localhost:3002` (Gitea laeuft auf demselben Rechner wie der Runner), weil der Nginx Proxy Manager vor `git.vicolab.de` grosse Image-Blobs blockt. Das Pullen auf den Servern laeuft ueber `git.vicolab.de` (`docker-compose.prod.yml`). Weitere Secrets bei Bedarf: 1. In Gitea **Settings > Actions > Secrets** den Secret anlegen 2. In `.gitea/workflows/ci.yml` ueber `${{ secrets.SECRET_NAME }}` referenzieren **Wichtig:** Secrets niemals in Logs ausgeben oder in Workflow-Dateien hardcoden. ## 4. Pipeline-Ueberblick Die CI/CD-Pipeline (`.gitea/workflows/ci.yml`) laeuft bei jedem Push auf die Zweige `main` und `live` sowie bei jedem Tag `v*` (z. B. `v1.0.0`) und besteht aus drei aufeinander aufbauenden Jobs: 1. **quality** -- Lint und TypeScript Type-Check (Lint ist derzeit ein Leerlauf, siehe WINDOWS #35; der Type-Check ist echt) 2. **test** -- Vitest Unit- und Integrationstests 3. **publish** -- Docker Images mit Versionsstempel bauen und in die Gitea-Registry veroeffentlichen Ablauf: `quality` -> `test` -> `publish` (jeder Job nur bei Erfolg des vorherigen). Der Job `publish` besteht aus drei Schritten: `actions/checkout@v4` mit `fetch-depth: 0` (volle Historie samt Tags, sonst liefert `git describe` nichts), Login in die Registry (siehe Abschnitt 3) und der Aufruf von `.gitea/scripts/publish-images.sh`. ### Zwei Kanaele: Etiketten je Anlass Das Skript `.gitea/scripts/publish-images.sh` entscheidet allein anhand `GITHUB_REF`, ob und unter welchen Etiketten veroeffentlicht wird: | Anlass | Kanal (`APP_CHANNEL`) | Etiketten in der Registry | |--------|----------------------|---------------------------| | Push auf `main` | `beta` | `beta` und `latest` (`latest` ist nur ein Alias fuer `beta` und entfaellt spaeter) | | Tag `vX.Y.Z` | `live` | `live` und `vX.Y.Z` | | Push auf `live` ohne Tag | -- | keine; der Lauf prueft nur (`quality`, `test`), das Skript endet mit "nichts zu tun" | Das Kanalmodell fuer den Betrieb (welcher Server welches Etikett zieht, Freigabe, Hotfix) steht in `docs/anleitung-betrieb.md`, Kapitel 9. ### Versionsstempel Das Skript berechnet vier Werte und gibt sie als `--build-arg` an beide Dockerfiles (`apps/web/Dockerfile`, `apps/api/Dockerfile`): | Build-Arg | Quelle | |-----------|--------| | `APP_VERSION` | `git describe --tags --always` (ohne Tag: kurzer Commit-SHA) | | `APP_CHANNEL` | `beta` oder `live`, siehe Tabelle oben | | `APP_COMMIT` | `git rev-parse --short HEAD` | | `APP_BUILD_TIME` | `date -u`, ISO-Format | Die API liest die Werte zur Laufzeit (`GET /health/version`, Startzeile im Log). Das Web-Image bettet `NEXT_PUBLIC_APP_*` beim Build in das Browser-Bundle ein -- deshalb laeuft die `builder`-Stufe des Web-Images jetzt bei jedem Pipeline-Lauf neu, die Laufzeit liegt eher bei 4-6 statt 2 Minuten. Lokale Probe ohne Docker-Aufruf: ```bash GITHUB_REF=refs/tags/v1.2.3 sh .gitea/scripts/publish-images.sh --print-plan ``` Hinweis: Die fruehere Entscheidung D-13 (Images lokal bauen, keine Registry) ist ueberholt -- seit der Einfuehrung der Gitea-Registry werden Images gepusht und von den Servern per `docker compose pull` geholt. ## 5. Sicherheitshinweise ### Docker Socket Der act_runner mountet den Host-Docker-Socket (`/var/run/docker.sock`), um Jobs in Docker-Containern ausfuehren zu koennen. Das bedeutet: - Der Runner hat Zugriff auf den Docker-Daemon des Hosts - Er kann Container starten, stoppen und inspizieren **Risikobewertung:** Akzeptabel fuer interne CI, da: - Nur Claude pusht manuell bei Meilensteinen (D-11) - Kein externer Code wird ausgefuehrt - Ephemeral Mode ist aktiviert (siehe unten) ### Ephemeral Runner `GITEA_RUNNER_EPHEMERAL=1` sorgt dafuer, dass der Runner seine Credentials nach jedem Job widerruft und sich neu registriert. Das verhindert: - Persistente Zugriffstokens im Runner-Container - Kompromittierung ueber alte Job-Artefakte - Seitliche Bewegung zwischen Jobs ### Workflow-Dateien Workflow-Dateien in `.gitea/workflows/` werden direkt aus dem Repository geladen. Da nur vertrauenswuerdiger Code gepusht wird (D-11, Claude als einziger Committer), ist das Risiko einer manipulierten Pipeline minimal. Ein Tag-Push `v*` ist der Freigabe-Hebel fuer Live: wer ihn setzen darf, kann das `live`-Etikett neu belegen. Heute hat nur das Konto `schalli` Schreibrecht (0 Kollaborateure, keine Branch-Regeln). Kommen weitere Konten dazu, in Gitea unter **Repository > Settings > Branches / Tags** eine Tag-Schutzregel fuer `v*` und einen Branch-Schutz fuer `live` anlegen (T-KU1-04). ## 6. Fehlerbehebung ### Runner registriert sich nicht 1. Pruefen ob `GITEA_INSTANCE_URL` korrekt und erreichbar ist 2. Token ggf. neu generieren (Token sind einmalig verwendbar bei Ephemeral Mode) 3. Runner-Logs pruefen: `docker compose -f docker-compose.ci.yml logs act_runner` ### Pipeline startet nicht 1. In Gitea pruefen ob Actions fuer das Repository aktiviert ist 2. Pruefen ob der Runner als "online" angezeigt wird (Gitea > Actions > Runners) 3. Sicherstellen dass die Workflow-Datei unter `.gitea/workflows/` liegt 4. YAML-Syntax validieren ### Docker-Build schlaegt fehl 1. Sicherstellen dass `docker-compose.yml` im Arbeitsverzeichnis des Runners erreichbar ist 2. Docker Daemon Status pruefen: `docker info` 3. Disk Space pruefen: `df -h` ### Stempel zeigt `dev` oder nur eine Kurzkennung statt des Tags 1. Im Job `publish` pruefen, dass `actions/checkout@v4` mit `fetch-depth: 0` auscheckt -- ohne Tags liefert `git describe --tags --always` nur den SHA 2. Pruefen, ob der Tag wirklich gepusht wurde: `git ls-remote --tags origin` 3. `dev` bedeutet: das Image wurde ohne Build-Args gebaut (lokal statt ueber das Skript) -- das ist fuer lokale Builds normal