Files
Proxmox-AIS-Server/docs/gitea-actions.md
T
BartelLuis 9c528c6eca
CI / container-policy (push) Successful in 8s
CI / javascript-check (push) Successful in 18s
CI / python-tests (push) Failing after 4m44s
CI / container-verify (push) Skipped
CI / container-publish (push) Skipped
ci: migrate workflows to Gitea Actions
2026-09-14 20:23:20 +02:00

211 lines
12 KiB
Markdown

# Gitea Actions und Container Registry
Das Projekt liegt auf
[Gitea](https://gitlab.bartelluis.de/BartelLuis/Proxmox-AIS-Server).
Der [Workflow](../.gitea/workflows/ci.yml) prüft Python und JavaScript, baut
das Image und führt den Container-Smoke-Test aus. Bei aktivierter
Veröffentlichung lädt er dasselbe getestete Image in die Gitea Container
Registry. Der Workflow endet beim Image-Push; die Schritte auf dem Zielserver
stehen in der [Deployment-Anleitung](deployment.md).
## Gitea und Runner einrichten
In den Repository-Einstellungen **Actions** aktivieren und unter
**Settings → Actions → Runners** einen registrierten Runner prüfen oder
einrichten. Gitea benötigt einen eigenen Runner-Dienst; ein GitHub-Runner-Label
stellt keine Rechenkapazität bereit.
[Gitea Actions einrichten](https://docs.gitea.com/usage/actions/quickstart/).
Alle Jobs verwenden `vars.AIS_RUNNER_LABEL` oder, wenn die Variable nicht gesetzt
ist, `ubuntu-latest`. Das ausgewählte Label muss einem für dieses Repository
verfügbaren, erreichbaren Linux-amd64-Runner entsprechen. Die Angabe
`ubuntu-latest` wählt ein Runner-Label; sie installiert kein Ubuntu-Image.
Für ein anderes Label in **Settings → Actions → Variables** beispielsweise
`AIS_RUNNER_LABEL=ais-ci` setzen und genau dieses Label am Runner konfigurieren.
Die tatsächliche Job-Umgebung benötigt Git, Bash, OpenSSL, `ssh-keygen`, Python
3.13 mit `venv`, Node.js 24 sowie Docker CLI und Buildx mit Zugriff auf einen
laufenden Docker-Daemon. Die Setup-Actions richten Python 3.13 und Node.js 24
für ihre jeweiligen Jobs ein. Die Umgebung muss außerdem bereits die
JavaScript-Laufzeit zum Ausführen der Actions unterstützen. Bei einem
Container-Runner müssen Werkzeuge und Docker-Zugriff im Job-Container verfügbar
sein, nicht nur auf dem Host. Ein Standard-Node-Image allein enthält nicht die
gesamte Build-Umgebung. Runner-Konfiguration und Label-Zuordnung sind in der
[Runner-Anleitung](https://docs.gitea.com/1.26/usage/actions/act-runner/#labels)
beschrieben.
Der Runner muss Gitea, die Registry, die absoluten Action-URLs im Workflow und
die Downloadquellen für Python, Node.js, Python-Pakete und das Docker-Basisimage
erreichen. Die Actions sind auf vollständige Commit-SHAs festgelegt.
Der Artefakt-Upload verwendet die Gitea-kompatible Action
`https://gitea.com/actions/gitea-upload-artifact`.
Diese Build-Umgebung ist unabhängig vom AIS-Host-Runner für die
Postinstallation auf Proxmox-Hosts. CI-Code mit Docker-Zugriff auf einer dafür
vorgesehenen Build-Maschine ausführen; Änderungen an Workflow und CI-Skripten
vor der Übernahme prüfen.
## Registry und Veröffentlichung einrichten
Ohne `PUBLISH_IMAGES=true` führen alle Refs ausschließlich Prüfungen durch.
In **Settings → Actions → Variables** folgende Repository-Variablen setzen:
| Variable | Wert und Bedeutung |
| --- | --- |
| `AIS_RUNNER_LABEL` | Optional: Label eines verfügbaren Runners; Standard `ubuntu-latest` |
| `REGISTRY_HOST` | Optional: Registry-Host ohne Schema oder Pfad; Standard `gitlab.bartelluis.de` |
| `REGISTRY_USERNAME` | Gitea-Benutzername des Token-Inhabers; für Veröffentlichung erforderlich |
| `PUBLISH_IMAGES` | Genau `true`, nachdem Registry-Zugang und Schutzregeln eingerichtet sind |
Im Gitea-Benutzerkonto einen Personal Access Token mit Paket-Schreibrecht
(`write:package`, in der Oberfläche **package: Read & Write**) erstellen.
Den Wert unter **Settings → Actions → Secrets** als `REGISTRY_TOKEN` speichern.
Das zugehörige Konto muss beim Paketinhaber `BartelLuis` Schreibzugriff besitzen.
Das kurzlebige `GITEA_TOKEN` des Jobs unterstützt die Paketveröffentlichung
nicht; es ersetzt dieses Secret nicht.
[Gitea-Secrets](https://docs.gitea.com/usage/actions/secrets/),
[Paketberechtigungen](https://docs.gitea.com/usage/packages/overview/#access-restrictions),
[Gitea-Paketautorisierung](https://docs.gitea.com/usage/actions/comparison/#package-repository-authorization).
Der Imagepfad ist `<REGISTRY_HOST>/<kleingeschriebener Repositoryname>`, hier
`gitlab.bartelluis.de/bartelluis/proxmox-ais-server`. Bei einem Fork oder einer
Umbenennung ändert sich der Pfad. Pakete gehören in Gitea einem Benutzer oder
einer Organisation. Nach dem ersten Push kann das Paket in seinen Einstellungen
mit dem Repository verknüpft werden, damit es auch in dessen Paketliste erscheint.
[Gitea Container Registry](https://docs.gitea.com/usage/packages/container/).
## Standardbranch und Release-Tags schützen
Vor `PUBLISH_IMAGES=true` in den Gitea-Repository-Einstellungen den
Standardbranch `main` und die Release-Tags schützen. Für `main` direkte Pushes
deaktivieren, Reviews und erfolgreiche Statuschecks verlangen sowie Force-Push
und Löschen einschränken.
Für `v*` die Erstellung, Änderung und Löschung auf Release-Verantwortliche
begrenzen. Release-Tags auf einen geprüften Commit mit passender Projektversion
setzen. Die Schutzregeln werden durch den Workflow-Commit nicht angelegt.
[Geschützte Branches](https://docs.gitea.com/usage/access-control/protected-branches/),
[Geschützte Tags](https://docs.gitea.com/usage/access-control/protected-tags/).
Nach dem ersten Pull-Request-Lauf die tatsächlich gemeldeten Statuskontexte
für `python-tests`, `javascript-check`, `container-policy` und `container-verify`
als verpflichtend auswählen. `container-publish` wird bei Pull Requests übersprungen und ist
deshalb keine Pflichtprüfung.
Die CI entscheidet anhand von `PUBLISH_IMAGES`, Ereignis und Ref. Sie fragt
keinen Schutzstatus ab: Giteas kompatibler `ref_protected`-Wert ist dafür nicht
verwendbar. Die Gitea-Schutzregeln und restriktive Schreibrechte bleiben daher
ein eigener Einrichtungsschritt.
## Auslöser und Image-Tags
Der Workflow läuft bei Branch- und Tag-Pushes, bei Pull Requests sowie bei
manuellem Start über `workflow_dispatch`.
| Ref und Ereignis | Container-Job | Veröffentlichung |
| --- | --- | --- |
| `PUBLISH_IMAGES` fehlt oder ist nicht `true` | `container-verify` | Keine |
| Pull Request, Feature-Branch oder sonstiger Tag | `container-verify` | Keine |
| Standardbranch, Push oder manueller Start, Veröffentlichung aktiviert | `container-publish` | `sha-<vollständiger Commit-SHA>` und `edge` |
| Tag `vX.Y.Z`, Push oder manueller Start, Veröffentlichung aktiviert | `container-publish` | `sha-<vollständiger Commit-SHA>` und `X.Y.Z` |
Release-Tags müssen vollständig dem Muster
`v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)` entsprechen. Führende
Nullen, Vorabversionen und Build-Zusätze veröffentlichen kein Image.
Bei einem zur Veröffentlichung ausgewählten Release muss die Version außerdem
exakt `[project].version` in [pyproject.toml](../pyproject.toml) entsprechen;
eine Abweichung bricht den Publish-Job ab.
`edge` ist ein beweglicher Tag. Ein erneuter Lauf eines älteren Commits kann
ihn zurücksetzen. SHA-Tags enthalten alle 40 Zeichen des Commits; externe
Build-Abhängigkeiten können bei erneuten Builds zu einem anderen Digest führen.
Es gibt keinen `latest`-Tag. Im Betrieb den Digest aus `deploy.env` verwenden
und bisherige Registry-Versionen für Updates und Rollback aufbewahren.
## Jobs und Artefakte
`python-tests` führt über [ci/python-tests.sh](../ci/python-tests.sh) Pytest in
einer temporären virtuellen Umgebung aus. `javascript-check` prüft mit
`node --check provisioner/static/app.js` die JavaScript-Syntax.
`container-policy` wählt den Container-Job aus. Nach erfolgreichen
Quellcodeprüfungen läuft genau einer der Jobs `container-verify` und
`container-publish`. Beide verwenden [ci/container.sh](../ci/container.sh);
das Skript prüft vor einer Veröffentlichung erneut Ereignis, Ref und Opt-in.
Der [Container-Smoke-Test](../tests/container_smoke.py) prüft das gebaute
`linux/amd64`-Image auf TLS, Anmeldung, CSRF, Webdateien und Datenerhalt über
einen Dienstneustart. Er läuft als UID 10001 mit schreibgeschütztem Dateisystem,
entfernten Linux-Capabilities und temporären Testdaten. Eine Proxmox-Installation
ist kein Bestandteil dieses Tests. Der Publish-Job lädt das getestete Image
ohne zweiten Build hoch. OCI-Labels enthalten Quellrepository, Commit und
Anwendungsversion; Provenance- und SBOM-Attestierungen werden nicht erzeugt.
| Artefakt im Gitea-Lauf | Inhalt | Angefragte Aufbewahrung |
| --- | --- | --- |
| `python-test-results` | `reports/pytest.xml`, auch bei fehlgeschlagenen Tests, sofern erzeugt | 7 Tage |
| `container-build` | `build.env` nach erfolgreicher Verifikation | 7 Tage |
| `container-deploy` | `build.env` und `deploy.env` nach erfolgreicher Veröffentlichung | 30 Tage |
Die tatsächliche Aufbewahrung unterliegt der Gitea-Instanzkonfiguration.
Unter **Actions** den erfolgreichen Lauf öffnen und das gewünschte Artefakt
herunterladen. `build.env` enthält den temporären lokalen Image-Tag, Commit
und Anwendungsversion. Der lokale `ci-…`-Tag wird nicht veröffentlicht und am
Jobende entfernt. `deploy.env` enthält ausschließlich
`PROVISIONER_IMAGE=gitlab.bartelluis.de/bartelluis/proxmox-ais-server@sha256:…`
beziehungsweise die konfigurierte Registry-Adresse. Beide Dateien enthalten
keine Zugangsdaten. Die Image-Zeile in `.env` auf dem Zielserver übernehmen.
## Erster Lauf und Release
Nach dem Push unter **Actions** prüfen, dass der Lauf einen Runner erhält und
Python-, JavaScript- und Containerprüfungen erfolgreich sind. Nach aktivierter
Veröffentlichung muss ein Standardbranch-Lauf außerdem die Image-Tags
`sha-<Commit>` und `edge` sowie `container-deploy` mit `deploy.env` liefern.
Lokale Tests ersetzen diesen Lauf mit Registry-Anmeldung und Push nicht.
Für ein Release zuerst `[project].version` ändern und den geprüften Commit
übernehmen. Anschließend mit einem berechtigten Konto den passenden Tag
erstellen und an den Gitea-Remote pushen. Im vorhandenen Checkout heißt er
`origin`; vor dem Push mit `git remote -v` prüfen. Für Projektversion `0.1.0`,
sofern der Tag noch nicht existiert:
```bash
git tag -a v0.1.0 -m "Release 0.1.0"
git push origin v0.1.0
```
Der Release-Lauf muss den Image-Tag `0.1.0` erzeugen. Für einen manuellen Lauf
unter **Actions** den Workflow und den gewünschten Ref auswählen. Auch dabei
gelten Opt-in, Standardbranch- beziehungsweise Tag-Regel und Versionsabgleich.
Branch-Push und Pull Request können für denselben Quellstand getrennte Läufe
erzeugen. Pull Requests veröffentlichen keine Images.
## Fehlersuche und Deployment
Bei **Waiting** beziehungsweise **no matching online runner** das angeforderte
Label mit den erreichbaren Runnern unter **Settings → Actions → Runners**
vergleichen. Der bisherige Workflow verlangte `ubuntu-24.04`; dafür war kein
passender Online-Runner verfügbar. `AIS_RUNNER_LABEL` auf ein tatsächlich
vorhandenes Label setzen oder einen geeigneten Runner registrieren und starten.
Ein Label-Wechsel allein ersetzt keine fehlende Runner-Installation.
Bei fehlendem Docker-Zugriff `docker info` und `docker buildx version` in der
Job-Umgebung prüfen. Bei DNS-, Checkout- oder Artefaktfehlern müssen Giteas
öffentliche `ROOT_URL`, die Checkout-Adresse und die vom Runner erreichbare
Adresse zusammenpassen. Das Projekt verwendet `gitlab.bartelluis.de`; eine
von der Instanz zurückgegebene abweichende Adresse wie `git.bartelluis.de` muss
ebenfalls auflösbar und erreichbar sein oder in der Gitea-Konfiguration
korrigiert werden.
Bei übersprungenem Publish-Job `PUBLISH_IMAGES`, Ereignis, Standardbranch und
Tagformat prüfen. Bei `denied` oder `unauthorized` Registry-Host, Benutzername,
`REGISTRY_TOKEN`, dessen `write:package`-Scope und die Rechte am Paketinhaber
kontrollieren. Bei Versionsfehlern Git-Tag und `pyproject.toml` abgleichen.
Fehlt `container-deploy`, die Build-, Smoke-, Push- und Upload-Logs prüfen.
Zum Deployment [compose.yaml](../compose.yaml) und
[config/deployment.env.example](../config/deployment.env.example) auf den
Zielserver kopieren. Die [Deployment-Anleitung](deployment.md) beschreibt
Registry-Anmeldung, Erstinitialisierung, HTTPS-Prüfung, Updates und Rollback.
Für private Pakete benötigt das Deploymentkonto einen eigenen Token mit
`read:package`; öffentliche Pakete lassen sich anonym laden.