Zum Hauptinhalt springen

Deployment-Umgebungen

Umgebungen sind benannte Deployment-Ziele (z. B. staging, production, eu-west) mit kombinierbaren Sicherheits-Gates. Ein Workflow-Job mit environment: production wird gegen ALLE konfigurierten Gates geprüft, bevor fremforge die Runner-VM bereitstellt – schlägt ein Gate fehl, wird das Deployment mit einer strukturierten Begründung abgelehnt. Admins der Organisation sichten das in der Verwaltungsoberfläche; der Workflow kann erneut ausgeführt werden, sobald die zugrunde liegende Bedingung erfüllt ist.

Schnellstart

  1. Gehe zu fremforge-Verwaltung → Umgebungen (https://frem.sh/<org>/_admin/environments).

  2. Gib unter Neue Umgebung einen Namen ein und klicke auf Erstellen.

  3. Öffne die Detailseite der neuen Umgebung, scrolle zu Deployment-Richtlinien, konfiguriere die gewünschten Richtlinien und klicke auf Richtlinien speichern.

  4. Verweise in einem beliebigen Workflow-Job auf die Umgebung:

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

Das nächste Deployment in diese Umgebung wird gegen deine Gates geprüft.

Die 9 Gates

Alle Gates sind unabhängig und kombinierbar. ALLE konfigurierten Gates müssen BESTEHEN, damit ein Deployment weiterläuft. Ein Gate ohne Konfiguration wird übersprungen (gilt als bestanden).

A. Erforderliche Freigebende

Blockiert den Start, bis N Personen beim ausstehenden Deployment auf Freigeben geklickt haben.

  • Wann sinnvoll: Produktions-Deployments, regulierte Umgebungen, überall dort, wo ein zweites Paar Augen das Sicherheitsnetz ist.
  • Konfiguration: Required reviewers auf der Detailseite der Umgebung. 0 = keine Freigabe; 1–6 = N Freigebende erforderlich.
  • Wo freigeben: fremforge-Verwaltung → Deployments (/<org>/_admin/deployments), Abschnitt „Ausstehende Freigaben“.
  • Hinweise: Wer den Workflow ausgelöst hat (die Person, die den Commit gepusht oder den PR eröffnet hat), kann das eigene Deployment nicht freigeben. Die Plattform lehnt Selbstfreigaben sowohl auf Routenebene als auch im Evaluator ab.
  • Widerrufen: Freigebende können ihre eigene Freigabe widerrufen, solange das Deployment noch nicht gestartet ist (z. B. wenn dir nach dem Klick auf Freigeben ein Problem auffällt). Sobald das Deployment gestartet ist, ist die Freigabe unveränderlich.

B. Erlaubte Refs (Branch- und Tag-Muster)

Schränkt ein, welche Git-Refs in diese Umgebung deployen dürfen.

  • Wann sinnvoll: „nur main deployt nach Produktion“; „nur release/*-Tags deployen in den Canary“.
  • Konfiguration: Branches und Tags für Deployments auf der Detailseite der Umgebung. Globs im GitHub-Stil: main, release/*, **/hotfix-*, refs/tags/v[0-9]+.*. Leer = jede Ref erlaubt.

C. Zeitfenster

Beschränkt Deployments auf bestimmte Geschäftszeiten oder sperrt sie während eines Freeze.

  • Wann sinnvoll: „Deployments nur Mo–Do 09:00–17:00 MEZ“; „alle Deployments vom 22. Dez. bis 2. Jan. sperren (Feiertags-Freeze)“.

  • Konfiguration: Time-window JSON auf der Detailseite der Umgebung. Aufbau:

    {
      "tz": "Europe/Copenhagen",
      "allowed": [
        { "days": ["Mon", "Tue", "Wed", "Thu"], "from": "09:00", "to": "17:00" }
      ],
      "blackouts": [
        { "from": "2026-12-22T00:00Z", "to": "2027-01-02T00:00Z", "reason": "holiday freeze" }
      ]
    }
    • tz: IANA-Zeitzone. Standard ist UTC.
    • allowed: Array erlaubter Zeitfenster. Tage mit drei Buchstaben (Mon..Sun). Uhrzeiten im 24-Stunden-Format HH:MM in tz.
    • blackouts: Array absoluter UTC-Zeiträume, in denen Deployments unabhängig von allowed verboten sind.
  • Hinweise: Blackouts haben Vorrang vor allowed. Leer = keine zeitliche Einschränkung.

D. SLO-Budget im grünen Bereich

Lehnt Deployments ab, solange das SLO-Fehlerbudget verbrannt wird.

  • Wann sinnvoll: „nicht deployen, solange Latenz oder Fehlerrate für Kunden im roten Bereich sind – erst die Regression beheben.“
  • Konfiguration: Block when these alarms are firing – kommagetrennte Namen von CES-/LTS-Alarmen, die deine Burn-Rate-Watchdogs pflegen. Beispiel: my-api-latency-sev1, my-api-error-budget-sev2.
  • So funktioniert es: fremforge verfolgt den jeweils letzten Zustand jedes aufgeführten Alarms. Ist einer davon im Zustand firing, lehnt dieses Gate den Start ab.
  • Fail-closed: Hat fremforge für einen aufgeführten Alarm keinen aktuellen Zustand, schlägt das Gate geschlossen fehl – eine Untersuchung ist einer stillen Umgehung vorzuziehen.

E. Erforderliche Statusprüfungen

Verlangt, dass benannte Forgejo-Commit-Status-Kontexte beim zu deployenden Commit success sind.

  • Wann sinnvoll: „Deployments warten, bis dep-scan, SAST und image-scan für diesen Commit bestanden sind.“
  • Konfiguration: Required check contexts – einer pro Zeile. Beispiele: dep-scan, sast, sha-pin-scan, image-scan-trivy.
  • So funktioniert es: fremforge liest beim Preflight GET /api/v1/repos/<o>/<r>/statuses/<sha>. Jeder erforderliche Kontext muss den Zustand success melden. Fehlende Kontexte ODER andere Zustände lassen das Gate fehlschlagen.

F. Parallelitätssperre

Begrenzt die Zahl gleichzeitig laufender Deployments in diese Umgebung.

  • Wann sinnvoll: „immer nur ein Produktions-Deployment gleichzeitig“ – verhindert Race Conditions, bei denen sich zwei Deployments gegenseitig überschreiben.
  • Konfiguration: Max in-flight deploys – Ganzzahl 0–100. 0 = keine Begrenzung.
  • Gezählt werden: die Zustände pending_gates, pending_approval und dispatched. Ein Versuch im Zustand completed oder failed zählt nicht mehr.

G. Cooldown nach einem Rollback

Sperrt nach einem Rollback Deployments für N Minuten, damit das Team untersuchen kann.

  • Wann sinnvoll: „nach einem Rollback 60 Minuten Pause erzwingen, bevor erneut deployt wird“ – verhindert, dass dieselbe Regression versehentlich wieder ausgelöst wird.
  • Konfiguration: Cooldown after rollback (minutes) – Ganzzahl 0–1440 (24 h). 0 = kein Cooldown.

H. Verknüpftes Ticket erforderlich

Verlangt, dass der Body des zu deployenden PR auf ein Issue- oder Incident-Ticket verweist.

  • Wann sinnvoll: Compliance- oder Audit-Trail-Anforderung – jedes Produktions-Deployment muss ein „Warum“ mitbringen.
  • Konfiguration: Require PR body to reference an issue/incident ticket ankreuzen. Optional die Regex unter Ticket pattern überschreiben.
  • Standardmuster: (?i)(JIRA|FF|INC|FIX)-[0-9]+|fixes? #[0-9]+|closes? #[0-9]+|resolves? #[0-9]+ – passt auf JIRA-1234, FF-99, fixes #42, Closes #99 usw. Das Präfix (?i) macht das Muster unabhängig von Groß- und Kleinschreibung.
  • Überschreibung pro Tenant: jede gültige JavaScript-Regex. Das Präfix (?i) wird beachtet.

I. Pause-Flag

Ein Schalter pro Umgebung, der alle Deployments anhält.

  • Wann sinnvoll: während eines Vorfalls. Pause setzen, untersuchen, aufheben.
  • Konfiguration: Pro Umgebung (Tenant-Admin): <org>/_admin/deployments → Abschnitt „Pause-Flags“. fremforge kann bei einem Vorfall zusätzlich eine plattformweite Pause setzen; jede aktive Pause, die deine Umgebung abdeckt, blockiert das Deployment.
  • Auflösung: Für das Begründungsfeld gewinnt der spezifischste Geltungsbereich, aber JEDER aktive Geltungsbereich blockiert das Deployment.

Ablauf einer Prüfung

Wenn die Plattform einen Workflow mit environment: <name> übernimmt:

  1. Preflight – fremforge sucht die Umgebung für den Tenant. Keine Umgebung konfiguriert = keine Gates (schrittweises Onboarding; die Workflows neuer Kunden werden nicht blockiert, bevor sie Umgebungen einrichten).
  2. Deploy-Versuch anlegen oder finden, mit dem Schlüssel (env, ref, commit_sha). Erneute Starts desselben Workflows für denselben Commit teilen sich denselben Versuch – ein Freigabeablauf bleibt also über Wiederholungen hinweg bestehen.
  3. Rahmendaten auflösen – E-Mail der auslösenden Person und PR-Body werden aus Forgejo gelesen. Nach bestem Bemühen; ist Forgejo beeinträchtigt, werden synthetische Werte verwendet.
  4. Alle 9 Gates parallel prüfen – jedes Gate ist unabhängig und liest sein eigenes Signal.
  5. Zusammenführen – bestehen ALLE konfigurierten Gates, wechselt der Status zu dispatched und die Runner-VM wird bereitgestellt. Schlägt NUR Gate A (Freigebende) fehl, wechselt der Status zu pending_approval – Admins können auf Freigeben klicken, die nächste Wiederholung prüft erneut. Schlägt ein anderes Gate fehl, wechselt der Status zu gates_failed.
  6. Audit – die vollständige Aufschlüsselung der Gate-Ergebnisse wird gespeichert und ein Audit-Ereignis ausgelöst.

So sieht ein abgelehntes Deployment aus

Kundenseitig: Der Workflow-Lauf wird abgebrochen, mit einer Commit-Statusprüfung, die den Ablehnungsgrund zeigt (z. B. deploy_gate_C_time_window — outside allowed windows).

Admins der Organisation sehen: eine Zeile unter Pending deployments mit der vollständigen Aufschlüsselung der Prüfung – welche Gates bestanden haben, welche fehlgeschlagen sind, mit dem jeweiligen reason-Text pro Gate.

Was in jeder Umgebung live ist

fremforge-Verwaltung → Deployments (https://frem.sh/<org>/_admin/deployments) beginnt mit Live je Umgebung. Für jede Umgebung siehst du das Deployment, das jetzt live ist, und das davor, also dein Ziel für ein Rollback:

  • Repository, Ref (Branch oder Tag) und Commit, verlinkt;
  • die Tags, die auf diesen Commit zeigen, zum Beispiel prd-2026-11-01 oder rc-81;
  • wer es freigegeben hat, und wann;
  • wann das Deployment abgeschlossen war, und ein Link zu seinem Workflow-Run.

Ein Deployment gilt nur dann als live, wenn sein Run gestartet wurde und erfolgreich endete. Fehlgeschlagene, abgebrochene, abgelehnte und noch wartende Versuche zählen nie. Nach einem fehlgeschlagenen Deployment steht also das vorherige weiter als live da. Eine Umgebung ohne erfolgreiches Deployment zeigt Nie deployt.

Release-Tools lesen dieselben Daten über die API, mit einem Token mit deployments:read, statt die Seite auszulesen:

curl -fsS "https://frem.sh/_app/api/v1/orgs/acme/deployments/live?environment=production" \
  -H "Authorization: Bearer $FREMFORGE_TOKEN"

Jede Umgebung in der Antwort hat live und previous. Beide sind null, bis dort etwas deployt wurde. Jeder Eintrag enthält repo_full_name, ref, commit_sha, commit_url, tags, approvals, deployed_at, run_number und run_url. Ohne ?environment= bekommst du alle Umgebungen. tags stammt aus den 150 neuesten Tags des Repositorys und kann bis zu eine Minute alt sein. Das Feld ist null (nicht []), wenn die Tags gerade nicht gelesen werden konnten.

Gates kombinieren

Die Stufen sind bewusst kombinierbar – die meisten Kunden konfigurieren 2–3 Gates pro Umgebung, nicht alle 9. Vorschläge für den Einstieg:

MusterKonfigurierte GatesBegründung
Einzelentwickler, eine UmgebungkeineFür ein Ein-Personen-Team sind keine Gates nötig; fremforge erlaubt standardmäßig „alle Branches“.
Kleines Team, ProduktionsumgebungB (refs=main) + I (Pause-Flag verfügbar)Verhindert versehentliche Deployments von Feature-Branches nach Produktion; die Bereitschaft hat den Notschalter.
Mittelgroßes Team, reguliertA (2 Reviewer) + B (refs=main, release/*) + H (verknüpftes Ticket) + IFreigabe + Audit-Trail + teamübergreifender Notschalter.
Unternehmen, mehrstufigA (3 Reviewer) + B + C (Geschäftszeiten) + D (SLO im grünen Bereich) + E (dep-scan + sast) + F (Parallelität=1) + G (60 Min. Cooldown) + H + IAlle Stufen; in dieser Größenordnung ist jedes Gate sinnvoll.

Fang klein an – füge Gates hinzu, wenn du wächst.

Secrets und Variablen pro Umgebung

Unabhängig von den Gates haben Umgebungen eigene Secrets und Variablen, die nur in Jobs mit environment: <name> eingespeist werden. Das Muster für den Umgang mit Secrets beschreibt Secrets.

Umgebungen über die API verwalten

Alles, was die Verwaltungsoberfläche kann, kann auch die REST-API. Umgebungen liegen im Namensraum fremforge-extension, die Basis-URL ist also https://frem.sh/_app/api/v1 – nicht das bloße /api/v1, das ist Forgejos eigene API und lehnt den Aufruf ab.

MethodePfadScope
GET/orgs/<org>/environmentsenvironments:read
POST/orgs/<org>/environmentsenvironments:write
GET/orgs/<org>/environments/<name>environments:read
DELETE/orgs/<org>/environments/<name>environments:write
PUT DELETE/orgs/<org>/environments/<name>/variables/<VAR>environments:write
GET/orgs/<org>/environments/<name>/secretsenvironments:read
PUT/orgs/<org>/environments/<name>/secrets/<NAME>environments:write
DELETE/orgs/<org>/environments/<name>/secrets/<id>environments:write
PUT/orgs/<org>/environments/<name>/gatesenvironments:write
PUT/orgs/<org>/environments/<name>/branchesenvironments:write
GET/orgs/<org>/deployments/livedeployments:read

Namen von Umgebungen entsprechen [A-Za-z0-9_.-]+ (kein /). Variablennamen entsprechen [A-Z][A-Z0-9_]*, Werte bis 64 KiB. Werte von Secrets werden verschlüsselt gespeichert und nie zurückgegeben – die Listen-Endpunkte liefern nur Namen und Metadaten.

# Create an environment, then give it a variable and a secret.
curl -fsS -X POST https://frem.sh/_app/api/v1/orgs/acme/environments \
  -H "Authorization: Bearer $FREMFORGE_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"staging"}'

curl -fsS -X PUT https://frem.sh/_app/api/v1/orgs/acme/environments/staging/variables/REGION \
  -H "Authorization: Bearer $FREMFORGE_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"value":"eu-de"}'

curl -fsS -X PUT https://frem.sh/_app/api/v1/orgs/acme/environments/staging/secrets/DEPLOY_KEY \
  -H "Authorization: Bearer $FREMFORGE_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"value":"…"}'
Ein Hinweis zum Feldnamen im Body. Umgebungsvariablen und Umgebungs-Secrets erwarten {"value": "…"}. Secrets auf Organisationsebene (PUT /orgs/<org>/secrets/<NAME>) sind mit {"data": "…"} dokumentiert und akzeptieren value zusätzlich als Alias, beide Schreibweisen funktionieren also. Schickst du beide, gewinnt data.

Wenn du ein 403 bekommst

403 Token lacks required scope 'environments:…' bedeutet, dass der Endpunkt existiert und dein Token den Scope nicht trägt – es ist keine fehlende Funktion. Prüfe, welche Scopes deine Anmeldedaten tatsächlich haben. Ein selbst erstelltes PAT trägt genau die Scopes, die du angekreuzt hast; eine Dev-Bench trägt einen von der Plattform ausgestellten Satz, der bewusst enger ist und beim Aufwachen der Bench erneuert wird.

OIDC-Claim für die Umgebung

Workflows mit environment: <name> erhalten einen zusätzlichen OIDC-Claim – sub wird zu repo:<owner>/<repo>:environment:<name>. Darauf prüfen Vertrauensrichtlinien in der Cloud bei kurzlebiger Föderation (AWS STS AssumeRoleWithWebIdentity, Azure WIF, GCP Workload Identity Federation). Die Formen der Vertrauensrichtlinien beschreibt OIDC-Föderation.

Fehlerbehebung

Der Workflow hängt bei „Review pending“, und es wurde keine Benachrichtigung verschickt. → Prüfe die Anzahl unter Required reviewers der Umgebung. Freigaben erfolgen auf der Verwaltungsseite Pending deployments; fremforge schickt Reviewern (noch) keine E-Mails. Nimm die Seite in die morgendliche Standup-Runde deines Teams auf.

Ein Deployment wurde mit deploy_gate_D_slo_burn abgelehnt, obwohl ich Gate D nicht konfiguriert habe. → Gate D schlägt geschlossen fehl, wenn fremforge für einen aufgeführten Alarm keinen aktuellen Zustand hat. Hast du einen Alarmnamen EINGETRAGEN, der nie einen Zustand gemeldet hat, lehnt das Gate automatisch ab. Entferne den Alarmnamen aus der Gate-Konfiguration oder sorge dafür, dass der Alarm so angebunden ist, dass sein Zustand gemeldet wird.

Der PR-Body passt auf ein Ticket-Muster, aber Gate H schlägt trotzdem fehl. → Der Deploy-Versuch wurde angelegt, BEVOR der PR eröffnet wurde. fremforge erfasst den PR-Body bei der ersten Prüfung und ruft ihn nicht erneut ab. Pushe einen leeren Commit, um eine neue Prüfung auszulösen.

Ich möchte die Gates vorübergehend umgehen. → Eine Umgehung pro Tenant in der Oberfläche gibt es noch nicht. Wende dich an support@frem.sh, um ein Gate vorübergehend zu umgehen. Die Geltungsbereiche der Pause-Flags sind reine Schalter für aufgehoben/aktiv.

Audit-Ereignisse

Jede Gate-Entscheidung erzeugt strukturierte Audit-Ereignisse:

EreignisWann
environment.gates.updateTenant-Admin ändert die Gate-Konfiguration
tenant.deploy.approval_grantedFreigebende Person klickt auf Freigeben
tenant.deploy.approval_rejectedFreigebende Person klickt auf Ablehnen (mit Begründung)
tenant.deploy.approval_revokedFreigebende Person widerruft ihre eigene Freigabe
tenant.deploy.pause_set / _clearedPause-Flag pro Umgebung umgeschaltet (Tenant-Admin)
platform.deploy.pause_set / _clearedPlattformweites Pause-Flag umgeschaltet