|
All checks were successful
CI (self-validation) / validate (push) Successful in 8s
|
||
|---|---|---|
| .forgejo/workflows | ||
| examples | ||
| README.md | ||
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 viasecrets: inheritaus 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
fpvom 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-Gategithub.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:
- YAML-Parse aller Workflows (best-effort via PyYAML).
- yamllint (relaxed) — falls verfuegbar.
- 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-Regression4586d50). - workflow_call-Parse-Gate: verbietet einen
secrets:-Block innerhalb deson:/workflow_call-Bereichs (Forgejo/act_runner erlaubt dort nurinputs/outputs; einsecrets:-Block macht den Workflow unparsebar und bricht die Reusable flottenweit — Regression0932a7c).
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). ✅