# 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 `/`, 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-` und `edge` | | Tag `vX.Y.Z`, Push oder manueller Start, Veröffentlichung aktiviert | `container-publish` | `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-` 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.