Workflow-Lauf mit einer Freigabe, einem Delay-Knoten und Lauf-Variablen

Semaphore UI 2.20 ergänzt ein Audit-Log mit SIEM-Export, baut Workflows zu einer echten Pipeline-Engine mit Delay-Knoten, Revisionen, zwischen Aufgaben übergebenen Outputs und Workflow-Variablen aus, überarbeitet Rollen so, dass ein Mitglied mehrere davon halten kann und Administratoren instanzweite Rollen sowie IdP-Gruppen-Mappings erhalten, führt die Host-Konfiguration für SSH- und Git-Zugangsdaten pro Host ein, verlagert jede zusätzliche Ansible-Variable in Vault-verschlüsselte Dateien und stellt Prometheus-Metriken bereit.

Die Linie beginnt mit v2.20.0. Patch-Releases werden am Ende dieser Seite aufgeführt, sobald sie erscheinen.

Highlights

  • Audit-Log — wer hat was, von wo und mit welchem Ergebnis getan; ein Admin-Bildschirm, Aufbewahrungsfristen und Export per Syslog / Splunk HEC an SIEMs (Export und Filter in Pro).
  • Workflows — Delay-Knoten, unveränderliche Revisionen, die an Läufe gebunden sind, Outputs, die als Inputs der nächsten Aufgabe geliefert werden, Workflow-Variablen, die in einem Run-Dialog abgefragt werden, ein neu gestalteter Editor mit Hotkeys und Undo sowie Webhooks, die Workflows starten.
  • Mehrere Rollen pro Mitglied, Rollen mit IDs und Slugs, globale Rollen mit instanzweiten Berechtigungen (Pro) und IdP-Gruppen → Rollen-Mappings, die bei der Anmeldung angewendet werden (Enterprise).
  • Externe Identitäten — LDAP- und OIDC-Anmeldungen werden über die stabile ID des Anbieters an Konten gebunden, nicht über die E-Mail-Adresse; mehrere LDAP-Verzeichnisse auf einer Anmeldeseite.
  • Host-Konfiguration — SSH-Hosts und Git-URLs auf Projekt-Zugangsdaten abbilden, angewendet auf Clones, Galaxy, Terraform-Module und Ansible.
  • Zusätzliche Ansible-Variablen stehen nie mehr auf der Kommandozeile; Secrets werden in einer mit Ansible Vault verschlüsselten Datei übertragen, und Jinja2 in Werten wird nicht mehr ausgewertet.
  • Vorlagen: Ansible-Arbeitsverzeichnis, eindeutige Namen und template_name in der Task-API, unterdrückte Fehlerbenachrichtigungen, ausgeblendetes Dry Run / Diff, Galaxy-Installationsoptionen, Survey-Variablen mit Mehrfachauswahl, Survey-Secrets auf entfernten Runnern.
  • Monorepo-Repositories teilen einen Checkout zwischen Vorlagen; Git-Wiederholungsversuche, paralleles Abrufen von Submodulen, Prüfung von SSH-Host-Keys.
  • Prometheus-Metriken unter /api/metrics.
  • SSH-Schlüsselpaare auf dem Server erzeugen und den öffentlichen Schlüssel aus dem Key Store kopieren.

Audit-Log

Audit-Log-Bildschirm

Semaphore zeichnet sicherheitsrelevante Ereignisse jetzt in einem dedizierten Log auf, das nur angefügt wird. Aktivieren mit:

"audit": {
  "enabled": true,
  "instance_id": "semaphore-prod"
}

(SEMAPHORE_AUDIT_ENABLED, SEMAPHORE_AUDIT_INSTANCE_ID; instance_id ist erforderlich und benennt die Installation in jedem Ereignis.)

Was aufgezeichnet wird. 116 Ereignisarten in acht Kategorien: auth (Anmeldungen, Abmeldungen, MFA, abgewiesene API-Token, abgelehnte Anfragen, CSRF-Blockaden), iam (Benutzer, Passwörter, API-Token, Identitäten, Mitgliedschaften, Rollen, Vorlagenberechtigungen), resource (Projekte, Backups, Inventare, Repositories, Vorlagen, Zeitpläne, Integrationen, Host-Konfigurationen, Workflows, Variablengruppen), secret (Zugangsdaten und Secret-Speicher), task (Start mit Auslöser, Abschluss mit Ergebnis und Dauer, Freigaben, Stopps, Löschen der Historie), runner (Registrierung, Änderungen, abgewiesene Meldungen), system (Einstellungen, Lizenz) und audit selbst (Start, Aufbewahrung, Export). Passwörter, Token, Secret-Werte, Aufgabenausgaben und Variablen werden niemals geschrieben.

Ereignis-Envelope. Jedes Ereignis trägt eine UUID, eine lückenlose Sequenznummer, einen UTC-Zeitstempel mit Mikrosekunden, den Akteur (Benutzer / anonym / System / Runner / Integration, mit Session- oder API-Token-Authentifizierung und einem Token-Fingerprint), die Quell-IP und den User-Agent, das Ziel, das Projekt, eine Request-ID (die auch im Antwort-Header X-Request-ID zurückgegeben wird), die Instanz-ID und die HA-Knoten-ID. Die Ergebnisse sind success oder failure mit einer abgeschlossenen Liste von Gründen; eine Aktion, die das Objekt gespeichert hat, aber bei einem späteren Schritt gescheitert ist, gilt als Erfolg mit partial = true. Hinter einem Reverse-Proxy wird X-Forwarded-For nur aus audit.trusted_proxy_cidrs als vertrauenswürdig behandelt.

Karte eines Audit-Ereignisses

Admin-Bildschirm. Audit-Log im Benutzermenü (/audit-log) listet Ereignisse mit den neuesten zuerst auf, 50 pro Seite, mit Älter / Neuer zum Blättern; eine Zeile öffnet eine Karte mit den Abschnitten Wer, Objekt, Wo, Wann, Details und Technisch sowie einer Schaltfläche, die das Ereignis als das JSON kopiert, das an ein SIEM gesendet wird. Der Zugriff erfordert die neue globale Berechtigung Audit-Log lesen.

Aufbewahrung. audit.retention_days löscht ältere Ereignisse in Stapeln, stündlich mit Jitter, damit HA-Knoten nicht kollidieren; jeder Durchlauf, der etwas löscht, wird selbst aufgezeichnet.

Pro: Filter und Export. Nach Zeitraum, Benutzer, Projekt, Ereignisart, Ergebnis und IP filtern; von jedem Kartenwert aus weiterfiltern; die aktuelle Auswahl als CSV oder JSON Lines exportieren.

Pro: SIEM-Export. Zwei Ziele, jedes mit eigenem Cursor, sodass nichts übersprungen wird, wenn ein Empfänger ausfällt: Syslog über TLS (RFC 5424, das Ereignis-JSON als Body) über audit.syslog und Splunk HTTP Event Collector über audit.splunk_hec (url, token, index, source, sourcetype, ca_file, …). Die Zustellung erfolgt mindestens einmal, geordnet nach Sequenz; in einer HA-Umgebung exportiert nur ein Knoten pro Ziel, koordiniert über ein Redis-Lease. Drei Prometheus-Serien beschreiben den Exporter: semaphore_audit_export_pending_events, semaphore_audit_export_oldest_pending_seconds und semaphore_audit_export_errors_total.

Speicherung: Tabellen audit_event, audit_event_sequence, audit_export_state (Migrationen v2.20.9 bis v2.20.11). API: GET /api/audit/events und GET /api/audit/events/export.


Workflows

Workflows sind eine Pro-Funktion; das Beta-Label ist entfallen.

Delay-Knoten

Eine vierte Knotenart neben Aufgabe, Freigabe und Notiz: Delay pausiert den Lauf für eine Anzahl von Sekunden und gibt dann seine Kanten frei. Die Laufansicht zeigt einen laufenden Countdown auf der Karte; ein gestoppter Lauf bricht das Delay ab. Feld delay_seconds, Migration v2.20.2.

Revisionen

Jedes Speichern eines Workflows erzeugt eine neue Revision des Graphen; ein Lauf fixiert die Revision, mit der er gestartet ist, sodass das Bearbeiten eines Workflows einen laufenden Lauf nie verändert und die Knoten vergangener Läufe nie verwaisen lässt. Der Editor zeigt einen rev. N-Chip und wie viele Läufe noch eine ältere Revision ausführen; die Laufansicht zeigt, welche Revision sie ausführt. Revisionen, auf die kein Lauf verweist, werden gelöscht, sobald eine neuere gespeichert wird. API: GET …/workflows/{id}/revisions und …/revisions/{revision_id}.

Outputs und Inputs

Laufansicht mit Output-Badges

Eine Aufgabe kann strukturierte Daten an die ihr nachfolgenden Knoten übergeben. Jede von einem Workflow gestartete Aufgabe erhält SEMAPHORE_OUTPUTS_FILE; was sie dort als JSON-Objekt schreibt, wird zu ihren Outputs:

cat > "$SEMAPHORE_OUTPUTS_FILE" <<EOF
{"image_tag": "1.4.2", "replicas": 3, "subnet_ids": ["subnet-1", "subnet-2"]}
EOF

Ansible erzeugt Outputs mit ansible.builtin.set_stats über ein mitgeliefertes Callback-Plugin; Outputs von Terraform, OpenTofu und Terragrunt werden automatisch aus output -json erfasst (sensitive-Werte werden übersprungen und als Not captured aufgeführt). Outputs werden nur gelesen, wenn die Aufgabe erfolgreich ist; die Grenzen liegen bei 100 Outputs, je 32 KB und 256 KB pro Datei.

Eine Verbindung in einen Aufgabenknoten liefert Inputs — sie füllt die Survey-Variablen der Zielvorlage aus den Outputs des Quellknotens:

  • Nach Name (Standard): jeder Output, dessen Name einer Survey-Variablen entspricht, füllt diese.
  • Inputs explizit zuordnen: die zu liefernden Paare variable ← output key auflisten; sobald der Workflow einen abgeschlossenen Lauf hat, schlägt das Panel die Keys vor, die dieser Lauf erzeugt hat.

Verbindungspanel mit explizitem Input-Mapping

Werte werden auf den Variablentyp konvertiert, Freigabe- und Delay-Knoten geben Outputs weiter, ein explizites Mapping gewinnt gegenüber einer Lieferung nach Name, und eine erforderliche Variable ohne Wert lässt die Aufgabe des Knotens schon vor dem Start fehlschlagen, sodass der Lauf seinen Bei Fehler-Kanten folgt. Die Laufansicht zeigt pro Knoten ein N outputs-Badge, der Aufgabendialog hat eine Outputs-Tabelle, und das Aufgabenlog beginnt mit einer Zeile Input "x" <- output "y" of node N pro geliefertem Wert. Outputs werden im Klartext gespeichert und füllen nie eine secret-Variable; ein secret kann nicht über Outputs weitergegeben werden. Aufgaben auf entfernten Runnern erzeugen und empfangen Outputs; die Docker- und Kubernetes-Executoren erfassen sie noch nicht.

Aufgabendialog mit der Outputs-Tabelle

Workflow-Variablen und der Run-Dialog

Run-Dialog fragt Workflow-Variablen ab

Ein Workflow hat eigene Survey-Variablen, die beim Start eines Laufs einmal in einem Run “…”-Dialog abgefragt werden (ein Workflow ohne Variablen startet wie bisher sofort). Die Antworten werden am Lauf gespeichert, als Chips in einer Variablen-Leiste über der Lauf-Arbeitsfläche angezeigt und erreichen eine Aufgabe nur über eine explizite Bindung im Knotenpanel — eine Workflow-Variable gelangt nie über ihren Namen in eine Vorlage. Secrets sind als Workflow-Variablen nicht erlaubt. POST …/workflows/{id}/runs akzeptiert {"environment": {"image_tag": "1.4.3"}}; eine Antwort, die nicht zu ihrem Typ passt, oder ein fehlender erforderlicher Wert verhindert den Start.

Umgebung einer Workflow-Aufgabe

Jede von einem Workflow gestartete Aufgabe erhält SEMAPHORE_WORKFLOW_ID, SEMAPHORE_WORKFLOW_RUN_ID, SEMAPHORE_WORKFLOW_URL (benötigt web_host) und SEMAPHORE_OUTPUTS_FILE, für jede App und auch auf entfernten Runnern.

Neu gestalteter Editor

Workflow-Editor

  • Neue Knotenkarten mit Art-Kachel, Status, Dauer, Outputs-Badge und integriertem Genehmigen / Ablehnen; Kantenbeschriftungen mit einem Dropdown für die Bedingung direkt an der Kante und einer Löschschaltfläche; eine Arbeitsfläche mit Punktraster.
  • Schnell-Hinzufügen-Menü über den +-Anschluss eines Knotens, einen Rechtsklick auf die Arbeitsfläche oder die Schaltfläche im Leerzustand: durchsuchbare Liste von Knotenarten und Aufgabenvorlagen, der neue Knoten wird bei Erfolg verbunden.
  • Undo / Redo (Ctrl/⌘+Z, Ctrl/⌘+Shift+Z), Umbenennen des Workflows direkt an der Stelle, ein Probleme-Menü, das den betroffenen Knoten fokussiert, ein Speichern-Badge für nicht gespeicherte Änderungen und eine Warnung beim Verlassen der Seite.
  • Hotkeys auf der Arbeitsfläche: Pfeiltasten verschieben (Shift für einen großen Schritt), + / - zoomen, 0 passt den Graphen ein, 1 setzt den Zoom zurück, Esc hebt die Auswahl auf; Knotenkarten sind per Tastatur fokussierbar.
  • Schwebende Steuerelemente: hinein- / herauszoomen, Ansicht einpassen, Tidy up-Autolayout, Zoom-Prozentsatz.
  • Ein Chevron klappt die Palette und die Hauptnavigation gemeinsam ein; der Zustand wird gemerkt.
  • Überscrollen mit dem Trackpad löst unter macOS nicht mehr die Zurück-Gestur des Browsers aus.

Schnell-Hinzufügen-Menü

Webhooks starten Workflows

Eine Integration kann jetzt einen Workflow statt einer Vorlage ausführen (Runs: Template / Workflow im Integrationsformular). Jeder extrahierte Wert wird zu einer Antwort auf das Survey des Workflows. Das Verwalten solcher Integrationen erfordert die Pro-Funktion workflow_integrations_management. Bei Vorlagen-Integrationen setzt ein extrahierter Task Params-Wert mit dem Namen git_branch den Branch der gestarteten Aufgabe, sofern die Vorlage das Überschreiben erlaubt.

API-Änderungen

POST …/workflows/{id}/run wurde in POST …/workflows/{id}/runs umbenannt und akzeptiert den environment-Body. Die Laufdetails enthalten revision_id, revision, ein delay-Objekt pro Knoten und task.artifacts. Vom Client gelieferte Werte für workflow_run_id, workflow_node_id und artifacts an einer Aufgabe werden ignoriert, sodass eine Aufgabe sich nicht als Knoten eines fremden Laufs ausgeben kann.


Rollen und Zugriffskontrolle

Mehrere Rollen pro Mitglied

Team-Seite mit mehreren Rollen pro Mitglied

Ein Projektmitglied hält einen Satz von Rollen, der auf der Team-Seite als Chips bearbeitet wird. Die API akzeptiert roles: ["manager", "release_approver"] neben dem bisherigen role; die Antwort behält das skalare role nur für Mitglieder mit einer einzigen Rolle. Ein Nicht-Administrator kann dem letzten Eigentümer die integrierte Rolle Owner nicht entziehen.

Rollen mit IDs, Slugs und Scopes

Rollen sind jetzt Datensätze mit einer ganzzahligen id und einem slug (^[A-Za-z0-9_-]{1,100}$, im Formular aus dem Namen abgeleitet); auch die vier integrierten Rollen sind Datensätze und können nicht mehr von einer eigenen Rolle überdeckt werden. Rollen haben einen Scope: integriert, geteilt (in jedem Projekt nutzbar) oder projektbezogen. Das Löschen einer Rolle, die in Verwendung ist, antwortet mit 409 samt ihrer Auswirkung (Mitglieder, Projekte, Vorlagenberechtigungen, Mappings) und kann mit ?force=true wiederholt werden — Mit Zuweisungen löschen in der UI. Die Migrationen v2.20.12 und v2.20.13 bauen die Rollentabellen neu auf; siehe die Hinweise zum Upgrade.

Globale Rollen und Berechtigungen (Pro)

Tab für globale Rollen auf der Benutzerseite

Instanzweite Rechte bestehen nicht mehr nur aus dem Admin-Flag. Eine globale Rolle gewährt eine Maske aus vier Berechtigungen — Benutzer verwalten, Globale Rollen verwalten, Systemeinstellungen verwalten, Audit-Log lesen — und wird Benutzern im Tab Rollen der Benutzerseite (/users/roles) sowie im Tab Globale Rollen des Benutzerdialogs zugewiesen, der auch die effektiven Berechtigungen und die jeweils gewährende Rolle anzeigt. Jede Admin-Route wird durch eines der vier Bits geschützt; GET /api/user liefert global_permissions. Eine Instanz behält immer mindestens einen Administrator, erzwungen mit einem Row-Lock, der auch über HA-Knoten hinweg sicher ist. Ein Benutzer mit Benutzer verwalten kann keinen Administrator und niemanden bearbeiten, der eine Berechtigung hält, die ihm selbst fehlt. API: /api/global-roles, /api/users/{id}/global-roles, /api/users/{id}/global-permissions, Katalog unter /api/global-roles/permissions.

Globale Rollen eines Benutzers

Gruppen-Rollen-Mappings (Enterprise)

Seite für Gruppen-Mappings

Auf der neuen Seite Gruppen-Mappings (/role-mappings) wird eine Gruppe des Identitätsanbieters auf eine Projektrolle abgebildet: Anbieter, Gruppe, Projekt, Rolle. Bei jeder OIDC-Anmeldung werden die zugeordneten Rollen des Benutzers an die Gruppen im Token angeglichen (groups_claim des Anbieters). Zugeordnete Rollen erscheinen auf der Team-Seite als gesperrte Chips mit einem provider: group-Tooltip und können nicht als Mitgliedsrollen entfernt werden; zugeordnete Rollen zählen nicht als letzter Eigentümer des Projekts. Eine Anmeldung per Passwort oder LDAP löscht zugeordnete Rollen, weil sie keine Gruppen mitbringt. API: /api/role_mappings.


Authentifizierung und Identitäten

Anmeldeseite mit mehreren LDAP-Verzeichnissen

  • Externe Identitäten. LDAP- und OIDC-Anmeldungen werden über die stabile ID des Anbieters (OIDC sub, LDAP DN) in der neuen Tabelle user__external_identity an Semaphore-Konten gebunden, nicht über die E-Mail-Adresse. Damit ist die Fehlerklasse geschlossen, bei der ein IdP, der jede eingegebene Adresse akzeptiert, das Konto einer anderen Person übernimmt. external_auth_email_matching (Standard auto, always, never) steuert, ob ein bestehender externer Benutzer ohne Identität einmalig noch über die E-Mail-Adresse zugeordnet werden darf; lokale Passwortkonten werden niemals übernommen. Eine OIDC-E-Mail-Adresse zählt nur bei email_verified, wenn der Anbieter require_verified_email setzt. Benutzer verknüpfen und lösen Identitäten selbst im Kontodialog (/api/users/{id}/identities, POST /api/user/identities/ldap, /api/auth/oidc/{provider}/login?link=1).
  • Mehrere LDAP-Verzeichnisse. ldap_providers ist eine Map benannter Verzeichnisse, jedes mit eigenem Server, Bind, Suche, Mappings, Farbe und Reihenfolge; der bisherige flache ldap_*-Block funktioniert weiter als Anbieter ldap. Die Anmeldeseite zeigt einen Umschalter, wenn es mehr als einen Tab gibt, und der interne Tab sendet nie ein Passwort an ein Verzeichnis. GET /api/auth/login liefert ldap_providers und login_with_password.
  • LDAPS-Zertifikate werden standardmäßig geprüft. Setzen Sie ldap_tls_skip_verify (flacher Block) oder tls_skip_verify (pro Anbieter) für ein selbst signiertes Zertifikat.
  • Absolute Session-Lebensdauer. auth.max_session_life_hours (SEMAPHORE_AUTH_MAX_SESSION_LIFE_HOURS) lässt eine Session eine feste Zeit nach der Anmeldung ablaufen, unabhängig von ihrer Aktivität; 0 behält nur das Inaktivitäts-Timeout.
  • Ein Benutzer ohne Projekte, der keines anlegen darf, sieht eine Seite Noch keine Projekte statt eines Formulars, das er nicht abschicken kann; POST /api/projects antwortet in diesem Fall mit 403.
  • Die im Benutzermenü gewählte Sprache wird auf dem Server gespeichert und folgt dem Benutzer über Browser hinweg (lang in /api/user/options).

Host-Konfiguration

Seite für die Host-Konfiguration

Eine neue Projektseite, Host-Konfiguration, bildet SSH-Hosts und Git-URLs auf Projekt-Zugangsdaten ab:

  • ein Host-Mapping (bastion.example.com) hängt einen SSH-Schlüssel an, als Host-Block einer generierten ssh_config;
  • ein URL-Mapping (https://github.com/acme/, ein auf / endendes Präfix deckt eine Gruppe ab) hängt einen SSH-Schlüssel oder ein Login/Passwort an (nur HTTPS), als Git-insteadOf-Umschreibung; die spezifischste URL gewinnt.
Formular für ein Host-Mapping

Mappings gelten für das Vorlagen-Repository und seine Submodule, für Rollen und Collections aus requirements.yml, für terraform init-Module, für Git-Befehle, die ein Playbook ausführt, für Inventar-Repositories und Inventar-Hosts sowie für das Durchsuchen von Branches und Playbooks; sie werden an entfernte Runner ausgeliefert. Private Schlüssel landen nie auf der Festplatte — ein SSH-Agent pro Mapping, gebunden über IdentityAgent; Passwörter laufen über GIT_CONFIG_PARAMETERS, und Repository-URLs werden in Aufgabenlogs redigiert. Ein Schlüssel, auf den ein Mapping verweist, kann nicht gelöscht werden. Mappings sind Teil der Projekt-Backups. Erfordert git_client: cmd_git. Tabelle project__host_config, Migration v2.20.7; API /api/project/{id}/host_configs.


Vorlagen und Aufgaben

Vorlagenformular mit Arbeitsverzeichnis und Benachrichtigungsoptionen

  • Ansible-Arbeitsverzeichnis. Abweichendes Arbeitsverzeichnis führt ansible-playbook aus einem Unterverzeichnis des Repositorys aus; der Pfad muss innerhalb des Checkouts bleiben (working_directory, Migration v2.20.3).

  • Eindeutige Vorlagennamen pro Projekt (Migration v2.20.4), und POST /api/project/{id}/tasks akzeptiert template_name anstelle von template_id.

  • Fehlerbenachrichtigungen unterdrücken pro Vorlage, neben der bestehenden Unterdrückung von Erfolgsmeldungen; E-Mail-Alerts beachten erstmals beide (suppress_error_alerts, Migration v2.20.5).

  • Dry Run / Diff ausblenden im Aufgabendialog pro Vorlage; der Server hängt für diese Vorlage dann auch kein --check / --diff mehr an (task_params.hide_dry_run, hide_diff).

  • Galaxy-Installationsoptionen — ein einklappbarer Abschnitt mit Galaxy-Installation überspringen, separaten CLI-Argumenten für ansible-galaxy role install und collection install (eine Allowlist von Flags; --token, --api-key und Pfad-Flags werden abgewiesen) sowie der Abfrage zum Überschreiben pro Aufgabe.

  • Die Playbook-Auswahl listet Unterverzeichnisse schon während der Eingabe auf, gefiltert pro App (.yml für Ansible, Verzeichnisse der obersten Ebene für Terraform / OpenTofu / Terragrunt / Pulumi, .sh, .py, .ps1), überspringt Ansible-Layout-Verzeichnisse und Punkt-Verzeichnisse, ist auf 30 Einträge begrenzt und durchsucht einen Shallow Clone, der auf das Repository-Wurzel beschränkt ist.

  • Survey-Variablen mit Mehrfachauswahl — der neue Typ select akzeptiert mehrere Werte, im Aufgabendialog als Chips dargestellt; default_value darf ein Array sein.

    Dialog für neue Aufgabe mit einer Survey-Variablen mit Mehrfachauswahl
  • Survey-Secrets erreichen entfernte Runner. Eine secret-Survey-Antwort kam auf einem Runner bisher leer an. Sie wird jetzt verschlüsselt als aufgabengebundener Access Key gespeichert (access_key.task_id, expire_at, Migration v2.20.1), von demjenigen HA-Knoten entschlüsselt, der den Runner bedient, beim Ende der Aufgabe gelöscht und stündlich aufgeräumt; im Key Store, in Backups und in der Keys-API ist er verborgen.

  • Zusätzliche Variablen als YAML. Der Editor für Variablengruppen hat einen Umschalter Tabelle | JSON | YAML und einen Vollbildeditor erhalten; die Konvertierungen sind streng (Datumsangaben bleiben Strings, Nicht-Objekt-Wurzeln und nicht endliche Zahlen werden abgewiesen). Die Speicherung ist unverändert.

    Editor für Variablengruppen im YAML-Modus

  • Die Aufgabenseite benennt und verlinkt den Zeitplan oder die Integration, die eine Aufgabe gestartet hat, und markiert einen gelöschten Ursprung als #id (deleted). Log-Zeitstempel werden beim Kopieren eines Logs nicht mehr mit ausgewählt.

  • Zeitpläne validieren den Ausdruck vor dem Speichern auf dem Server, sodass @hourly akzeptiert wird, und das Zeitzonen-Banner lässt sich schließen.

    Formular für Zeitpläne
  • Das Stoppen einer lokalen Aufgabe beendet ihre gesamte Prozessgruppe: SIGTERM, eine Gnadenfrist von 15 s, dann SIGKILL; verwaiste ssh- oder Provider-Prozesse überleben die Aufgabe nicht mehr. Ein gestoppter Terraform-Plan läuft nicht weiter; ein Plan, der bei SIGTERM mit 0 endet, wird nicht als Erfolg gelesen.

  • Das repository_id eines Inventars wird nur noch für den Typ file beibehalten und muss zum Projekt gehören.

  • Serverlogs benennen den Benutzer in den Einträgen Task added to queue / Task started.


Secrets und Ansible Vault

  • Zusätzliche Variablen werden in Dateien übertragen, nicht auf der Kommandozeile. Variablengruppen, Survey-Antworten, Workflow-Inputs und Aufgabendetails werden in eine 0600-YAML-Datei geschrieben, die als --extra-vars @file übergeben wird. Secrets — secret-Survey-Antworten und Secrets aus Variablengruppen — landen in einer zweiten Datei, die im Format Ansible Vault 1.1 / AES-256 verschlüsselt ist, durch eine native Go-Implementierung (kein ansible-vault-Binary nötig), entsperrt mit einem Einmal-Passwort, das auf --vault-id <uuid>@prompt von ansible-playbook geantwortet wird. Weder die Werte noch das Passwort erscheinen in ps, und beide Dateien werden beim Ende der Aufgabe entfernt.

  • Jinja2 in Werten ist Daten, nicht Code. Jeder String, der {{, {%, {# oder einen #jinja2:-Header enthält, wird rekursiv als !unsafe markiert, sodass eine Survey-Antwort wie {{ lookup('pipe', 'id') }} wörtlich übergeben wird. Strings ohne Delimiter bleiben absichtlich unmarkiert: ansible-core ≥ 2.19 löst !unsafe-Skalare erneut auf, was "2026.08" in eine Fließkommazahl verwandeln würde.

  • Ein neuer Debug-Namensraum extra_vars (SEMAPHORE_DEBUG_FILTER=extra_vars) protokolliert, wie Variablen aufgeteilt und geschrieben werden — nur Namen, Dateien und Größen, niemals Werte.

  • Ein SSH-Schlüsselpaar auf dem Server erzeugen. SSH-Schlüssel erzeugen im Key Store erstellt einen RSA-Schlüssel; der öffentliche Schlüssel wird beim Schlüssel gespeichert, mit Anzeigen / Verbergen und einer Kopierschaltfläche dargestellt und direkt nach dem Erstellen in einem Dialog angeboten (generate_ssh_key).

    Schlüssel mit einem erzeugten SSH-Schlüsselpaar
  • Eine Schlüsselaktualisierung schreibt type, secret und den öffentlichen Teil nur, wenn Override gesetzt ist; ein Client kann die Nutzlast eines Schlüssels also nicht ändern, ohne das Secret zu ersetzen.

  • Das Lesen von Zugangsdaten aus einer Umgebungsvariablen des Servers oder einer Datei unter dirs.secrets ist jetzt dokumentiert (Tabs Env / File im Formular des Key Store).


Repositories und Git

Repository-Formular mit der Option für einen einzelnen Checkout
  • Monorepo: ein einzelner Checkout für alle Vorlagen. Eine Repository-Option klont das Repository einmal und teilt es zwischen den Vorlagen, anstatt eine Kopie pro Vorlage anzulegen; der Checkout wird für Fetch und Pull gesperrt, Aufgaben laufen danach parallel. Vorlagen eines solchen Repositorys können keinen eigenen Branch haben, und ihre Aufgaben können Branch oder Commit nicht überschreiben (monorepo, Migration v2.20.11).
  • Git-Wiederholungsversuche. clone und pull werden mit exponentieller Verzögerung wiederholt, begrenzt auf eine Minute; git_attempts (SEMAPHORE_GIT_ATTEMPTS, Standard 4).
  • Parallele Submodule. git_submodule_jobs (SEMAPHORE_GIT_SUBMODULE_JOBS, Standard 4) wird als --jobs übergeben.
  • Prüfung von SSH-Host-Keys. Neuer ssh-Abschnitt: config_path, known_hosts_file (SEMAPHORE_SSH_KNOWN_HOSTS_FILE) und strict_host_key_checking — no (Standard), yes oder accept-new — angewendet auf Git über SSH.
  • Das Durchsuchen eines Repositorys verwendet einen Shallow Clone pro Branch; Zugangsdaten werden für Bare-Metal-Clones prozentkodiert und in Logs sowie im Ereignis-Feed redigiert.

Runner und Integrationen

  • runner.check_interval_seconds (SEMAPHORE_RUNNER_CHECK_INTERVAL_SECONDS, Standard 5) legt fest, wie oft ein Runner abfragt; ein Schalter Erweiterte Optionen auf der Runner-Seite übernimmt den Wert in die generierten Env-, Konfigurations- und Docker-Snippets (ausgeliefert in v2.19.17).

  • runner.connection.timeout_seconds (SEMAPHORE_RUNNER_CONNECTION_TIMEOUT_SECONDS, Standard 3) begrenzt Verbindungsaufbau, TLS-Handshake und Antwort-Header separat; Log-Uploads werden nicht abgeschnitten.

  • runners.default_global_runners_mode (SEMAPHORE_DEFAULT_GLOBAL_RUNNERS_MODE: disable, prefer, require) ersetzt das veraltete use_remote_runner; runners.registration_token ersetzt das runner_registration_token auf oberster Ebene.

  • Serverseitige Runner-Diagnostik unter SEMAPHORE_DEBUG_FILTER=runner: Gründe für abgewiesene Token, Erkennung von Neustart und Online-Status, abgewiesene Fortschrittsmeldungen, Dispatch-Tracing.

  • unregister-Anfragen eines Runners werden authentifiziert; der Runner-Client verweigert HTTP-Redirects.

  • HMAC-SHA512 zur Webhook-Authentifizierung (hmac-sha512) neben dem bestehenden HMAC-SHA256; der Signatur-Header ist konfigurierbar.

    Integrationsformular mit HMAC-SHA512
  • Ein Webhook, dessen Integration zu einem anderen Projekt gehört, wird abgewiesen.


Observability

  • Prometheus-Metriken. GET /api/metrics hinter HTTP Basic Auth mit statischen Dienst-Zugangsdaten:

    "metrics": { "enabled": true, "username": "prometheus", "password": "…" }
    

    (SEMAPHORE_METRICS_ENABLED, SEMAPHORE_METRICS_USERNAME, SEMAPHORE_METRICS_PASSWORD.) Serien: semaphore_tasks_running, semaphore_tasks_total{status}, die Standard-Collectors go_* und process_* sowie die Audit-Export-Gauges in Pro.

  • Neue Debug-Namensräume extra_vars und runner; das Durchsuchen von Repositories protokolliert die Git-Ausgabe auf DEBUG.

  • Export und Wiederherstellung von Projekt-Backups werden protokolliert.


Sicherheit

  • Identitätsverknüpfung über die Anbieter-ID statt über die E-Mail-Adresse; Prüfung von LDAPS-Zertifikaten standardmäßig aktiv.
  • Zusätzliche Variablen nicht mehr auf der Kommandozeile; Secrets Vault-verschlüsselt; Jinja2 in Werten wird nicht ausgewertet.
  • Gefälschte workflow_run_id, workflow_node_id und artifacts werden aus Client-Aufgaben entfernt.
  • Admin-Routen werden durch explizite globale Berechtigungen statt durch das Admin-Flag geschützt; unbekannte Berechtigungsbits werden abgewiesen; Schutz vor Rechteausweitung in der Benutzerverwaltung.
  • Die Playbook-Auswahl ist auf das Repository-Wurzel beschränkt (OpenRoot), begrenzt und gefiltert.
  • Wurzeln von zusätzlichen Variablen und YAML-Zahlen werden validiert; Galaxy-CLI-Argumente stehen auf einer Allowlist.
  • Repository-Zugangsdaten werden in Logs und im Ereignis-Feed redigiert; = wird in Git-Konfigurationsparametern escaped.
  • Audit-Endpunkte verweigern Cross-Site-Lesezugriffe und fehlerhafte Cursor; Netze vertrauenswürdiger Proxys werden validiert.
  • Runner-unregister wird authentifiziert; Redirects werden vom Runner-Client verweigert.
  • Projekt- und Integrations-IDs von Webhooks werden geprüft.
  • Lokale Aufgaben werden mit ihrer gesamten Prozessgruppe gestoppt.

Hinweise zum Upgrade

Breaking Changes und Verhaltensänderungen

  1. Vorlagennamen müssen pro Projekt eindeutig sein. Migration v2.20.4 fügt einen eindeutigen Index hinzu; benennen Sie Duplikate vor dem Upgrade um.
  2. Die Rollentabellen werden neu aufgebaut (v2.20.12 / v2.20.13). Sichern Sie vorher. Eine eigene Rolle, deren Slug ohne Beachtung der Groß-/Kleinschreibung mit einer integrierten oder einer anderen Rolle kollidiert, wird umbenannt (protokolliert); Vorlagenberechtigungen, die auf eine nicht auflösbare Rolle verweisen, werden entfernt (protokolliert). Die Mitgliedschaft ist nach project__user_role umgezogen; die Spalte project__user.role ist entfallen.
  3. GET /api/project/{id}/users liefert role nur für Mitglieder mit einer einzigen Rolle — lesen Sie roles.
  4. /roles* ist umgezogen vom Admin-Flag zur Berechtigung Globale Rollen verwalten; Administratoren sind nicht betroffen.
  5. LDAPS-Zertifikate werden standardmäßig geprüft. Setzen Sie ldap_tls_skip_verify oder das tls_skip_verify eines Anbieters für selbst signierte Zertifikate.
  6. ansible-playbook wird anders aufgerufen: --extra-vars @file, plus eine zweite Datei und ein --vault-id <uuid>@prompt, wenn die Aufgabe Secrets hat, selbst bei Vorlagen ohne Vault. Alles, was die Kommandozeile parst, oder eine ansible.cfg, die Vault-Prompts verbietet, ist betroffen.
  7. Jinja2 in Werten zusätzlicher Variablen wird nicht mehr ausgewertet. Ein Playbook, das auf das Templating eines Webhook- oder Survey-Werts gesetzt hat, wird das nicht mehr tun.
  8. Der Endpunkt für Workflow-Läufe wurde umbenannt: POST …/workflows/{id}/run → …/runs.
  9. Monorepo-Repositories überschreiben die Vorlage: kein Branch pro Vorlage, kein Überschreiben von Branch oder Commit in Aufgaben.
  10. Das repository_id eines Inventars entfällt für alle Typen außer file.
  11. Das Stoppen einer lokalen Aufgabe beendet ihre Prozessgruppe (unter Windows noch kein Äquivalent).
  12. Workflow-Outputs werden von den Docker- und Kubernetes-Executoren noch nicht erfasst; Survey-Secrets erreichen diese Executoren noch nicht.

Neue Konfiguration

audit, metrics, auth.max_session_life_hours, ssh.{config_path,known_hosts_file,strict_host_key_checking}, git_attempts, git_submodule_jobs, ldap_providers, ldap_tls_skip_verify, external_auth_email_matching, groups_claim und require_verified_email pro OIDC-Anbieter, runner.check_interval_seconds, runner.connection.timeout_seconds, runners.{default_global_runners_mode,registration_token}. Alle sind optional. Konfigurationsfelder mit Pointer-Typ können jetzt über Umgebungsvariablen gesetzt werden. Die Referenzseiten für Konfiguration und CLI werden aus dem Quellcode generiert.

Datenbankmigrationen

v2.20.0 externe Identitäten · v2.20.1 aufgabengebundene Survey-Secrets · v2.20.2 Delay-Knoten · v2.20.3 Arbeitsverzeichnis · v2.20.4 eindeutige Vorlagennamen · v2.20.5 Unterdrückung von Fehler-Alerts · v2.20.7 Host-Konfiguration · v2.20.8 Workflow-Revisionen · v2.20.9–v2.20.11 Audit-Log und Indizes, Input-Mappings für Kanten, Monorepo-Flag · v2.20.12–v2.20.13 Rollentabellen, Workflow-Variablen · v2.20.14 Workflow-Integrationen und Gruppen-Mappings · v2.20.16 globale Rollen.

Abhängigkeiten

Go 1.26; Docker-Images auf Alpine 3.24; prometheus/client_golang 1.23 hinzugefügt; go-oidc 3.21, go-ldap 3.4.14, golang.org/x/crypto 0.57, modernc.org/sqlite 1.59, logrus 1.10; im Frontend js-yaml 5 und cron-parser 5.10. Neue One-Click-Deployments: Cloudzy, RepoCloud und Pethost.