--- type: types/entity.md entity_type: technology tags: [ci-cd, workflows, automation, gitea] created: 2026-07-25 modified: 2026-09-01 related: [Gitea, Act Runner, Docker, Gitea MCP Server, Ambient Environment Dependency, CI Integration] sources: [Source - Conversation - Versioning CI-CD and Content Migration Session 2026-08-30, Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31, Source - Conversation - Hardening the Test Suite Against Silent Environment Dependencies Session 2026-08-31, Source - Conversation - Nightly Drift-Check Workflow and doctor's Bootstrap Gap Session 2026-08-31] confidence: 0.90 confidence_base: 0.90 provenance: sourced summary: CI/CD-Workflow-Plattform, in Gitea integriert; fuehrt YAML-Workflows ueber den Act Runner aus, samt Release-Pipeline, belegten paths-ignore-Filtern und einem nightly.yml-Drift-Check, dessen schedule-Ausloesung seit 2026-09-01 (Run 90) belegt ist --- # Gitea Actions **Typ:** Technology (CI/CD Platform) ## Beschreibung Gitea Actions ist das CI/CD-Workflow-Automatisierungssystem, das in Gitea integriert ist. Es ermöglicht die Definition von Build-, Test- und Deployment-Pipelines als Code in YAML-Workflow-Dateien. Die Workflows werden vom [[Act Runner]] ausgeführt. ## Kerndaten - **Typ:** CI/CD-Workflow-Automatisierung - **Status:** Aktiv (Stand 2026-07-12) - **Runner:** [[Act Runner]] - **Workflow-Syntax:** GitHub Actions kompatibles YAML ## Architektur ### Workflow-Ausführung 1. **Auslöser:** Push, PR, Zeitplan oder manuelle Auslösung 2. **Runner-Auswahl:** Basierend auf Routing-Labels (`linux-docker`, `container-builder`, `k3s-deploy`) 3. **Job-Container:** Isoliertes Bridge-Netz pro Job 4. **Secret-Injektion:** Runtime-Abruf aus 1Password 5. **Cache:** Built-in Actions Cache Server auf Port 8088 ### Schlüsselkomponenten - **Runner:** `act_runner`-Docker-Container im Host-Network-Modus - **Cache Server:** Built-in, zugänglich via statische IP-Konfiguration - **Job-Container:** Kurzlebige Docker-Container pro Workflow-Job - **Actions:** Wiederverwendbare Workflow-Komponenten ## Konfiguration ### Cache-Konfiguration ```yaml # In act_runner config.yaml cache: enabled: true host: "192.0.2.10" # static IP of ci-runner.example.net port: 8088 ``` **Wichtig:** `cache.host` ist die Adresse, die Job-Container verwenden, um den Cache-Server zu erreichen, nicht die Listen-Adresse des Servers. ### Workflow-Beispiel ```yaml name: Build and Deploy on: [push] permissions: packages: write # Required for registry pushes jobs: build: runs-on: linux-docker steps: - uses: actions/checkout@v4 - name: Load secrets uses: 1password/load-secrets-action@v2 with: vault: CI-CD env: REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} - name: Build with BuildKit run: | docker buildx create --driver remote tcp://$HOST_IP:1234 docker buildx build --push ... ``` ## Validierte Szenarien ### Szenario A: Arch-Paketbuilds - **Basis-Image:** `archlinux:base-devel` - **Herausforderung:** `makepkg` benötigt Root - **Lösung:** Erstelle non-Root-Benutzer `builder` on-the-fly - **Artefakte:** `actions/upload-artifact@v3` (v4 nicht vollständig unterstützt) - **Hinweis:** Gitea Actions v4 hat begrenzte Artefakt-Unterstützung ### Szenario B: Container-Builds - **Basis-Image:** `debian:trixie-slim` (Standard) - **Vermeidet:** Alpine Linux (musl libc inkompatibel mit 1Password CLI) - **Verbindung:** Dynamische IP-Erkennung via `ip route | awk '/default/ { print $3 }'` ### Szenario C: K3s-Deployments -Cluster - **Authentifizierung:** Kubeconfig aus 1Password-Vault - **Muster:** `kubectl wait --for=delete pod -l ...` für zuverlässige Ressourcenverwaltung ### Szenario D: Test- und Release-Pipeline eines Python-Werkzeugs - **Basis-Image:** `debian:trixie-slim`, trägt python3 3.13[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30] - **Erster Schritt:** `apt-get install nodejs`, **vor** dem Checkout - Voraussetzung für jede JavaScript-Action, siehe [[Act Runner]][^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30] - **Checkout:** `actions/checkout@v7`[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30] - **Release:** `${{ gitea.token }}` genügt für das Anlegen von Release und Tag sowie für Asset-Uploads; kein Actions-Secret mit `write:repository` nötig[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30] - **Auslöser des Release-Workflows:** eine Änderung an der `VERSION`-Datei, siehe [[KB Stack Versioning]] ### Läufe eines Workflows auf ihre Ursache prüfen Bei einem privaten Repository lässt sich der Lauf-Zustand nicht anonym über HTTP feststellen; [[Gitea]] antwortet einem anonymen Aufrufer identisch mit `404`, ob das Repository unsichtbar oder nicht vorhanden ist[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]. Läufe, ihr Ausgang und ihre Logs werden über den [[Gitea MCP Server]] gelesen. ## Auslöser filtern `paths-ignore` schließt Pfade von einem Workflow aus. Für die Filterlisten gelten hier drei Festlegungen, die alle Ableitungen aus Undokumentiertem vermeiden[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]: - **Keine YAML-Anker**, um eine Liste zwischen zwei Workflows zu teilen. GitHubs Parser lehnt Anker ab, und für Gitea ist nicht dokumentiert, dass er sie annimmt. Die Liste steht lieber zweimal. - **Keine negierten Muster** wie `!**/CONTRACT.md`. Gitea dokumentiert die Unterstützung negierter Filtermuster nicht. - **Die Muster scheitern offen.** Alles Unvorhergesehene löst weiterhin einen Lauf aus; das ist die richtige Richtung für einen Filter, dessen Auswertung nicht bewiesen ist. Dass die Filter greifen, ist seit 2026-08-31 beobachtet und nicht mehr angenommen. Commit `f916376` war ein reiner Content-Publish - `kb/index.md`, `kb/log.md`, `kb/provenance.md`, acht Seiten unter `kb/*/**` und eine Datei unter `raw/notes/`, sämtlich auf der Ignore-Liste - und erzeugte zu seiner `head_sha` keinen einzigen Lauf[^s-conversation-issue-triage-labels-and-todo-retirement-session-2026-08-31]: | Commit | Inhalt | Läufe | |---|---|---| | `6f54c31` | Stack (1.1.0) | 59 | | `adfa220` | Stack (1.1.1) | 60, 61 | | `f916376` | nur `kb/` und `raw/` | keine | | `40adbb7` | Stack (1.2.0) | 62, 63 | Die Stack-Commits davor und danach erzeugten je zwei Läufe, CI und Release, weil `VERSION` sich bewegt hatte. Der Unterschied ist also der Filter und kein untätiger Runner; Gitea wertet diese Muster wie GitHub aus[^s-conversation-issue-triage-labels-and-todo-retirement-session-2026-08-31]. Der Befund steht im Kommentarkopf von `.gitea/workflows/ci.yml`, damit er nicht erneut für eine Annahme gehalten wird, und schloss Gitea-Issue #11[^s-conversation-issue-triage-labels-and-todo-retirement-session-2026-08-31]. Als Folgewirkung bleibt die stärkste Hälfte der Begründung für den nächtlichen Drift-Check (Issue #9) stehen: Weil der Filter greift, läuft `lint --fail-on-error` bei einem Content-Publish tatsächlich nicht mehr. Ob dieser Gitea-Build `on: schedule` überhaupt auswertet, ist davon unberührt - ~~und weiter offen~~ (Stand 2026-08-31; seit 2026-09-01 geklärt, siehe unten)[^s-conversation-issue-triage-labels-and-todo-retirement-session-2026-08-31]. `.gitea/workflows/nightly.yml` (seit 2026-08-31) implementiert diesen Drift-Check: `on: schedule` (`17 3 * * *` UTC) plus `workflow_dispatch`, kein Push-Trigger, dieselbe Runner-Form wie `ci.yml`. Diese Gitea-Instanz läuft **1.26.1** - weit über der 1.20-Version, die Actions-Schedules einführte, was den Trigger plausibel, aber nicht bewiesen macht[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31]. Zwei `workflow_dispatch`-Testläufe bestätigten zunächst nur, dass der Job selbst durchläuft (Run 85, alle sieben Schritte grün) - ~~keiner davon ist ein `schedule`-Lauf. **Offen bleibt weiterhin**, ob der Cron-Trigger auf diesem Stand tatsächlich feuert - frühestens ab 2026-09-01 03:17 UTC zu beobachten, an einem Lauf mit `"event":"schedule"`, nicht an einem weiteren `workflow_dispatch`-Erfolg~~ (Stand 2026-08-31)[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31]. **Bestätigt seit 2026-09-01:** Run 90 ist der erste Lauf der Repository-Historie mit `"event":"schedule"` - gestartet `2026-09-01T03:17:35Z`, exakt zur konfigurierten Cron-Zeit, abgeschlossen `03:17:38Z`, alle sieben Schritte grün. Dieser Gitea-1.26.1-Stand wertet `on: schedule` auf dem Default-Branch also tatsächlich aus; der im Issue vorgesehene externe Fallback (ein externer Cron gegen die Actions-API) war nicht nötig. Gitea-Issue #9 ist damit geschlossen. ## Bekannte Probleme und Lösungen ### Der Job-Container ist keine konfigurationsfreie Maschine (Beobachtet 2026-08-31) **Beobachtung:** `actions/checkout@v7` legt im Job-Container selbst eine globale git-Konfiguration an. Aus dem Log von Lauf 79 des Chemenu-CI (damals `llm-wiki-test1`): `Copying '/root/.gitconfig' to '/tmp//.gitconfig'` und `Temporarily overriding HOME='/tmp/' before making global git config changes`. Ein `git config --global --add safe.directory` im eigenen Setup-Schritt schreibt zusätzlich hinein[^s-conversation-hardening-the-test-suite-against-silent-environment-dependencies-session-2026-08-31]. **Warum das zählt:** Ein CI-Container gilt gern als neutrale Umgebung - "hier ist nichts konfiguriert, also fällt auf, was von der Maschine gelesen wird". Für git stimmt das nicht mehr. Ein Test oder Guard, der sich darauf verlässt, hört still auf zu greifen: kein roter Lauf, keine Meldung, nur eine Prüfung, die nichts mehr prüft. **Konsequenz:** Wer Umgebungsunabhängigkeit prüfen will, stellt sie explizit her (`GIT_CONFIG_GLOBAL=/dev/null`, eigenes `HOME`) statt sie vom Container zu erwarten. Siehe [[Ambient Environment Dependency]]. ### `doctor` prüft eine Instanz, ein Checkout ist noch keine (Behoben 2026-08-31) **Problem:** Der erste `workflow_dispatch`-Lauf von `nightly.yml` scheiterte am `doctor`-Schritt: `FAIL git-identity: 'git config user.name' is not set` und `FAIL skills: No skills published yet`[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31]. **Grundursache:** `doctor` fragt, ob eine *arbeitsfähige Instanz* korrekt konfiguriert ist, nicht ob ein Checkout vollständig ist. `.agents/skills/` und `.claude/skills/` sind generiert und bewusst nicht committet (siehe `instructions/bootstrap.md`), existieren also erst nach `wikitool instructions sync`; und der Job-Container hat keine git-Konfiguration, unabhängig davon, ob `WIKI_AUTHOR` gesetzt ist - das deckt nur die separate `author`-Prüfung, nicht `git-identity`[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31]. Weil `doctor` den Job abbrach, wurde `instructions verify` nie erreicht - der Fehlschlag stand vor dem eigentlichen Prüfzweck des Laufs, nicht in ihm[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31]. **Lösung:** Vor `doctor` eine echte git-Identität setzen (`git config --global user.name/ user.email`) und `tools/wikitool instructions sync` laufen lassen - ein Mechanismus deckt beide Prüfungen ab, statt zwei separate (git-Identität, `WIKI_AUTHOR`) je eine. Jeder Workflow, der `doctor` oder `instructions verify` auf einem frischen Checkout aufruft, braucht denselben Bootstrap[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31]. ### JavaScript-Actions ohne `node` im Job-Image (Behoben 2026-08-30) **Problem:** Jeder Lauf scheiterte an `actions/checkout` mit `exec: "node": executable file not found in $PATH` und `exitcode '127'`. **Grundursache:** act_runner führt JavaScript-Actions mit `node` im Job-Container aus; das gepinnte `debian:trixie-slim` bringt keins mit. Das Runner-Label `linux-docker` war nie das Problem - es routete und startete den Container von Anfang an[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]. **Lösung:** `nodejs` als erster Schritt vor dem Checkout installieren, Checkout auf `actions/checkout@v7` heben. Ausführlich auf der Seite [[Act Runner]]. ### Actions Cache Server-Konnektivität (Behoben 2026-07-12) **Problem:** `setup-go@v6` und andere Cache-verwendende Actions zeigten Timeout bei Versuch, den Cache-Server unter `172.18.0.2:39329` (interne Docker-Bridge-IP) zu erreichen. **Grundursache:** Runner-Container befand sich in seinem eigenen Bridge-Netz (`act_runner_default`), während sich jeder Job-Container in einem isolierten temporären Bridge-Netz befand. Diese Netze konnten ohne Host-Routing nicht miteinander kommunizieren. **Lösung:** 1. Änderte Runner-Container zu `network_mode: host` 2. Setzte `cache.host` auf statische IP `192.0.2.10` 3. Cache-URL automatisch als `ACTIONS_CACHE_URL` injiziert 4. Vollständiger Neustart erforderlich: `docker compose down && docker compose up -d` ## Beziehungen - **Teil von:** [[Gitea]]-Ökosystem - **Ausgeführt von:** [[Act Runner]] - **Nutzt:** [[Docker]] für Container - **beobachtet über:** [[Gitea MCP Server]] - **zeigte:** [[Ambient Environment Dependency]] - **implementiert:** [[CI Integration]] ## Vorteile - GitHub Actions kompatible Syntax - Selbstgehostet, volle Kontrolle - Integriert mit Gitea-Ökosystem - Zero-Trust-ready mit 1Password-Integration - Keine Vendor-Lock-in ## Siehe auch - [[Gitea]] - Git-Dienst - [[Act Runner]] - Runner-Implementierung - Host-VM - Secrets-Verwaltung - Build-System - [[Docker]] - Container-Plattform concept - [[Gitea MCP Server]] - [[Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31]] - [[Source - Conversation - Hardening the Test Suite Against Silent Environment Dependencies Session 2026-08-31]] - [[Ambient Environment Dependency]] - [[CI Integration]] ## Fußnoten [^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]: [[Source - Conversation - Versioning CI-CD and Content Migration Session 2026-08-30]] [^s-conversation-issue-triage-labels-and-todo-retirement-session-2026-08-31]: [[Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31]] [^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31]: [[Source - Conversation - Nightly Drift-Check Workflow and doctor's Bootstrap Gap Session 2026-08-31]] [^s-conversation-hardening-the-test-suite-against-silent-environment-dependencies-session-2026-08-31]: [[Source - Conversation - Hardening the Test Suite Against Silent Environment Dependencies Session 2026-08-31]]