Zum Hauptinhalt springen

Actions und CI/CD

fremforge betreibt Forgejo Actions, ein mit GitHub Actions kompatibles CI/CD-System. Workflow-Dateien nutzen die YAML-Syntax von GitHub Actions, und rund 95 % der Actions aus dem GitHub Marketplace funktionieren ohne Änderung.

Speicherort der Workflow-Dateien

Lege Workflow-Dateien unter .forgejo/workflows/<name>.yaml in deinem Repository ab. Zur Kompatibilität mit von GitHub migrierten Repositorys liest Forgejo auch .github/workflows/, auf fremforge ist aber .forgejo/workflows/ der maßgebliche Ort.

Trigger-Ereignisse

EreignisAuslöser
pushJeder Push auf passende Branches oder Tags
pull_requestPR geöffnet, synchronisiert oder wieder geöffnet
pull_request_targetPR gegen das Ziel-Repository (für Forks) – siehe Sicherheitshinweis unten
scheduleCron-Zeitplan (UTC)
workflow_dispatchManueller Auslöser über UI oder API
workflow_callWiederverwendbarer Workflow, der von einem anderen Workflow aufgerufen wird
releaseRelease veröffentlicht, angelegt oder bearbeitet
issuesIssue geöffnet, bearbeitet, geschlossen oder mit Label versehen
issue_commentKommentar zu einem Issue oder PR
createBranch oder Tag angelegt
deleteBranch oder Tag gelöscht
registry_packagePaket veröffentlicht oder aktualisiert

Kontextvariablen

fremforge nutzt zur Kompatibilität mit dem Ökosystem von GitHub Actions die Kontextnamen github.*. Sie beziehen sich auf die fremforge-/Forgejo-Instanz, nicht auf GitHub.

VariableWert
github.actorBenutzername der Person, die den Lauf ausgelöst hat
github.repository<org>/<repo>
github.refVollständige Git-Ref, z. B. refs/heads/main
github.shaCommit-SHA
github.event_nameEreignis, das den Workflow ausgelöst hat
github.run_idEindeutige Kennung des Laufs
github.server_urlhttps://frem.sh
github.api_urlhttps://frem.sh/api/v1

Eingebaute Secrets

SecretBeschreibung
secrets.FORGEJO_TOKENAutomatisch erzeugtes Token pro Job; auf das Repository beschränkt; standardmäßig nur lesend, außer dass es die Pakete des Repositorys veröffentlichen kann
secrets.GITHUB_TOKENAlias für FORGEJO_TOKEN (Kompatibilität)

Eingebaute Tokens sind kurzlebig und auf den aktuellen Workflow-Lauf beschränkt. Außerhalb des Jobs, der sie erhalten hat, lassen sie sich nicht verwenden.

permissions-Block

Die Standardberechtigung ist contents: read. Alle anderen Berechtigungen stehen standardmäßig auf none, sofern sie nicht ausdrücklich deklariert werden.

permissions:
  contents: read       # git checkout
  id-token: write      # OIDC token federation
  issues: write        # create / update issues
  pull-requests: write # comment on PRs

Deklariere Berechtigungen auf Workflow-Ebene (gilt für alle Jobs) oder auf Ebene einzelner Jobs. Deklarationen auf Job-Ebene überschreiben die auf Workflow-Ebene.

packages: write steht nicht in dieser Liste, weil es nicht gebraucht wird. Das eingebaute Token pro Job liest bereits jedes Paket des Owners des Repositorys und schreibt Pakete, die mit dem eigenen Repository verknüpft sind (Läufe für Pull-Requests aus Forks nur lesend). Siehe Aus Forgejo Actions veröffentlichen.

Minimales Workflow-Beispiel

name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: fremforge
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: npm ci && npm test

Wiederverwendbare Workflows

Lagere gemeinsame Logik in einen wiederverwendbaren Workflow aus, den andere Workflows mit workflow_call aufrufen:

# .forgejo/workflows/reusable.yaml
on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string

jobs:
  deploy:
    runs-on: fremforge
    environment: ${{ inputs.environment }}
    steps:
      - run: echo "Deploying to ${{ inputs.environment }}"

Aufruf aus einem anderen Workflow:

jobs:
  deploy-staging:
    uses: ./.forgejo/workflows/reusable.yaml@main
    with:
      environment: staging

Caching

Mit actions/cache bewahrst du Verzeichnisse zwischen Läufen auf:

- uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

Cache-Treffer beschleunigen Jobs bei Paketmanagern, Build-Werkzeugen und kompilierten Ergebnissen deutlich. Das eingebaute Caching von actions/setup-node, setup-python, setup-go und setup-java (cache: npm usw.) nutzt denselben Dienst.

So verhält sich der Cache auf fremforge:

  • Auf das Repository beschränkt. Ein in einem Repository gespeicherter Cache ist für kein anderes sichtbar, weder in derselben noch in einer anderen Organisation. Innerhalb eines Repositorys teilen sich die Branches einen Cache.
  • Pull-Requests sind isoliert. Ein pull_request-Lauf kann die Caches des Repositorys wiederherstellen, was er speichert, sehen aber nur spätere Läufe desselben Pull-Requests. Ein Pull-Request (auch einer aus einem Fork) kann also nicht ändern, was andere Branches wiederherstellen.
  • Grenzen. Bis zu 10 GiB pro Eintrag und 10 GiB pro Repository; überschreitet ein Repository das, werden seine am längsten nicht genutzten Einträge entfernt. Einträge, die 7 Tage lang nicht genutzt wurden oder älter als 30 Tage sind, werden entfernt.
  • Lässt nie einen Job scheitern. Ist der Cache nicht verfügbar, protokolliert actions/cache eine Warnung, und der Job läuft ohne ihn weiter.

Der Cache liegt auf der eigenen Infrastruktur von fremforge in der EU.

Umgebungen und Deployment-Gates

Umgebungen ergänzen Deploy-Jobs um Freigabe-Gates, erforderliche Prüfer und Secrets, die auf die Umgebung beschränkt sind.

Lege Umgebungen unter Org-Admin → Umgebungen (https://frem.sh/<org>/_admin/environments) an. Konfiguriere erforderliche Prüfer, damit vor dem Lauf des Jobs eine manuelle Freigabe nötig ist.

Eine Umgebung in einem Job referenzieren:

jobs:
  deploy-prod:
    runs-on: fremforge
    environment: production
    steps:
      - run: ./deploy.sh

Sind für production erforderliche Prüfer konfiguriert, wartet der Job vor der Ausführung auf die Freigabe. Secrets der Umgebung production werden nur in diesen Job eingespeist.

Hinweise zur Kompatibilität

  • ~95 % der Actions aus dem GitHub Marketplace funktionieren ohne Änderung.
  • secrets.GITHUB_TOKEN ist ein Alias für secrets.FORGEJO_TOKEN. Actions, die es nutzen, funktionieren unverändert.
  • Actions, die die GitHub-API direkt aufrufen (fest eingetragenes api.github.com), scheitern. Die API-URL von fremforge ist https://frem.sh/api/v1.
  • Actions, die öffentliche Daten von api.github.com lesen (die Versionslisten der setup-*-Actions, Release-Downloads), teilen sich das Limit von GitHub von 60 Anfragen pro Stunde mit jedem Job auf derselben ausgehenden IP-Adresse. Gib eine major.minor-Version an und übergib ein GitHub.com-Token: siehe Rate-Limit der GitHub-API.
  • actions/upload-artifact und actions/download-artifact funktionieren.
  • GitHub Packages (ghcr.io, pkg.github.com) sind nicht verfügbar. Nutze stattdessen die Paket-Registry von fremforge.
  • Actions, die GitHub-spezifische Funktionen voraussetzen (GitHub Copilot, GitHub Codespaces, GitHub Packages), haben in fremforge keine Entsprechung.
  • Die Workflow-Befehle ::set-output, ::set-env und ::add-path bewirken nichts. Schreibe stattdessen nach $GITHUB_OUTPUT, $GITHUB_ENV und $GITHUB_PATH; siehe Ausgaben, Umgebungsvariablen und PATH.
  • Ein Ausdruck, der sich nicht auswerten lässt, lässt seinen Schritt oder Job scheitern, ebenso eine ungültige strategy.matrix, etwa ein exclude, das einen Wert nennt, den die Matrix nicht hat.
  • Job-Zusammenfassungen werden nicht unterstützt. Ein Schritt, der nach $GITHUB_STEP_SUMMARY schreibt, ist trotzdem erfolgreich, aber die Zusammenfassung wird verworfen, und das Schrittprotokoll zeigt die Warnung This Forgejo instance does not support job summaries.

Die vollständige Kompatibilitätsmatrix der Top-100-Actions findest du unter Marketplace-Kompatibilität.

Ausgaben, Umgebungsvariablen und PATH

Seit dem 21. Oktober 2026 laufen die gehosteten Runner mit forgejo-runner 13, der drei Workflow-Befehle entfernt hat: ::set-output, ::set-env und ::add-path. Ein Schritt, der einen davon ausgibt, bekommt eine Warnung in sein Protokoll und läuft ansonsten weiter, aber die Ausgabe, die Umgebungsvariable oder der PATH-Eintrag wird nicht gesetzt. Der Job kann trotzdem grün werden, und ein späterer Schritt oder Job liest dann einen leeren Wert.

Das betrifft vor allem von GitHub übernommene Workflows, wo ::set-output zwar veraltet ist, aber noch akzeptiert wird. ACTIONS_ALLOW_UNSECURE_COMMANDS=true zu setzen bringt die Befehle nicht zurück.

Schreibe stattdessen in die Dateien, die der Runner benennt. Jede ist als GITHUB_* und als FORGEJO_* verfügbar und zeigt auf dieselbe Datei, sodass ein Workflow, der auch auf GitHub läuft, mit den GITHUB_*-Namen weiter funktioniert.

Entfernter BefehlStattdessen schreiben nach
echo "::set-output name=NAME::value"echo "NAME=value" >> "$GITHUB_OUTPUT" (oder $FORGEJO_OUTPUT)
echo "::set-env name=NAME::value"echo "NAME=value" >> "$GITHUB_ENV" (oder $FORGEJO_ENV)
echo "::add-path::/some/dir"echo "/some/dir" >> "$GITHUB_PATH" (oder $FORGEJO_PATH)

Vorher – setzt jetzt nichts mehr:

      - id: version
        run: echo "::set-output name=tag::$(git describe --tags)"
      - run: echo "Releasing ${{ steps.version.outputs.tag }}"   # empty

Nachher:

      - id: version
        run: echo "tag=$(git describe --tags)" >> "$GITHUB_OUTPUT"
      - run: echo "Releasing ${{ steps.version.outputs.tag }}"

So findest du die Befehle in einem Repository: git grep -nE '::(set-output|set-env|add-path)'. Eine Marketplace-Action, die sie noch ausgibt, verliert ihre Ausgaben auf dieselbe Weise; aktualisiere sie auf ein Release, das in die Dateien schreibt.

Reichweite von Secrets bei Fork-PRs – Richtlinie zu pull_request_target

Kurz gesagt: Workflows, die pull_request_target auslöst, laufen mit den Secrets und Berechtigungen des Ziel-Repositorys, auch wenn der PR aus einem Fork kommt. Checke in einem solchen Workflow niemals den Head des PRs aus und führe ihn nie aus (zum Beispiel actions/checkout mit ref: ${{ github.event.pull_request.head.sha }}): Damit läuft nicht vertrauenswürdiger Code neben deinen Secrets. Nutze pull_request, um Beiträge zu bauen und zu testen; PRs aus Forks laufen dort ohne Secrets und ohne Identitäts-Token.

pull_request_target führt Workflows im Kontext des Ziel-Repositorys aus, wenn ein PR aus einem Fork kommt – der Workflow hat also Zugriff auf die Secrets des Ziel-Repositorys, obwohl die Workflow-Datei von der Autorin oder dem Autor des Forks geändert worden sein kann. Genau dieses Angriffsmuster steht hinter der Klasse des GitHub-Actions-Marketplace-Vorfalls von 2023.

Richtlinie von fremforge: Workflows mit pull_request_target DÜRFEN KEINEN vom Fork gelieferten Code ausführen, während Secrets vorhanden sind. Zwei zulässige Muster:

  1. pull_request statt pull_request_target, wenn der Workflow Fork-Code ausführen muss. Der Workflow des Fork-PRs läuft im Kontext des Forks – keine Secrets des Ziel-Repositorys erreichbar. Das ist der Standard und die sichere Form.
  2. pull_request_target NUR für rein lesende Workflows zum Labeln, Sichten oder Kommentieren, die ausdrücklich github.sha auschecken (die Merge-Basis, nicht den Head des Forks) und keinen vom Fork gelieferten Install-, Build- oder Testschritt ausführen.

Workflows, die pull_request_target mit actions/checkout@v4 gegen github.event.pull_request.head.sha kombinieren, sind ein SEV-1-Vektor zur Exfiltration von Secrets und werden im Review vor dem Merge markiert. Ein Pre-Receive-Hook in Forgejo, der die gefährliche Kombination statisch ablehnt, steht auf der Roadmap für künftige Härtung; bis er ausgeliefert ist, ist das Code-Review das aktive Gate.

Keine Umgebung für einen Lauf aus einem Fork (strenger als GitHub). Ein pull_request_target-Lauf, den ein Pull-Request aus einem Fork auslöst, bekommt überhaupt keine Umgebung: keine Secrets der Umgebung, keine Variablen der Umgebung und keinen environment-Claim in seinem OIDC-Token, selbst wenn der Job environment: deklariert und die Workflow-Datei der Basis ausgeführt wird. GitHub gibt einem solchen Lauf die Umgebung, vorbehaltlich ihrer Schutzregeln; fremforge tut das seit dem 27.10.2026 nicht. Pull-Requests aus einem Branch desselben Repositorys behalten ihre Umgebung, gelesen aus der Workflow-Datei des Basis-Branches und wie üblich durch die Branch-Regel und die Prüfer der Umgebung abgesichert. Die Branch-Regel wird wie auf GitHub gegen den Basis-Branch geprüft, auf den der Pull-Request zielt, nicht gegen die eigene Ref des Pull-Requests (refs/pull/<n>/head): Eine auf main beschränkte Umgebung lässt einen pull_request_target-Job aus demselben Repository bei einem Pull-Request nach main zu. Secrets des Repositorys und der Organisation bleiben unverändert: Der pull_request_target-Lauf eines Forks erhält sie weiterhin, wie auf GitHub und Forgejo.

Darum bleibt das Auschecken des Heads gefährlich. Ein pull_request_target-Job, der den Head-Code des Pull-Requests auscheckt und ausführt (eine Installation, einen Build, einen Test, ein Skript aus dem PR), übergibt diesem Code jedes Secret, das der Job noch erreichen kann: die Secrets des Repositorys und der Organisation sowie das Job-Token. Das Zurückhalten der Umgebung ändert daran nichts. Beschränke solche Jobs auf die oben beschriebene rein lesende Form, oder verlege die Arbeit nach pull_request.

Kein OIDC-ID-Token für einen Lauf aus einem Fork. Ein pull_request_target-Lauf, den ein Pull-Request aus einem Fork auslöst, bekommt kein ID-Token: getIDToken (bzw. id-token: write) antwortet mit 403, egal für welche Audience. Ein solcher Lauf kann sich also weder mit einer Cloud föderieren noch schlüssellos mit Sigstore signieren. Ein Job, der deployen oder signieren muss, gehört auf push oder workflow_dispatch, nachdem eine Maintainerin oder ein Maintainer die Änderung gemergt hat. Läufe aus dem Repository selbst, einschließlich Pull-Requests aus einem Branch desselben Repositorys, sind nicht betroffen.

Für den vollständigen Hintergrund: Das Sicherheitsmodell von Forgejo Actions entspricht dem von GitHub. Die Semantik von pull_request_target ist übernommen, nur dass fremforge dem Lauf eines Forks weder ID-Token noch Umgebung ausstellt.

Richtlinie für Image-Quellen

uses:-Anweisungen gibt es in zwei Formen – beide werden auf fremforge akzeptiert, aber der ausgehende Datenverkehr unterscheidet sich:

  • uses: <owner>/<repo>@<sha> – wird gegen den EU-Action-Mirror unter frem.sh/<owner>/<repo> aufgelöst – jeder Upstream-Herausgeber hat seine eigene Mirror-Organisation (actions, docker, aws-actions, azure, google-github-actions, peter-evans, softprops, sonarsource, step-security, dorny, pnpm), sodass uses: actions/checkout@<sha> zu frem.sh/actions/checkout aufgelöst wird. Die Mirrors synchronisieren alle 8 Stunden vom Upstream. Das ist die empfohlene Form.
  • uses: docker://<registry>/<image>:<tag> – Forgejo Actions löst das auf, indem es das Image direkt von der Registry-URL zieht, die der Workflow angibt. Es gibt keine automatische Umleitung auf einen fremforge-Mirror und derzeit keine eingebaute Allowlist für den Registry-Teil. Pinne auf einen Digest (docker://<registry>/<image>@sha256:…) statt auf ein veränderliches Tag. Seit dem 24.10.2026 listet der tägliche Scan Workflow-Pinning jede docker://-Referenz auf, die nicht per Digest gepinnt ist. Ein Pre-Receive-Hook in Forgejo oder eine Allowlist auf Runner-Seite für docker:// steht auf der Roadmap für künftige Härtung; bis dahin behandle eine ungepinnte docker://-Referenz als Thema für das Code-Review.

Die API für Workflow-Läufe

Vier Routen existieren und funktionieren. Nur die ersten beiden sind irgendwo sonst dokumentiert, weshalb die anderen beiden meist als fehlend gemeldet werden:

WasRoute
Läufe auflistenGET /api/v1/repos/<owner>/<repo>/actions/runs
Protokolle abrufenGET /api/v1/repos/<owner>/<repo>/actions/runs/<run_id>/logs
Einen Lauf abbrechenPOST /api/v1/repos/<owner>/<repo>/actions/runs/<run_id>/cancel
Einen Lauf neu startenPOST /api/v1/repos/<owner>/<repo>/actions/runs/<run_id>/rerun
# stop a run that is queued or in progress
curl -X POST -H "Authorization: token <forgejo-pat>" \
  https://frem.sh/api/v1/repos/<owner>/<repo>/actions/runs/<run_id>/cancel
# -> 204, and the run's status becomes `cancelled`

Warum es so aussieht, als gäbe es kein Abbrechen

Jedes Signal weist davon weg, „Ich habe es nicht gefunden“ ist also das erwartbare Ergebnis und kein Versäumnis beim Suchen:

  • DELETE liefert 405. Die Route ist nur POST. DELETE .../cancel und beide Verben auf .../runs/<id> (ohne /cancel) liefern alle 405.
  • /actions/tasks/<id>/cancel liefert 404. Tasks sind keine Läufe.
  • Forgejos eigene OpenAPI-Spezifikation wird hier nicht ausgeliefert. /swagger.v1.json und jede Variante davon liefern auf frem.sh 404, es gibt also nichts, worin man die Route nachschlagen könnte.
  • Die API-Spezifikation von fremforge beschreibt sie nicht, und kann es auch nicht. Sie dokumentiert die Endpunkte dieser Plattform, nicht die von Forgejo – cancel kommt darin nur unter /orgs/{org}/billing/cancel vor, und das betrifft Abonnements. Wer darin nach einer Möglichkeit sucht, einen Lauf abzubrechen, findet das falsche cancel.
  • Die fremforge-API antwortet mit 501. Das ist die Auffangantwort für /api/v1/*-Pfade, die zu keinem Endpunkt passen, und ihre Meldung verweist auf die OpenAPI-Spezifikation von fremforge – also zurück auf die Spezifikation, die diese Route nicht enthält.
  • ffp_*-Tokens können das überhaupt nicht. Der organisationsgebundene Proxy überbrückt nur die Protokoll-Route (siehe unten); Abbrechen und Neustarten brauchen einen Forgejo-PAT oder ein Sitzungs-Cookie.

Wenn du Läufe mehr als einmal von Hand abbrichst

Automatisiere das nicht per Skript – setze stattdessen eine Concurrency-Gruppe, damit Forgejo den überholten Lauf selbst abbricht:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Jeder Push auf einen Branch überholt dann dessen vorherigen Lauf. Sicher für erforderliche Checks: Status gelten pro Commit, daher kann das Abbrechen des Laufs für einen älteren Commit die Checks des aktuellen Heads nicht hängen lassen.

Ein abgebrochener Lauf lässt seine Checks scheitern. Der Commit-Status jedes abgebrochenen Jobs endet mit failure und der Beschreibung Has been cancelled, egal ob der Job lief oder noch wartete. Brichst du also einen Lauf auf dem Commit ab, den du mergen willst, werden dessen erforderliche Checks rot, und ein scharf geschalteter Auto-Merge mergt ihn nicht. Pushe erneut, oder POST .../rerun.

Workflows aktivieren und deaktivieren

Die Schaltflächen Disable workflow / Enable workflow im Tab Actions eines Repositorys haben API-Entsprechungen. Pfade, Operationsnamen und JSON sind die von Gitea, sodass ein für die Gitea-API geschriebener Client unverändert funktioniert.

WasRouteWer
Workflows und ihren Zustand auflistenGET /api/v1/repos/<owner>/<repo>/actions/workflowsalle, die die Actions des Repositorys lesen dürfen
Einen Workflow abrufenGET /api/v1/repos/<owner>/<repo>/actions/workflows/<workflow_id>alle, die die Actions des Repositorys lesen dürfen
Einen Workflow deaktivierenPUT /api/v1/repos/<owner>/<repo>/actions/workflows/<workflow_id>/disableAdmin des Repositorys, mit einem Token
Einen Workflow aktivierenPUT /api/v1/repos/<owner>/<repo>/actions/workflows/<workflow_id>/enableAdmin des Repositorys, mit einem Token

<workflow_id> ist der Dateiname des Workflows, z. B. ci.yaml, wie er in .forgejo/workflows/ (oder .gitea/workflows/, .github/workflows/) auf dem Standard-Branch erscheint.

# switch a workflow off, then back on
curl -X PUT -H "Authorization: token <forgejo-pat>" \
  https://frem.sh/api/v1/repos/<owner>/<repo>/actions/workflows/ci.yaml/disable
# -> 204
curl -X PUT -H "Authorization: token <forgejo-pat>" \
  https://frem.sh/api/v1/repos/<owner>/<repo>/actions/workflows/ci.yaml/enable
# -> 204

# which workflows are switched off?
curl -H "Authorization: token <forgejo-pat>" \
  https://frem.sh/api/v1/repos/<owner>/<repo>/actions/workflows
{
  "workflows": [
    {
      "id": "ci.yaml",
      "name": "CI",
      "path": ".forgejo/workflows/ci.yaml",
      "state": "disabled_manually",
      "created_at": "2026-10-09T08:00:00Z",
      "updated_at": "2026-10-09T08:00:00Z",
      "url": "https://frem.sh/api/v1/repos/<owner>/<repo>/actions/workflows/ci.yaml",
      "html_url": "https://frem.sh/<owner>/<repo>/src/branch/main/.forgejo/workflows/ci.yaml",
      "badge_url": "https://frem.sh/<owner>/<repo>/badges/workflows/ci.yaml/badge.svg?branch=main"
    }
  ],
  "total_count": 1
}
  • state ist active oder disabled_manually. Es ist dieselbe Einstellung, die die Schaltflächen ändern, daher stimmen UI und API immer überein.
  • name ist das name: des Workflows oder der Dateiname, wenn er keinen hat. created_at und updated_at sind beide der Zeitpunkt des neuesten Commits auf dem Standard-Branch, wie bei Gitea, nicht die eigene Historie der Datei.
  • Deaktivieren und Aktivieren erfordern Admin-Rechte am Repository, genau wie die Schaltflächen. Wer Schreibzugriff hat, bekommt 403. Das ist strenger als bei Gitea, wo Schreibberechtigte das dürfen.
  • 404 für eine Datei, die kein Workflow auf dem Standard-Branch ist. Ein Tippfehler, eine Datei auf einem anderen Branch oder eine Datei im Workflow-Verzeichnis, die nicht .yml/.yaml ist, wird abgelehnt statt gespeichert.
  • Ein archiviertes Repository antwortet mit 423 auf Aktivieren und Deaktivieren. Lesen lässt es sich weiterhin.
  • Beide Aufrufe sind idempotent. Einen deaktivierten Workflow zu deaktivieren liefert 204 und ändert nichts.
  • Was „deaktiviert“ stoppt: Läufe durch Ereignisse (Push, Pull-Request und die übrigen), geplante Läufe und Neustarts seiner vorhandenen Läufe (POST .../rerun antwortet mit 422). Ein manueller Dispatch (POST .../actions/workflows/<workflow_id>/dispatches) läuft weiterhin, genau wie Run workflow in der UI.
  • ffp_*-Tokens können diese Routen nicht aufrufen. Sie brauchen einen Forgejo-PAT (Scope write:repository für Aktivieren/Deaktivieren) oder eine Sitzung, wie beim Abbrechen und Neustarten.

Workflow-Protokolle programmatisch abrufen

Die Forgejo-Weboberfläche zeigt die Protokolle von Action-Läufen interaktiv an. Für den programmatischen Zugriff (Fehlerbenachrichtigungen, Debug-Skripte, Compliance-Exporte, KI-Agenten, die Fehler sichten) gibt es zwei Endpunkte, je nachdem, welche Art von Token du hast:

Mit einem Forgejo-PAT oder Sitzungs-Cookie

curl -H "Authorization: token <forgejo-pat>" \
  https://frem.sh/api/v1/repos/<owner>/<repo>/actions/runs/<run_id>/logs

Liefert text/plain – alle Jobs des Laufs aneinandergehängt, mit === job: <name> (status=<status>, attempt=<n>) ===-Kopfzeilen zwischen den Jobs. <run_id> ist die globale ID, die Forgejo von GET /api/v1/repos/<owner>/<repo>/actions/runs zurückgibt (dieselbe ID, die die Weboberfläche unter /<owner>/<repo>/actions/runs/<n> zeigt). Die RBAC ist Forgejos übliche Leseprüfung für Repositorys; Bot-Benutzer mit der passenden Mitgliedschaft in der Organisation funktionieren genauso wie menschliche Benutzer.

Mit einem fremforge-API-PAT (ffp_*)

Beginnt dein Token mit ffp_ – darunter PATs, die in der Admin-Oberfläche erzeugt wurden, Tokens aus POST /_app/api/v1/auth/token-exchange (OIDC-Austausch) und Tokens, die POST /_app/api/v1/oauth/token (client_credentials) ausstellt –, erkennt Forgejo es nicht. Nutze stattdessen den Proxy der fremforge-API:

curl -H "Authorization: Bearer <ffp_…>" \
  https://frem.sh/_app/api/v1/orgs/<org>/repos/<repo>/actions/runs/<run_id>/logs

Gleiche Antwortform (text/plain, aneinandergehängte Jobs, Kopfzeilen dazwischen). Erforderlicher Scope: runners:read. Der Proxy prüft die Mandantenbindung des Tokens (<org> in der URL muss zum Mandanten des Tokens passen), bevor er mit einer System-Zugangsberechtigung an Forgejo weiterleitet – die System-Zugangsberechtigung verlässt die Plattform nie, sodass ein geleakter Kunden-PAT nur die Protokolle seines eigenen Mandanten lesen kann.

Beide Endpunkte liefern denselben Body, ein Aufrufer, der die Authentifizierungsart wechselt, muss also nur die URL und den Authorization-Header ändern.

Hinweis zur Übergangslösung. Der Proxy /api/v1/orgs/<org>/repos/<repo>/... ist eine vorübergehende Brücke, bis Forgejo upstream API-Domain-Tokens (ffp_*) auf seinem nativen Endpunkt /api/v1/repos/<owner>/<repo>/... unterstützt. Sobald das ausgeliefert ist, wird der Proxy abgeschaltet, und ffp_*-Tokens nutzen denselben Pfad wie Forgejo-PATs. Die Antwortform bleibt identisch; nur die Form der URL ändert sich.

Wenn Protokolle nicht verfügbar sind

  • 404 – Lauf nicht gefunden oder gehört nicht zum Repository in der URL.
  • 410 – die Protokolle wurden vom Bereinigungsjob gelöscht (Action-Läufe, die älter als der Aufbewahrungszeitraum sind).
  • 502 – Forgejo-Origin nicht erreichbar. Erneut versuchen; hält es an, prüfe status.frem.sh.

Querverweise