1 Architecture
vr6syncro edited this page 2026-07-06 20:52:36 +02:00

Architektur

ci-workflows ist eine Bibliothek wiederverwendbarer Forgejo-Workflows. Aufrufende Repos referenzieren die Workflows via workflow_call; Secrets flieszen ausschlieszlich per secrets: inherit vom (privaten) Caller.

Komponenten

Datei Rolle Version
.forgejo/workflows/security.yml Reusable Security-Scan, Basic-Profil v2.2.1
.forgejo/workflows/security-hardened.yml Reusable Security-Scan, Hardened-Profil v2.2.1
.forgejo/workflows/promotion-gate.yml Reusable Pflichtdatei-Gate (public-Org) v1.0.0
.forgejo/workflows/ci.yml Self-CI / Regressions-Gate
examples/security-caller.yml Vorlage fuer den thin caller

Datenfluss

  1. Ein Caller-Repo triggert bei push/pull_request/schedule seinen thin caller.
  2. Der thin caller ruft security.yml@main (oder security-hardened.yml) via workflow_call auf und vererbt Secrets.
  3. Die Scanner laufen (Trivy FS immer; im Hardened-Profil zusaetzlich OSV, Hadolint, optional SAST; pip-audit nur bei requirements*.txt, Node-audit nur bei Lockfile).
  4. Der Report-Schritt zaehlt Findings (inkl. non-CVE-Vulns und committeter Secrets) und bildet einen sha256-Fingerprint des Fund-Zustands.
  5. Bei Findings und event != pull_request wird ein Forgejo-Issue ge-upsertet (stabiler Titel, Duplikat-Closer, Auto-Close bei sauberem Scan).
  6. Telegram/Matrix feuern nur bei neuem Issue oder geaendertem Fingerprint.
  7. Das Hardened-Profil legt zusaetzlich SARIF- und SBOM-Artefakte ab.

Diagramm

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"]
    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;

Wichtige Invarianten (durch Self-CI erzwungen)

  • Kein secrets:-Block unter workflow_call — Forgejo erlaubt dort nur inputs/outputs; ein secrets:-Block macht den Workflow unparsebar und bricht die Reusable flottenweit (Regression 0932a7c). Secrets kommen ausschlieszlich via secrets: inherit.
  • non-CVE-Vulns zaehlen (GHSA/PYSEC/RUSTSEC/GO/DLA/DSA/USN/ALAS/ELSA).
  • committete Secrets zaehlen (.Results[].Secrets[]).
  • Clean-Scan = 0 Findings darf nicht roten (pipefail-Regression 4586d50).