Public reusable Forgejo Actions workflows for vr6syncro (security scan u.a.). Library-Repo muss public sein — enthaelt KEINE Secrets, nur ${{ secrets.* }}-Referenzen.
Find a file
2026-07-07 06:43:11 +02:00
.forgejo/workflows fix(ci): drop unsupported secrets: from workflow_call (fixes red phantom runs + fleet-wide reusable parse break) 2026-06-04 20:01:59 +02:00
examples fix(security): notify only on finding-state-change + PR runs report-only (stop Telegram/Matrix spam) 2026-06-01 17:30:00 +02:00
README.md docs: README berichtigen (Ist-Code) 2026-07-06 20:51:34 +02:00

ci-workflows

Zentrale, wiederverwendbare Forgejo-Actions-Workflows fuer die vr6syncro-Flotte.

⚠️ Dieses Repo ist absichtlich public. Forgejo (>= v15) unterstuetzt reusable workflows nur aus public Repos — auch auf der eigenen Instanz. Der Inhalt enthaelt keine Secrets, nur ${{ secrets.* }}-Referenzen, die beim Aufruf via secrets: inherit aus dem aufrufenden (privaten) Repo geerbt werden.

Ueberblick

Das Repo buendelt vier Workflows: zwei wiederverwendbare Security-Scanner (Basic + Hardened), ein wiederverwendbares Promotion-Gate (Pflichtdateien in public-Repos) und eine Self-CI, die die zentrale Logik vor jedem @main-Rollout gegen Regressions-Fixtures validiert. Aufrufende Repos ("thin caller") halten nur noch eine kleine Wrapper-Datei — Logik-Updates brauchen keinen flottenweiten Rollout.

flowchart TD
    subgraph caller["Aufrufendes Repo (thin caller)"]
        C[".forgejo/workflows/security.yml<br/>uses: ci-workflows/...@main<br/>secrets: inherit"]
        PGC["Promotion-Gate-Caller<br/>(public-Org-Repo)"]
    end

    subgraph lib["vr6syncro/ci-workflows (public)"]
        SEC["security.yml<br/>BASIC v2.2.1"]
        HARD["security-hardened.yml<br/>HARDENED v2.2.1"]
        PG["promotion-gate.yml<br/>v1.0.0"]
        CI["ci.yml<br/>Self-CI (Regressions-Gate)"]
    end

    subgraph scanners["Scanner"]
        TRIVY["Trivy FS<br/>vuln/secret/misconfig/license"]
        PIP["pip-audit"]
        NODE["npm / pnpm audit"]
        OSV["OSV-Scanner (G6)"]
        HADO["Hadolint (G8)"]
        SAST["SAST: Bandit/ShellCheck/cppcheck"]
    end

    subgraph out["Ausgaben"]
        ISSUE["Forgejo-Issue-Upsert<br/>fp-Gating + Auto-Close"]
        TG["Telegram"]
        MX["Matrix"]
        ART["Artefakte: SARIF (G5) + SBOM CycloneDX (G4)"]
    end

    C -->|workflow_call| SEC
    C -.optional.-> HARD
    PGC -->|workflow_call| PG
    CI -.validiert vor Rollout.-> SEC
    CI -.validiert vor Rollout.-> HARD

    SEC --> TRIVY & PIP & NODE
    HARD --> TRIVY & PIP & NODE & OSV & HADO & SAST

    TRIVY & PIP & NODE & OSV & HADO & SAST --> ISSUE
    ISSUE --> TG & MX
    HARD --> ART

    classDef libnode fill:#2d6cdf,stroke:#1b3a7a,color:#fff;
    classDef scan fill:#e67e22,stroke:#8a4a12,color:#fff;
    classDef output fill:#27ae60,stroke:#145a32,color:#fff;
    classDef call fill:#7f8c8d,stroke:#4d5656,color:#fff;
    class SEC,HARD,PG,CI libnode;
    class TRIVY,PIP,NODE,OSV,HADO,SAST scan;
    class ISSUE,TG,MX,ART output;
    class C,PGC call;

Workflows

.forgejo/workflows/security.yml — Security Scan (reusable, BASIC v2.2.1)

Trivy-FS (vuln,secret,misconfig,license) + pip-audit + Node-audit → Forgejo-Issue-Upsert (stabiler Titel, Duplikat-Closer, Auto-Close bei sauberem Scan) + Telegram + Matrix. Trivy wird ueber das apt-signierte Repo bezogen (kein curl | sh von raw.githubusercontent → supply-chain-haerter). Scan-Logik BYTE-IDENTISCH zur canonical security.yml v2.1.0 (orgamaster); nur der on:/env:-Block wurde durch workflow_call-Inputs ersetzt.

Notify nur bei Finding-STATE-Change (kein Chat-Spam)

Der Issue-Marker enthaelt einen Fingerprint des Fund-Zustands: <!-- security-scan:v2 fp=<sha256> -->. Der Fingerprint ist der sha256 ueber die sortiert-eindeutigen Fund-Zeilen (CVE-id:package aus Trivy plus je ein Section-Flag fuer node/pip/osv/misconfig/sast). Pro Lauf:

  • Das Issue wird immer in-place ge-PATCHt (Body bleibt aktuell, inkl. neuem fp).
  • Telegram + Matrix feuern nur, wenn das Issue neu ist oder der gespeicherte fp vom neuen abweicht (Funde geaendert / eskaliert) → CHANGED=1. Ein unveraenderter Fund-Satz aktualisiert das Issue still und pingt den Chat nicht erneut.
  • pull_request-Laeufe sind report-only: kein Issue-Upsert, kein Chat, kein Close — Funde erscheinen nur im Run-Log. (Scan-Gate github.event_name != 'pull_request'.)
  • Auto-Close benachrichtigt einmalig: wenn der Resolve-Schritt >= 1 Issue schliesst, geht eine Security findings resolved"-Nachricht raus; bei nichts Offenem bleibt es still.

push + pull_request decken jede echte Code-Aenderung ab; der Schedule im Caller ist daher von taeglich auf woechentlich (Mo) reduziert (reines Safety-Net).

Inputs (alle optional, Defaults = Kanon):

Input Default Zweck
severity HIGH,CRITICAL Trivy-Severities
auto_close true false = Issues nie auto-schliessen (NestRelay-Variante)
notify_min_sev HIGH HIGH | CRITICAL — Notify-Schwelle
notify_targets matrix,telegram Komma-Liste: matrix, telegram (oder einer / leer)

Secrets / Vars (via secrets: inherit, org/user-level vererbt): GITHUB_TOKEN (auto), TELEGRAM_BOT_TOKEN/_CHAT_ID, MATRIX_BOT_TOKEN/_ROOM_ID, Variable MATRIX_HOMESERVER. Fehlt ein Kanal → er wird still uebersprungen.

.forgejo/workflows/security-hardened.yml — Security Scan (reusable, HARDENED v2.2.1)

Gleicher Basic-Kern (korrektes Findings-Gating, stabiler Issue-Upsert, Dedup, Severity-Gate, auto_close, fp-Notify) plus erweiterter Scanner-Satz:

  • Trivy vuln,secret,misconfig,license + SARIF (G5) als Artefakt.
  • Trivy SBOM CycloneDX 1.6 (G4, EU-CRA) als Artefakt.
  • OSV-Scanner als zweite Vuln-Quelle (G6) — Binary von GitHub Releases (v2.3.5).
  • Hadolint Dockerfile-Lint (G8, nur wenn Dockerfile* vorhanden).
  • optional SAST (Input sast: true): Bandit (Python), ShellCheck (.sh), cppcheck (PlatformIO/C++).

Zusaetzlich ein Anti-stampede-Jitter (Random-Sleep bis 300s) sowie eine fail-closed-Trivy-Beschaffung: apt-signed-Repo mit Retries, dann gepinntes Release-Binary (checksum-verifiziert); nur wenn alle Methoden scheitern, bricht der Job ab (ein fehlender Scanner darf nicht als sauberes Ergebnis durchgehen).

Inputs: wie Basic, zusaetzlich sast (boolean, default false).

.forgejo/workflows/promotion-gate.yml — Promotion Gate (reusable v1.0.0)

Erzwingt „Enterprise-Stand"-Dateien in public-Org-Repos: prueft Vorhandensein und Mindestgroesse von LICENSE, README, SECURITY.md, CONTRIBUTING.md (inkl. alternativer Pfade wie .gitea/SECURITY.md, docs/CONTRIBUTING.md). Gedacht als Required-Check vor Branch-Protection-Merge. Portiert aus dem privaten orgamaster, weil private Repos keine cross-repo-Reusables bereitstellen koennen.

Inputs:

Input Default Zweck
min_license_bytes 100 Mindestgroesse fuer LICENSE
min_doc_bytes 200 Mindestgroesse fuer README/SECURITY/CONTRIBUTING

.forgejo/workflows/ci.yml — Self-CI (Regressions-Gate)

Validiert bei jedem push/PR das zentrale Repo, bevor @main flottenweit (~50 Repos) wirksam wird:

  1. YAML-Parse aller Workflows (best-effort via PyYAML).
  2. yamllint (relaxed) — falls verfuegbar.
  3. Report-jq-Regression deckt drei historisch unsichtbare Faelle ab: (1) non-CVE-Vuln (GHSA/PYSEC/RUSTSEC/GO/…) wird gezaehlt, (2) committetes Secret (.Results[].Secrets[]) wird gezaehlt, (3) Clean-Scan → 0 Findings, Job darf nicht roten (pipefail-Regression 4586d50).
  4. workflow_call-Parse-Gate: verbietet einen secrets:-Block innerhalb des on:/workflow_call-Bereichs (Forgejo/act_runner erlaubt dort nur inputs/outputs; ein secrets:-Block macht den Workflow unparsebar und bricht die Reusable flottenweit — Regression 0932a7c).

Verwendung (thin caller)

In jedem Repo .forgejo/workflows/security.yml durch den Caller aus examples/security-caller.yml ersetzen.

jobs:
  security:
    uses: vr6syncro/ci-workflows/.forgejo/workflows/security.yml@main
    secrets: inherit
    with:
      severity: "HIGH,CRITICAL"
      auto_close: true
      notify_min_sev: "HIGH"
      notify_targets: "matrix,telegram"

Fuer das Hardened-Profil stattdessen security-hardened.yml referenzieren und bei Bedarf sast: true setzen.

Versionierung / Pinning

  • @main = immer aktuellste Logik (gewollt fuer einen Security-Scanner).
  • Fuer reproduzierbare Builds stattdessen einen Tag pinnen, z.B. @v2.
  • Voraussetzung: Forgejo >= 15 + Runner > 12.5 (reusable workflow expansion). Flotte ist auf Forgejo 15.0.2 + Runner 12.10.2 (Stand 2026-05-31).