Deep Analysis 2026-06-04 — ci-workflows #5

Open
opened 2026-06-04 05:39:48 +02:00 by vr6syncro · 0 comments
Owner

Deep Analysis 2026-06-04 — ci-workflows

Autonome Multi-Agent-Analyse (Recon + 5 Blickrichtungen + adversariale Verifikation). Stand 2026-06-04.

1. Ueberblick & Einordnung

  • repo_class: full (zentrale, oeffentliche Reusable-Forgejo-Actions-Library der vr6syncro-Flotte).
  • Zweck: Stellt drei wiederverwendbare workflow_call-Workflows fuer ~50 Konsumenten-Repos bereit:
    security.yml (BASIC, v2.2.0), security-hardened.yml (v2.2.0, +OSV/Hadolint/SAST/SBOM/SARIF) und
    promotion-gate.yml (v1.0.0, erzwingt Pflichtdateien in Public-Repos). Konsumenten binden via thin caller
    • secrets: inherit ein.
  • Stack: Reine YAML + inline-Bash (set -euo pipefail), Scanner: Trivy (fs vuln/secret[/misconfig/license]),
    pip-audit, npm/pnpm audit, OSV-Scanner, Hadolint, optional Bandit/ShellCheck/cppcheck. Issue-/Notify-Logik via
    Forgejo-REST + Telegram + Matrix.
  • Dateibestand (main @ 4586d50): .forgejo/workflows/{security,security-hardened,promotion-gate}.yml,
    README.md, examples/security-caller.yml. Sonst nichts. Keine Dateileichen, kein .github/-Anti-Pattern,
    korrekt nur .forgejo/workflows.
  • Hinweis OEFFENTLICH: Security-Details bewusst verallgemeinert; keine Exploit-Schritte, keine internen Hosts/IPs.

2. Gesamtbewertung

Health-Grade: B.
Die Kern-Pipeline ist durchdacht und robust: fails-closed Trivy-Bootstrap (apt-signiert + SHA256-verifizierter
Release-Fallback), saubere Trennung SCAN_OK vs. SECURITY_FINDINGS, trap write_findings EXIT als Close-Gate-Schutz,
fp-basiertes Notify-Dedup, alle zustandsaendernden Schritte per github.event_name != 'pull_request' gegated, und das
Repo ist credential-clean (nur ${{ secrets.* }}/${{ vars.* }}-Referenzen, kein Klartext-Secret). Abwertung von A
auf B wegen zweier echter Korrektheitsfehler in der Fund-Auswertung, die zusammen mit dem Auto-Close-Gate dazu fuehren
koennen, dass non-CVE- bzw. Secret-Funde unsichtbar bleiben UND aktive Issues faelschlich geschlossen werden — bei einer
fleet-weiten Hebelwirkung ueber ~50 Repos relevant. Dazu fehlende Selbst-Governance: keine Self-CI, main ungeschuetzt,
~90% Code-Duplizierung zwischen Basic und Hardened, und das Repo verletzt sein eigenes Promotion-Gate (LICENSE/SECURITY.md/
CONTRIBUTING.md fehlen).

3. Bugs & Korrektheit

  • [CRITICAL] Trivy-Secret-Scanner laeuft, aber .Secrets[] wird im Normalpfad nie ausgewertet — security.yml:156 / security-hardened.yml:173,179 — Der Trivy-FS-Scan laeuft mit --scanners vuln,secret[,misconfig,license], detektiert also eingecheckte Klartext-Secrets. Der Schritt Build security report liest jedoch ausschliesslich .Results[].Vulnerabilities[] (security.yml:225, security-hardened.yml:283) und niemals .Results[].Secrets[]. Trivy legt Secret-Funde unter .Results[].Secrets[] ab, nicht unter .Vulnerabilities[]. Folge: Ein gefundenes Secret traegt nichts zu findings bei → SECURITY_FINDINGS=0 → kein Issue, keine Notify. Schlimmer: bei sauberem JSON-Scan (SCAN_OK=1) feuert das Close-Gate (if: env.SCAN_OK == '1' && env.SECURITY_FINDINGS != '1' && github.event_name != 'pull_request', security.yml:564 / security-hardened.yml:647) und schliesst evtl. offene Security-Issues, obwohl ein Secret-Leak vorliegt. .Secrets[] wird nur im if: failure()-Diagnoseschritt gelesen (security.yml:710, security-hardened.yml:793) — also nie im Normalpfad. Empfehlung: In Build security report einen Block fuer [.Results[]?.Secrets[]?] ergaenzen: bei >0 findings=1 setzen, Section (RuleID/Severity/Title/Datei) an security_sections.md haengen, in security_summary.txt + security_fp_lines.txt (Fingerprint) aufnehmen, Severity (Trivy-Secrets meist CRITICAL) ins max_sev-Mapping. Beide Dateien identisch patchen.

  • [HIGH] jq-Filter startswith("CVE") verwirft alle Nicht-CVE-Vuln-IDs (GHSA/PYSEC/RUSTSEC/GO …) — security.yml:226 / security-hardened.yml:284 — Die Report-Pipeline selektiert nur .VulnerabilityID | startswith("CVE"). Trivy meldet fuer npm/Go/Python/Rust- und viele OS-Pakete Schwachstellen oft nur mit GHSA-/PYSEC-/RUSTSEC-/GO--IDs ohne zugeordnete CVE. Solche HIGH/CRITICAL-Funde fallen komplett aus trivy_rows.md; sind sie die einzigen Funde, bleibt findings=0 → kein Issue/Notify und ggf. faelschliches Auto-Close ueber dasselbe Gate. Der Hardened-Pfad faengt einen Teil ueber OSV/pip-audit/node-audit ab, aber nur bei vorhandenem Lockfile/requirements; der reine Trivy-FS-Pfad (Container/OS-Pakete) bleibt blind. Der Fingerprint-sed nutzt bereits [A-Z0-9-]+, deckt GHSA also ab — nur der vorgelagerte jq-Filter ist zu eng. Empfehlung: Filter aufweiten, z.B. select(.VulnerabilityID? | strings | test("^(CVE|GHSA|PYSEC|RUSTSEC|GO|DLA|DSA|USN|ALAS)-"; "i")) oder schlicht select(.VulnerabilityID? != null and .VulnerabilityID != ""). Die osv.dev-Link-Vorlage funktioniert auch fuer GHSA. Beide Dateien angleichen.

  • [MEDIUM] Anti-stampede-Jitter (Sleep bis 300s) laeuft auf jedem Event inkl. push/pull_request/workflow_dispatchsecurity.yml (Step Anti-stampede jitter, ohne if:) / security-hardened.yml:79-84 — Der erste Step schlaeft RANDOM % 300 Sekunden ohne Event-Bedingung. Zweck ist die Entzerrung des Wochen-Cron ueber die Flotte; er feuert aber auch bei interaktiven PR-/Dispatch-Laeufen und verzoegert die Security-Feedbackschleife im Schnitt ~150s grundlos (relevant auf der langsamen dind-Runner-SSD). Korrektheitlich harmlos, aber unnoetige Latenz/Runner-Zeit fleet-weit. Empfehlung: Jitter-Step auf if: github.event_name == 'schedule' begrenzen.

  • [LOW] Pinning-Inkonsistenz @v2 vs. @main (aktuell synchron, kein Laufzeit-Drift) — promotion-gate.yml (Header @v2), examples/security-caller.yml (@main), security.yml/security-hardened.yml:17 (Header @main), README.md (empfiehlt @v2) — Das v2-Tag zeigt aktuell auf denselben Commit wie main HEAD (4586d50), d.h. KEIN funktionaler Drift. Das gemischte Modell ist aber fehleranfaellig: @main-Caller ziehen jede Aenderung sofort, @v2-Caller erst nach manuellem git tag -f v2 && git push -f. Empfehlung: Einheitliches Modell festlegen (empfohlen @v2 als gepinntes Tag mit dokumentiertem Promote-Schritt, ODER bewusst @main mit Begruendung) und konsistent in Caller/Header/README abbilden.

4. Security

Repo ist OEFFENTLICH und absichtlich credential-clean. Befunde sind primaer Supply-Chain-Haertung; keine Exploit-Details.

  • [MEDIUM] osv-scanner und hadolint werden ohne Checksum-Verifikation und mit || true von github.com/releases geladen — security-hardened.yml:129-130 — Beide Binaries werden per curl -fsSL -o /usr/local/bin/... && chmod +x ... || true direkt installiert, ohne jede Integritaetspruefung. Das steht im Widerspruch zum gehaerteten Trivy-Pfad im selben Step, der den Release-Tarball gegen checksums.txt mit sha256sum -c verifiziert (security-hardened.yml:114). Ein manipuliertes Release-Asset / MITM / gekapertes Upstream-Repo wuerde unbemerkt ein Binary mit Schreibzugriff auf den Checkout und Zugang zum Job-Env ausfuehren; das || true maskiert zusaetzlich Download-Fehler. Wirkung multipliziert sich ueber alle Hardened-Konsumenten. Empfehlung: Fuer osv-scanner/hadolint analog zu Trivy einen erwarteten SHA256 hinterlegen (Versionen sind ohnehin gepinnt: osv v2.3.5, hadolint v2.12.0) und nach Download mit sha256sum -c verifizieren, bei Mismatch fail-closed (kein || true als Erfolgsmaske).

  • [MEDIUM] main-Branch nicht protected bei fleet-weiter Hebelwirkung — Forgejo Branch-API: protected: false, required_approvals: 0, enable_status_check: false; Commits unsigniert (verified:false, gpg.error.not_signed_commit) — Da ~50 Repos die Logik via @main ziehen, wird jeder Direkt-Push ohne Review/Status-Check sofort fleet-weit aktiv; ein fehlerhafter Push kann alle Scans gleichzeitig brechen. Empfehlung: Branch-Protection auf main aktivieren (Required-Status-Check = neue Self-CI, mind. 1 Approval bzw. bei Solo-Betrieb wenigstens Required-Status-Check) und @v2 als empfohlenen Konsumenten-Pin etablieren.

  • [LOW] Ungepinnte latest-Installs von pip-audit, bandit und pnpm (nicht reproduzierbar, kein Integritaetscheck) — security.yml/security-hardened.yml:202 (pip-audit), security-hardened.yml:250 (bandit), :216 (pnpm via npm install -g pnpm --silent) — Installiert ueber pip install --break-system-packages --quiet ohne Version/Hash bzw. global latest. Nicht reproduzierbar, kein Anker gegen kompromittierte Upstream-Pakete; gegenlaeufig zum sonst haertenden Design. Risiko niedriger als bei den Binaries (grosse, beobachtete Oekosysteme). Empfehlung: pip-audit/bandit/pnpm auf konkrete Versionen pinnen, idealerweise --require-hashes ueber constraints-Datei.

  • [LOW] Trivy-Versionsermittlung via ungeprueftem GitHub-API-Aufruf steuert die Download-URL (Pin nur als Notausgang) — security.yml/security-hardened.yml:107-109 — Die Version stammt dynamisch aus der Releases-API (grep tag_name), der feste Pin 0.58.1 greift nur bei unerreichbarer API. Die sha256sum-Pruefung schuetzt gegen Transportfehler, nicht gegen eine konsistent boesartige Upstream-Antwort (Version + Referenz-Checksumme aus derselben Quelle). Deutlich besser als osv/hadolint, aber nicht deterministisch gepinnt. Empfehlung: Trivy-Version fest pinnen oder Referenz-Checksumme aus einer im Repo gepflegten Liste beziehen.

  • [INFO] Kein Klartext-Secret im Repo; Token-Handhabung ohne Logging-Leck (positiver Befund) — Verifiziert: ausschliesslich ${{ secrets.* }}/${{ vars.* }}-Referenzen (GITHUB_TOKEN→FORGEJO_TOKEN, TELEGRAM_, MATRIX_, var MATRIX_HOMESERVER), keine .env/.pem/credentials-Dateien. Secrets nur ueber Env in curl-Header/jq-Args, nie per echo/printf geloggt; der Failure-Diagnose-Step dumpt nur Flags + Scan-Output. Notify-Secrets required: false. Entspricht der credential-clean-by-design-Doktrin. Empfehlung: Beibehalten; beim Editieren des Diagnose-Steps weiterhin keine Secret-tragenden Variablen ausgeben, curl nie mit -v/Trace.

5. Features & QOL

  • [HIGH] Keine Self-CI: das Library-Repo lintet/validiert seine eigenen Workflows nicht — kein .forgejo/workflows/ci.yml; nur die 3 Reusables + Caller existieren (Branch-API: nur main) — Die gesamte Logik lebt in inline-Bash (set -euo pipefail, je >700 Zeilen); jede Aenderung wirkt bei @main sofort fleet-weit. Genau diese Pipeline hatte bereits eine produktive Regression (PR #4 / Commit 4586d50: clean scans no longer red the job (fp pipeline pipefail + -e abort)) — ein leeres Clean-Scan-Resultat brach den Job unter Actions' default bash -eo pipefail ab. Ohne automatisches Netz (actionlint + shellcheck + bash -n + yamllint) gibt es kein Gate, das pipefail-/jq-/YAML-Fehler vor dem Wirksamwerden abfaengt. Empfehlung: Schlanke ci.yml (push/PR): actionlint + yamllint + jeden run:-Block via bash -n + shellcheck (Actions-faithful bash -eo pipefail), plus optional Dry-Run gegen synthetische /tmp/trivy.json-Fixtures (Clean- UND Findings-Fall — die 4586d50-Regression als Regressionstest festschreiben). Wirkungsvollste Einzelmassnahme.

  • [MEDIUM] Massive Code-Duplizierung zwischen security.yml und security-hardened.yml (~90% identisch) — security-hardened.yml:25 Header: „Scan-Logik BYTE-IDENTISCH zur canonical security.yml v2.1.0" — Der gesamte Issue-Upsert-/Dedup-/fp-/Notify-/Close-/Self-Diagnostic-Apparat (mehrere hundert Zeilen) ist in beiden Dateien byte-fast-identisch dupliziert; nur die Scanner-Steps unterscheiden sich (Hardened: OSV/Hadolint/SAST/SARIF/SBOM). Jeder kuenftige Fix am Issue-/Notify-Pfad muss zweimal gepflegt werden → Drift-Risiko (z.B. fp-Fix landet nur in einer Datei). Empfehlung: Zu EINER security.yml mit hardened-(bool)/sast-Inputs konsolidieren (Extra-Scanner per if:), security-hardened.yml als duenner Alias-Caller; alternativ den gemeinsamen Issue-/Notify-Teil in einen separaten reusable workflow_call-Job auslagern, den beide aufrufen.

  • [MEDIUM] Supply-Chain-Inkonsistenz + kein renovate.json fuer die Tool-Versionen — security-hardened.yml:129-130 (osv/hadolint ungepinnt-checksumlos, || true); renovate.json nicht vorhanden — Tool-Pins (osv v2.3.5, hadolint v2.12.0, Trivy-Safety-Pin 0.58.1) veralten manuell; kein automatischer Drift-Hinweis. (Ueberschneidet sich mit dem MEDIUM-Supply-Chain-Befund in §4.) Empfehlung: Checksum-Verifikation fuer osv/hadolint (siehe §4) + renovate.json mit custom-regex-Manager auf die Release-URLs, damit Tool-Versionen automatisch aktuell bleiben.

  • [LOW] promotion-gate verweist in Fehlermeldungen/Summary auf das PRIVATE orgamaster-Repo, das public Caller nicht lesen koennen — promotion-gate.yml Steps Check LICENSE/Check SECURITY.md (::error::… siehe orgamaster/docs/extern-rules.md) + Gate Summary (Link auf …/vr6syncro/orgamaster/…/docs/promotion-gate.md); Header: „orgamaster ist privat" — Ein externer Caller, der durch das Gate faellt, bekommt Doku-Links auf ein nicht oeffnbares Repo → Sackgasse fuer genau die Zielgruppe (Public-Repos). Empfehlung: Spec-/Regel-Doku nach docs/ in dieses public Repo portieren und die Fehlermeldungen/Summary auf public Pfade umbiegen.

  • [LOW] Fehlende Beispiel-/Doku-Dateien: examples/caller-public.yml referenziert, aber nicht vorhanden; kein CHANGELOG — promotion-gate.yml Header nennt examples/caller-public.yml (API 404 bestaetigt nicht vorhanden); kein examples/promotion-gate-caller.yml; kein CHANGELOG.md; Header-Versionierung v2.2.0/v1.0.0 ohne Changelog — Konsumenten des Promotion-Gates/Hardened-Profils haben keine Copy-Paste-Vorlage; das manuell zu verschiebende @v2-Tag birgt das Risiko „Konsumenten merken Logik-Aenderung nicht". Empfehlung: examples/caller-public.yml (Promotion-Gate-Caller) + examples/security-hardened-caller.yml ergaenzen, tote Verweise korrigieren, CHANGELOG.md je v2-Tag-Bump pflegen.

  • [LOW] Scan-Artefakte (SARIF/SBOM/OSV-JSON) werden nur ins Working-Tree-.scan-out/ kopiert, nicht als CI-Artefakt persistiert — security-hardened.yml:808-812 (cp + ls -la, kein actions/upload-artifact); SBOM generiert :183 (trivy fs --format cyclonedx) — Da der Workspace nach dem Job verworfen wird, sind die im Header beworbenen Compliance-Outputs (CycloneDX-SBOM „G4 EU-CRA", SARIF „G5") nach dem Lauf nicht mehr abrufbar. Empfehlung: Falls der Runner actions/upload-artifact unterstuetzt, SARIF/SBOM/OSV-JSON als benannte Artefakte hochladen (retention-days); alternativ SBOM bei getaggten Laeufen als Release-Asset/Generic-Package anhaengen.

  • [LOW] (unsicher — nicht reproduziert) Issue-Suche mit limit=100 ohne Paginierung — security.yml/security-hardened.yml:418,487,497,668 (/issues?type=issues&state=open&limit=100) — Bei Repos mit >100 offenen Issues koennte das Marker-/Dedup-/Close-Matching das relevante Security-Issue verpassen (Doppel-Anlage oder nicht-Schliessen). Fuer die meisten Flotten-Repos unkritisch; nur in sehr issue-reichen Repos relevant. Als Hypothese gefuehrt: tritt nur bei >100 offenen Issues auf, in diesem Repo nicht reproduziert. Empfehlung: Issue-Suche per Label/Marker filtern (statt alle offenen Issues zu ziehen) oder kleine page-Schleife.

6. Struktur, Ordnung, Dateileichen, Templates

  • [MEDIUM] Das Repo verletzt sein eigenes Promotion-Gate: LICENSE/SECURITY.md/CONTRIBUTING.md fehlen — promotion-gate.yml Steps Check LICENSE/README/SECURITY.md/CONTRIBUTING.md (exit 1 bei Fehlen); Forgejo-API: LICENSE / SECURITY.md / CONTRIBUTING.md je 404, nur README.md (3619 B) vorhanden; Repo private:false — Die zentrale Library erzwingt fuer Public-Repos genau diese Pflichtdateien, erfuellt sie aber selbst nicht; wuerde am eigenen Gate scheitern. Fehlendes LICENSE ist bei einem zur Wiederverwendung gedachten Public-Repo zudem rechtlich relevant (ohne Lizenz „all rights reserved"); fehlende SECURITY.md bei einem Security-Tooling-Repo besonders auffaellig. Empfehlung: LICENSE (SPDX, z.B. MIT/Apache-2.0), SECURITY.md (Disclosure-Policy), CONTRIBUTING.md ergaenzen und das eigene Promotion-Gate als Self-Check laufen lassen (Dogfooding).

  • [LOW] Doku-Drift: promotion-gate referenziert nicht existierende Dateien — promotion-gate.yml Header (examples/caller-public.yml, docs/promotion-gate.md, docs/extern-rules.md) — Keine dieser Dateien/Ordner existiert im Repo (kein docs/, kein examples/caller-public.yml — API 404). Niemand kann den Promotion-Gate-Caller anhand der angegebenen Referenzen nachbauen. (Eng verwandt mit dem orgamaster-LOW in §5.) Empfehlung: Referenzierte Dateien anlegen oder die toten Verweise aus Header/Summary entfernen bzw. auf vorhandene README-Abschnitte umbiegen.

  • [INFO] Copy-Paste im security-hardened.yml-Header: Aufruf-Hinweis nennt security.yml@main statt security-hardened.ymlsecurity-hardened.yml:17 (# uses: vr6syncro/ci-workflows/.forgejo/workflows/security.yml@main) — Wer den Header copy-pastet, ruft versehentlich die Basic-Variante statt der Hardened-Variante auf. Rein dokumentarisch (YAML-Logik korrekt). Empfehlung: Header-Pfad auf security-hardened.yml korrigieren.

  • [INFO] Kein renovate.json, kein .gitignore, keine .editorconfig — git-tree (rekursiv) enthaelt keine dieser Dateien — Fuer ein reines YAML/Markdown-Repo funktional unkritisch (keine versehentlich committeten Artefakte gefunden), aber als Org-Konvention auffaellig (Renovate ist fleet-weit etabliert; siehe MEDIUM in §5 fuer die Tool-Version-Begruendung). Empfehlung: renovate.json ergaenzen (Action-/Release-Binary-Pins tracken); .gitignore/.editorconfig optional, niedrige Prioritaet.

  • [INFO] Saubere Struktur, keine Dateileichen, kein .github-Anti-Pattern (positiv) — git-tree (ref 4586d50): exakt 5 Dateien, 0 Datei-Artefakte (keine *.bak/*.orig/.DS_Store/Logs/Binaries), korrekt nur .forgejo/workflows. Namensgebung konsistent. Dient als Baseline-Einordnung der low/medium-Findings. Empfehlung: Keine Massnahme.

7. Status vs. offene Issues & PRs

  • 0 offene Issues, 0 offene PRs. list_repo_issues(state=open) und list_repo_pull_requests(state=open) sind leer — kein Backlog, keine stale/konfliktbehafteten PRs, keine Duplikate. Kein Tracker-Abgleich noetig; das Repo ist im Status-Sinn schuldenfrei.
  • PR-Historie: #1 (notify state-change + PR report-only), #2 (resilient Trivy bootstrap), #3 (CI-failure self-report), #4 (clean scans no longer red) — alle gemergt (alle vom Owner). Die in dieser Analyse genannten Befunde sind durch diese PRs NICHT abgedeckt (sie betreffen die Fund-Auswertung/Governance, nicht Notify-Dedup/Bootstrap). Keine Ueberschneidung mit getrackten Vorgaengen.
  • Branches/Tags: nur main (kein vergessener Feature-Branch). Tag v2 zeigt aktuell auf denselben Commit wie main HEAD (4586d50) → kein Pinning-Drift zur Analysezeit; das Restrisiko ist rein zukuenftig (manueller Tag-Move noetig).
  • Drift local↔remote: kein lokaler Klon vorhanden; Analyse vollstaendig gegen die Live-Forgejo-API (ref main). Kein Drift feststellbar.

8. Priorisierte Empfehlungen

Prio Thema Aufwand Bezug
P1 .Secrets[] im Report auswerten (findings/Notify/fp/max_sev) — verhindert unsichtbare Secret-Leaks + faelschliches Auto-Close M §3 CRITICAL
P1 jq-Filter von startswith("CVE") auf alle Vuln-ID-Praefixe (GHSA/PYSEC/RUSTSEC/GO …) aufweiten S §3 HIGH
P1 Self-CI (ci.yml: actionlint/yamllint/bash -n/shellcheck + Dry-Run-Fixtures) M §5 HIGH
P2 osv-scanner/hadolint mit SHA256 verifizieren, || true-Erfolgsmaske entfernen S §4 MEDIUM, §5 MEDIUM
P2 main-Branch-Protection (Required-Status-Check + Approval) S §4 MEDIUM
P2 LICENSE + SECURITY.md + CONTRIBUTING.md ergaenzen (eigenes Gate erfuellen) S §6 MEDIUM
P2 Basic/Hardened-Duplizierung konsolidieren (Input-Flag oder gemeinsamer reusable Notify-Job) M §5 MEDIUM
P3 Jitter auf if: github.event_name == 'schedule' begrenzen S §3 MEDIUM
P3 Pinning-Modell @main/@v2 vereinheitlichen + dokumentieren S §3 LOW
P3 pip-audit/bandit/pnpm + Trivy-Version pinnen; renovate.json ergaenzen S §4 LOW, §5/§6
P3 Doku-Drift beheben (orgamaster-Links, examples/caller-public.yml, docs/*, hardened-Header-Pfad), CHANGELOG S §5/§6 LOW/INFO
P3 SARIF/SBOM/OSV als CI-Artefakt/Release-Asset persistieren S §5 LOW

9. Methodik & Vertrauensgrad

  • Agenten: Recon + 5 Blickrichtungen (bugs, security, features_qol, structure, status) + 1 adversariale Verifikation.
  • Verifiziert: Alle in §3-§7 gelisteten Findings wurden gegen den echten Code (ref main @ 4586d50) per Forgejo-API
    nachgelesen — security.yml und security-hardened.yml (813 Zeilen, vollstaendig base64-dekodiert),
    promotion-gate.yml, examples/security-caller.yml, README.md. Codestellen (Datei:Zeile) der Kernbefunde direkt
    bestaetigt: --scanners vuln,secret, der .Vulnerabilities[]-only Report-jq, startswith("CVE"), das
    .Secrets[]-only im failure-Step, das Close-Gate SCAN_OK==1 && SECURITY_FINDINGS != '1', osv/hadolint ohne
    Checksum + || true, Trivy-Checksum-Kontrast, Jitter ohne Event-Guard, limit=100-Abfragen. Fehlende Standarddateien
    (LICENSE/SECURITY.md/CONTRIBUTING.md/examples/caller-public.yml) via API-404 bestaetigt. Branch-/PR-/Tag-Lage und
    „0 offene Vorgaenge" via Live-API verifiziert.
  • Verworfen/korrigiert: Ein Agent zitierte README als „enthaelt keine Secrets, nur ${{ secrets.* }}-Referenzen" —
    bestaetigt (Wortlaut leicht abweichend, inhaltlich korrekt). Der limit=100-Befund wurde auf LOW/unsicher abgestuft,
    weil er nur bei >100 offenen Issues greift und in diesem Repo nicht reproduzierbar ist. Doppelte Supply-Chain-/
    Promotion-Gate-/Pinning-Befunde mehrerer Agenten wurden zu je einem Eintrag konsolidiert.
  • Nicht (vollstaendig) pruefbar: Reales Laufzeitverhalten der Workflows (keine Runner-Log-API in Forgejo 15; keine
    Ausfuehrung moeglich) — die Korrektheitsbefunde sind statisch aus dem Code + jq-/Trivy-Semantik belegt, nicht aus einem
    Live-Lauf. Tatsaechliche Fork-PR-Exposition haengt von der Actions-Policy der ~50 Konsumenten-Repos ab (nicht aus diesem
    Repo allein bestimmbar). Kein lokaler Klon vorhanden — gesamte Analyse rein API-basiert.
  • Sicherheit: Keine Secret-Werte ausgegeben; Repo ist credential-clean (nur Referenzen). Keine Exploit-Schritte,
    keine internen Hosts/IPs im Issue.
# Deep Analysis 2026-06-04 — ci-workflows _Autonome Multi-Agent-Analyse (Recon + 5 Blickrichtungen + adversariale Verifikation). Stand 2026-06-04._ ## 1. Ueberblick & Einordnung - **repo_class:** `full` (zentrale, oeffentliche Reusable-Forgejo-Actions-Library der vr6syncro-Flotte). - **Zweck:** Stellt drei wiederverwendbare `workflow_call`-Workflows fuer ~50 Konsumenten-Repos bereit: `security.yml` (BASIC, v2.2.0), `security-hardened.yml` (v2.2.0, +OSV/Hadolint/SAST/SBOM/SARIF) und `promotion-gate.yml` (v1.0.0, erzwingt Pflichtdateien in Public-Repos). Konsumenten binden via thin caller + `secrets: inherit` ein. - **Stack:** Reine YAML + inline-Bash (`set -euo pipefail`), Scanner: Trivy (fs vuln/secret[/misconfig/license]), pip-audit, npm/pnpm audit, OSV-Scanner, Hadolint, optional Bandit/ShellCheck/cppcheck. Issue-/Notify-Logik via Forgejo-REST + Telegram + Matrix. - **Dateibestand (main @ 4586d50):** `.forgejo/workflows/{security,security-hardened,promotion-gate}.yml`, `README.md`, `examples/security-caller.yml`. Sonst nichts. Keine Dateileichen, kein `.github/`-Anti-Pattern, korrekt nur `.forgejo/workflows`. - **Hinweis OEFFENTLICH:** Security-Details bewusst verallgemeinert; keine Exploit-Schritte, keine internen Hosts/IPs. ## 2. Gesamtbewertung **Health-Grade: B.** Die Kern-Pipeline ist durchdacht und robust: fails-closed Trivy-Bootstrap (apt-signiert + SHA256-verifizierter Release-Fallback), saubere Trennung `SCAN_OK` vs. `SECURITY_FINDINGS`, `trap write_findings EXIT` als Close-Gate-Schutz, fp-basiertes Notify-Dedup, alle zustandsaendernden Schritte per `github.event_name != 'pull_request'` gegated, und das Repo ist credential-clean (nur `${{ secrets.* }}`/`${{ vars.* }}`-Referenzen, kein Klartext-Secret). Abwertung von A auf B wegen zweier echter Korrektheitsfehler in der Fund-Auswertung, die zusammen mit dem Auto-Close-Gate dazu fuehren koennen, dass non-CVE- bzw. Secret-Funde unsichtbar bleiben UND aktive Issues faelschlich geschlossen werden — bei einer fleet-weiten Hebelwirkung ueber ~50 Repos relevant. Dazu fehlende Selbst-Governance: keine Self-CI, `main` ungeschuetzt, ~90% Code-Duplizierung zwischen Basic und Hardened, und das Repo verletzt sein eigenes Promotion-Gate (LICENSE/SECURITY.md/ CONTRIBUTING.md fehlen). ## 3. Bugs & Korrektheit - **[CRITICAL]** Trivy-Secret-Scanner laeuft, aber `.Secrets[]` wird im Normalpfad nie ausgewertet — `security.yml:156` / `security-hardened.yml:173,179` — Der Trivy-FS-Scan laeuft mit `--scanners vuln,secret[,misconfig,license]`, detektiert also eingecheckte Klartext-Secrets. Der Schritt *Build security report* liest jedoch ausschliesslich `.Results[].Vulnerabilities[]` (`security.yml:225`, `security-hardened.yml:283`) und niemals `.Results[].Secrets[]`. Trivy legt Secret-Funde unter `.Results[].Secrets[]` ab, nicht unter `.Vulnerabilities[]`. Folge: Ein gefundenes Secret traegt nichts zu `findings` bei → `SECURITY_FINDINGS=0` → kein Issue, keine Notify. Schlimmer: bei sauberem JSON-Scan (`SCAN_OK=1`) feuert das Close-Gate (`if: env.SCAN_OK == '1' && env.SECURITY_FINDINGS != '1' && github.event_name != 'pull_request'`, `security.yml:564` / `security-hardened.yml:647`) und schliesst evtl. offene Security-Issues, obwohl ein Secret-Leak vorliegt. `.Secrets[]` wird nur im `if: failure()`-Diagnoseschritt gelesen (`security.yml:710`, `security-hardened.yml:793`) — also nie im Normalpfad. *Empfehlung:* In *Build security report* einen Block fuer `[.Results[]?.Secrets[]?]` ergaenzen: bei >0 `findings=1` setzen, Section (RuleID/Severity/Title/Datei) an `security_sections.md` haengen, in `security_summary.txt` + `security_fp_lines.txt` (Fingerprint) aufnehmen, Severity (Trivy-Secrets meist CRITICAL) ins `max_sev`-Mapping. Beide Dateien identisch patchen. - **[HIGH]** jq-Filter `startswith("CVE")` verwirft alle Nicht-CVE-Vuln-IDs (GHSA/PYSEC/RUSTSEC/GO …) — `security.yml:226` / `security-hardened.yml:284` — Die Report-Pipeline selektiert nur `.VulnerabilityID | startswith("CVE")`. Trivy meldet fuer npm/Go/Python/Rust- und viele OS-Pakete Schwachstellen oft nur mit `GHSA-`/`PYSEC-`/`RUSTSEC-`/`GO-`-IDs ohne zugeordnete CVE. Solche HIGH/CRITICAL-Funde fallen komplett aus `trivy_rows.md`; sind sie die einzigen Funde, bleibt `findings=0` → kein Issue/Notify und ggf. faelschliches Auto-Close ueber dasselbe Gate. Der Hardened-Pfad faengt einen Teil ueber OSV/pip-audit/node-audit ab, aber nur bei vorhandenem Lockfile/requirements; der reine Trivy-FS-Pfad (Container/OS-Pakete) bleibt blind. Der Fingerprint-`sed` nutzt bereits `[A-Z0-9-]+`, deckt GHSA also ab — nur der vorgelagerte jq-Filter ist zu eng. *Empfehlung:* Filter aufweiten, z.B. `select(.VulnerabilityID? | strings | test("^(CVE|GHSA|PYSEC|RUSTSEC|GO|DLA|DSA|USN|ALAS)-"; "i"))` oder schlicht `select(.VulnerabilityID? != null and .VulnerabilityID != "")`. Die osv.dev-Link-Vorlage funktioniert auch fuer GHSA. Beide Dateien angleichen. - **[MEDIUM]** Anti-stampede-Jitter (Sleep bis 300s) laeuft auf jedem Event inkl. `push`/`pull_request`/`workflow_dispatch` — `security.yml` (Step *Anti-stampede jitter*, ohne `if:`) / `security-hardened.yml:79-84` — Der erste Step schlaeft `RANDOM % 300` Sekunden ohne Event-Bedingung. Zweck ist die Entzerrung des Wochen-Cron ueber die Flotte; er feuert aber auch bei interaktiven PR-/Dispatch-Laeufen und verzoegert die Security-Feedbackschleife im Schnitt ~150s grundlos (relevant auf der langsamen dind-Runner-SSD). Korrektheitlich harmlos, aber unnoetige Latenz/Runner-Zeit fleet-weit. *Empfehlung:* Jitter-Step auf `if: github.event_name == 'schedule'` begrenzen. - **[LOW]** Pinning-Inkonsistenz `@v2` vs. `@main` (aktuell synchron, kein Laufzeit-Drift) — `promotion-gate.yml` (Header `@v2`), `examples/security-caller.yml` (`@main`), `security.yml`/`security-hardened.yml:17` (Header `@main`), `README.md` (empfiehlt `@v2`) — Das `v2`-Tag zeigt aktuell auf denselben Commit wie main HEAD (4586d50), d.h. KEIN funktionaler Drift. Das gemischte Modell ist aber fehleranfaellig: `@main`-Caller ziehen jede Aenderung sofort, `@v2`-Caller erst nach manuellem `git tag -f v2 && git push -f`. *Empfehlung:* Einheitliches Modell festlegen (empfohlen `@v2` als gepinntes Tag mit dokumentiertem Promote-Schritt, ODER bewusst `@main` mit Begruendung) und konsistent in Caller/Header/README abbilden. ## 4. Security > Repo ist OEFFENTLICH und absichtlich credential-clean. Befunde sind primaer Supply-Chain-Haertung; keine Exploit-Details. - **[MEDIUM]** osv-scanner und hadolint werden ohne Checksum-Verifikation und mit `|| true` von github.com/releases geladen — `security-hardened.yml:129-130` — Beide Binaries werden per `curl -fsSL -o /usr/local/bin/... && chmod +x ... || true` direkt installiert, ohne jede Integritaetspruefung. Das steht im Widerspruch zum gehaerteten Trivy-Pfad im selben Step, der den Release-Tarball gegen `checksums.txt` mit `sha256sum -c` verifiziert (`security-hardened.yml:114`). Ein manipuliertes Release-Asset / MITM / gekapertes Upstream-Repo wuerde unbemerkt ein Binary mit Schreibzugriff auf den Checkout und Zugang zum Job-Env ausfuehren; das `|| true` maskiert zusaetzlich Download-Fehler. Wirkung multipliziert sich ueber alle Hardened-Konsumenten. *Empfehlung:* Fuer osv-scanner/hadolint analog zu Trivy einen erwarteten SHA256 hinterlegen (Versionen sind ohnehin gepinnt: osv v2.3.5, hadolint v2.12.0) und nach Download mit `sha256sum -c` verifizieren, bei Mismatch fail-closed (kein `|| true` als Erfolgsmaske). - **[MEDIUM]** `main`-Branch nicht protected bei fleet-weiter Hebelwirkung — Forgejo Branch-API: `protected: false`, `required_approvals: 0`, `enable_status_check: false`; Commits unsigniert (`verified:false`, `gpg.error.not_signed_commit`) — Da ~50 Repos die Logik via `@main` ziehen, wird jeder Direkt-Push ohne Review/Status-Check sofort fleet-weit aktiv; ein fehlerhafter Push kann alle Scans gleichzeitig brechen. *Empfehlung:* Branch-Protection auf `main` aktivieren (Required-Status-Check = neue Self-CI, mind. 1 Approval bzw. bei Solo-Betrieb wenigstens Required-Status-Check) und `@v2` als empfohlenen Konsumenten-Pin etablieren. - **[LOW]** Ungepinnte `latest`-Installs von pip-audit, bandit und pnpm (nicht reproduzierbar, kein Integritaetscheck) — `security.yml`/`security-hardened.yml:202` (pip-audit), `security-hardened.yml:250` (bandit), `:216` (pnpm via `npm install -g pnpm --silent`) — Installiert ueber `pip install --break-system-packages --quiet` ohne Version/Hash bzw. global `latest`. Nicht reproduzierbar, kein Anker gegen kompromittierte Upstream-Pakete; gegenlaeufig zum sonst haertenden Design. Risiko niedriger als bei den Binaries (grosse, beobachtete Oekosysteme). *Empfehlung:* pip-audit/bandit/pnpm auf konkrete Versionen pinnen, idealerweise `--require-hashes` ueber constraints-Datei. - **[LOW]** Trivy-Versionsermittlung via ungeprueftem GitHub-API-Aufruf steuert die Download-URL (Pin nur als Notausgang) — `security.yml`/`security-hardened.yml:107-109` — Die Version stammt dynamisch aus der Releases-API (`grep tag_name`), der feste Pin `0.58.1` greift nur bei unerreichbarer API. Die `sha256sum`-Pruefung schuetzt gegen Transportfehler, nicht gegen eine konsistent boesartige Upstream-Antwort (Version + Referenz-Checksumme aus derselben Quelle). Deutlich besser als osv/hadolint, aber nicht deterministisch gepinnt. *Empfehlung:* Trivy-Version fest pinnen oder Referenz-Checksumme aus einer im Repo gepflegten Liste beziehen. - **[INFO]** Kein Klartext-Secret im Repo; Token-Handhabung ohne Logging-Leck (positiver Befund) — Verifiziert: ausschliesslich `${{ secrets.* }}`/`${{ vars.* }}`-Referenzen (GITHUB_TOKEN→FORGEJO_TOKEN, TELEGRAM_*, MATRIX_*, var MATRIX_HOMESERVER), keine `.env`/`.pem`/`credentials`-Dateien. Secrets nur ueber Env in curl-Header/jq-Args, nie per echo/printf geloggt; der Failure-Diagnose-Step dumpt nur Flags + Scan-Output. Notify-Secrets `required: false`. Entspricht der credential-clean-by-design-Doktrin. *Empfehlung:* Beibehalten; beim Editieren des Diagnose-Steps weiterhin keine Secret-tragenden Variablen ausgeben, curl nie mit `-v`/Trace. ## 5. Features & QOL - **[HIGH]** Keine Self-CI: das Library-Repo lintet/validiert seine eigenen Workflows nicht — kein `.forgejo/workflows/ci.yml`; nur die 3 Reusables + Caller existieren (Branch-API: nur `main`) — Die gesamte Logik lebt in inline-Bash (`set -euo pipefail`, je >700 Zeilen); jede Aenderung wirkt bei `@main` sofort fleet-weit. Genau diese Pipeline hatte bereits eine produktive Regression (PR #4 / Commit 4586d50: `clean scans no longer red the job (fp pipeline pipefail + -e abort)`) — ein leeres Clean-Scan-Resultat brach den Job unter Actions' default `bash -eo pipefail` ab. Ohne automatisches Netz (actionlint + shellcheck + `bash -n` + yamllint) gibt es kein Gate, das pipefail-/jq-/YAML-Fehler vor dem Wirksamwerden abfaengt. *Empfehlung:* Schlanke `ci.yml` (push/PR): actionlint + yamllint + jeden `run:`-Block via `bash -n` + shellcheck (Actions-faithful `bash -eo pipefail`), plus optional Dry-Run gegen synthetische `/tmp/trivy.json`-Fixtures (Clean- UND Findings-Fall — die 4586d50-Regression als Regressionstest festschreiben). Wirkungsvollste Einzelmassnahme. - **[MEDIUM]** Massive Code-Duplizierung zwischen security.yml und security-hardened.yml (~90% identisch) — `security-hardened.yml:25` Header: „Scan-Logik BYTE-IDENTISCH zur canonical security.yml v2.1.0" — Der gesamte Issue-Upsert-/Dedup-/fp-/Notify-/Close-/Self-Diagnostic-Apparat (mehrere hundert Zeilen) ist in beiden Dateien byte-fast-identisch dupliziert; nur die Scanner-Steps unterscheiden sich (Hardened: OSV/Hadolint/SAST/SARIF/SBOM). Jeder kuenftige Fix am Issue-/Notify-Pfad muss zweimal gepflegt werden → Drift-Risiko (z.B. fp-Fix landet nur in einer Datei). *Empfehlung:* Zu EINER `security.yml` mit `hardened`-(bool)/`sast`-Inputs konsolidieren (Extra-Scanner per `if:`), `security-hardened.yml` als duenner Alias-Caller; alternativ den gemeinsamen Issue-/Notify-Teil in einen separaten reusable `workflow_call`-Job auslagern, den beide aufrufen. - **[MEDIUM]** Supply-Chain-Inkonsistenz + kein renovate.json fuer die Tool-Versionen — `security-hardened.yml:129-130` (osv/hadolint ungepinnt-checksumlos, `|| true`); `renovate.json` nicht vorhanden — Tool-Pins (osv v2.3.5, hadolint v2.12.0, Trivy-Safety-Pin 0.58.1) veralten manuell; kein automatischer Drift-Hinweis. (Ueberschneidet sich mit dem MEDIUM-Supply-Chain-Befund in §4.) *Empfehlung:* Checksum-Verifikation fuer osv/hadolint (siehe §4) + `renovate.json` mit custom-regex-Manager auf die Release-URLs, damit Tool-Versionen automatisch aktuell bleiben. - **[LOW]** promotion-gate verweist in Fehlermeldungen/Summary auf das PRIVATE `orgamaster`-Repo, das public Caller nicht lesen koennen — `promotion-gate.yml` Steps *Check LICENSE*/*Check SECURITY.md* (`::error::… siehe orgamaster/docs/extern-rules.md`) + *Gate Summary* (Link auf `…/vr6syncro/orgamaster/…/docs/promotion-gate.md`); Header: „orgamaster ist privat" — Ein externer Caller, der durch das Gate faellt, bekommt Doku-Links auf ein nicht oeffnbares Repo → Sackgasse fuer genau die Zielgruppe (Public-Repos). *Empfehlung:* Spec-/Regel-Doku nach `docs/` in dieses public Repo portieren und die Fehlermeldungen/Summary auf public Pfade umbiegen. - **[LOW]** Fehlende Beispiel-/Doku-Dateien: `examples/caller-public.yml` referenziert, aber nicht vorhanden; kein CHANGELOG — `promotion-gate.yml` Header nennt `examples/caller-public.yml` (API 404 bestaetigt nicht vorhanden); kein `examples/promotion-gate-caller.yml`; kein `CHANGELOG.md`; Header-Versionierung `v2.2.0`/`v1.0.0` ohne Changelog — Konsumenten des Promotion-Gates/Hardened-Profils haben keine Copy-Paste-Vorlage; das manuell zu verschiebende `@v2`-Tag birgt das Risiko „Konsumenten merken Logik-Aenderung nicht". *Empfehlung:* `examples/caller-public.yml` (Promotion-Gate-Caller) + `examples/security-hardened-caller.yml` ergaenzen, tote Verweise korrigieren, `CHANGELOG.md` je v2-Tag-Bump pflegen. - **[LOW]** Scan-Artefakte (SARIF/SBOM/OSV-JSON) werden nur ins Working-Tree-`.scan-out/` kopiert, nicht als CI-Artefakt persistiert — `security-hardened.yml:808-812` (cp + `ls -la`, kein `actions/upload-artifact`); SBOM generiert `:183` (`trivy fs --format cyclonedx`) — Da der Workspace nach dem Job verworfen wird, sind die im Header beworbenen Compliance-Outputs (CycloneDX-SBOM „G4 EU-CRA", SARIF „G5") nach dem Lauf nicht mehr abrufbar. *Empfehlung:* Falls der Runner `actions/upload-artifact` unterstuetzt, SARIF/SBOM/OSV-JSON als benannte Artefakte hochladen (retention-days); alternativ SBOM bei getaggten Laeufen als Release-Asset/Generic-Package anhaengen. - **[LOW] _(unsicher — nicht reproduziert)_** Issue-Suche mit `limit=100` ohne Paginierung — `security.yml`/`security-hardened.yml:418,487,497,668` (`/issues?type=issues&state=open&limit=100`) — Bei Repos mit >100 offenen Issues koennte das Marker-/Dedup-/Close-Matching das relevante Security-Issue verpassen (Doppel-Anlage oder nicht-Schliessen). Fuer die meisten Flotten-Repos unkritisch; nur in sehr issue-reichen Repos relevant. *Als Hypothese gefuehrt:* tritt nur bei >100 offenen Issues auf, in diesem Repo nicht reproduziert. *Empfehlung:* Issue-Suche per Label/Marker filtern (statt alle offenen Issues zu ziehen) oder kleine page-Schleife. ## 6. Struktur, Ordnung, Dateileichen, Templates - **[MEDIUM]** Das Repo verletzt sein eigenes Promotion-Gate: LICENSE/SECURITY.md/CONTRIBUTING.md fehlen — `promotion-gate.yml` Steps *Check LICENSE/README/SECURITY.md/CONTRIBUTING.md* (`exit 1` bei Fehlen); Forgejo-API: LICENSE / SECURITY.md / CONTRIBUTING.md je 404, nur README.md (3619 B) vorhanden; Repo `private:false` — Die zentrale Library erzwingt fuer Public-Repos genau diese Pflichtdateien, erfuellt sie aber selbst nicht; wuerde am eigenen Gate scheitern. Fehlendes LICENSE ist bei einem zur Wiederverwendung gedachten Public-Repo zudem rechtlich relevant (ohne Lizenz „all rights reserved"); fehlende SECURITY.md bei einem Security-Tooling-Repo besonders auffaellig. *Empfehlung:* LICENSE (SPDX, z.B. MIT/Apache-2.0), SECURITY.md (Disclosure-Policy), CONTRIBUTING.md ergaenzen und das eigene Promotion-Gate als Self-Check laufen lassen (Dogfooding). - **[LOW]** Doku-Drift: promotion-gate referenziert nicht existierende Dateien — `promotion-gate.yml` Header (`examples/caller-public.yml`, `docs/promotion-gate.md`, `docs/extern-rules.md`) — Keine dieser Dateien/Ordner existiert im Repo (kein `docs/`, kein `examples/caller-public.yml` — API 404). Niemand kann den Promotion-Gate-Caller anhand der angegebenen Referenzen nachbauen. (Eng verwandt mit dem orgamaster-LOW in §5.) *Empfehlung:* Referenzierte Dateien anlegen oder die toten Verweise aus Header/Summary entfernen bzw. auf vorhandene README-Abschnitte umbiegen. - **[INFO]** Copy-Paste im security-hardened.yml-Header: Aufruf-Hinweis nennt `security.yml@main` statt `security-hardened.yml` — `security-hardened.yml:17` (`# uses: vr6syncro/ci-workflows/.forgejo/workflows/security.yml@main`) — Wer den Header copy-pastet, ruft versehentlich die Basic-Variante statt der Hardened-Variante auf. Rein dokumentarisch (YAML-Logik korrekt). *Empfehlung:* Header-Pfad auf `security-hardened.yml` korrigieren. - **[INFO]** Kein `renovate.json`, kein `.gitignore`, keine `.editorconfig` — git-tree (rekursiv) enthaelt keine dieser Dateien — Fuer ein reines YAML/Markdown-Repo funktional unkritisch (keine versehentlich committeten Artefakte gefunden), aber als Org-Konvention auffaellig (Renovate ist fleet-weit etabliert; siehe MEDIUM in §5 fuer die Tool-Version-Begruendung). *Empfehlung:* `renovate.json` ergaenzen (Action-/Release-Binary-Pins tracken); `.gitignore`/`.editorconfig` optional, niedrige Prioritaet. - **[INFO]** Saubere Struktur, keine Dateileichen, kein `.github`-Anti-Pattern (positiv) — git-tree (ref 4586d50): exakt 5 Dateien, 0 Datei-Artefakte (keine `*.bak`/`*.orig`/`.DS_Store`/Logs/Binaries), korrekt nur `.forgejo/workflows`. Namensgebung konsistent. Dient als Baseline-Einordnung der low/medium-Findings. *Empfehlung:* Keine Massnahme. ## 7. Status vs. offene Issues & PRs - **0 offene Issues, 0 offene PRs.** `list_repo_issues(state=open)` und `list_repo_pull_requests(state=open)` sind leer — kein Backlog, keine stale/konfliktbehafteten PRs, keine Duplikate. Kein Tracker-Abgleich noetig; das Repo ist im Status-Sinn schuldenfrei. - **PR-Historie:** #1 (notify state-change + PR report-only), #2 (resilient Trivy bootstrap), #3 (CI-failure self-report), #4 (clean scans no longer red) — **alle gemergt** (alle vom Owner). Die in dieser Analyse genannten Befunde sind durch diese PRs NICHT abgedeckt (sie betreffen die Fund-Auswertung/Governance, nicht Notify-Dedup/Bootstrap). Keine Ueberschneidung mit getrackten Vorgaengen. - **Branches/Tags:** nur `main` (kein vergessener Feature-Branch). Tag `v2` zeigt aktuell auf denselben Commit wie main HEAD (4586d50) → kein Pinning-Drift zur Analysezeit; das Restrisiko ist rein zukuenftig (manueller Tag-Move noetig). - **Drift local↔remote:** kein lokaler Klon vorhanden; Analyse vollstaendig gegen die Live-Forgejo-API (ref `main`). Kein Drift feststellbar. ## 8. Priorisierte Empfehlungen | Prio | Thema | Aufwand | Bezug | |------|-------|---------|-------| | **P1** | `.Secrets[]` im Report auswerten (findings/Notify/fp/max_sev) — verhindert unsichtbare Secret-Leaks + faelschliches Auto-Close | M | §3 CRITICAL | | **P1** | jq-Filter von `startswith("CVE")` auf alle Vuln-ID-Praefixe (GHSA/PYSEC/RUSTSEC/GO …) aufweiten | S | §3 HIGH | | **P1** | Self-CI (`ci.yml`: actionlint/yamllint/`bash -n`/shellcheck + Dry-Run-Fixtures) | M | §5 HIGH | | **P2** | osv-scanner/hadolint mit SHA256 verifizieren, `\|\| true`-Erfolgsmaske entfernen | S | §4 MEDIUM, §5 MEDIUM | | **P2** | `main`-Branch-Protection (Required-Status-Check + Approval) | S | §4 MEDIUM | | **P2** | LICENSE + SECURITY.md + CONTRIBUTING.md ergaenzen (eigenes Gate erfuellen) | S | §6 MEDIUM | | **P2** | Basic/Hardened-Duplizierung konsolidieren (Input-Flag oder gemeinsamer reusable Notify-Job) | M | §5 MEDIUM | | **P3** | Jitter auf `if: github.event_name == 'schedule'` begrenzen | S | §3 MEDIUM | | **P3** | Pinning-Modell `@main`/`@v2` vereinheitlichen + dokumentieren | S | §3 LOW | | **P3** | pip-audit/bandit/pnpm + Trivy-Version pinnen; `renovate.json` ergaenzen | S | §4 LOW, §5/§6 | | **P3** | Doku-Drift beheben (orgamaster-Links, `examples/caller-public.yml`, `docs/*`, hardened-Header-Pfad), CHANGELOG | S | §5/§6 LOW/INFO | | **P3** | SARIF/SBOM/OSV als CI-Artefakt/Release-Asset persistieren | S | §5 LOW | ## 9. Methodik & Vertrauensgrad - **Agenten:** Recon + 5 Blickrichtungen (bugs, security, features_qol, structure, status) + 1 adversariale Verifikation. - **Verifiziert:** Alle in §3-§7 gelisteten Findings wurden gegen den echten Code (ref `main` @ 4586d50) per Forgejo-API nachgelesen — `security.yml` und `security-hardened.yml` (813 Zeilen, vollstaendig base64-dekodiert), `promotion-gate.yml`, `examples/security-caller.yml`, `README.md`. Codestellen (Datei:Zeile) der Kernbefunde direkt bestaetigt: `--scanners vuln,secret`, der `.Vulnerabilities[]`-only Report-jq, `startswith("CVE")`, das `.Secrets[]`-only im failure-Step, das Close-Gate `SCAN_OK==1 && SECURITY_FINDINGS != '1'`, osv/hadolint ohne Checksum + `|| true`, Trivy-Checksum-Kontrast, Jitter ohne Event-Guard, `limit=100`-Abfragen. Fehlende Standarddateien (LICENSE/SECURITY.md/CONTRIBUTING.md/`examples/caller-public.yml`) via API-404 bestaetigt. Branch-/PR-/Tag-Lage und „0 offene Vorgaenge" via Live-API verifiziert. - **Verworfen/korrigiert:** Ein Agent zitierte README als „enthaelt keine Secrets, nur ${{ secrets.* }}-Referenzen" — bestaetigt (Wortlaut leicht abweichend, inhaltlich korrekt). Der `limit=100`-Befund wurde auf LOW/unsicher abgestuft, weil er nur bei >100 offenen Issues greift und in diesem Repo nicht reproduzierbar ist. Doppelte Supply-Chain-/ Promotion-Gate-/Pinning-Befunde mehrerer Agenten wurden zu je einem Eintrag konsolidiert. - **Nicht (vollstaendig) pruefbar:** Reales Laufzeitverhalten der Workflows (keine Runner-Log-API in Forgejo 15; keine Ausfuehrung moeglich) — die Korrektheitsbefunde sind statisch aus dem Code + jq-/Trivy-Semantik belegt, nicht aus einem Live-Lauf. Tatsaechliche Fork-PR-Exposition haengt von der Actions-Policy der ~50 Konsumenten-Repos ab (nicht aus diesem Repo allein bestimmbar). Kein lokaler Klon vorhanden — gesamte Analyse rein API-basiert. - **Sicherheit:** Keine Secret-Werte ausgegeben; Repo ist credential-clean (nur Referenzen). Keine Exploit-Schritte, keine internen Hosts/IPs im Issue.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
vr6syncro/ci-workflows#5
No description provided.