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

Closed
opened 2026-06-04 05:39:48 +02:00 by vr6syncro · 1 comment
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_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.
# 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.
Author
Owner

Geschlossen beim Aufräumen am 01.09.2026.

Das hier ist ein Bericht, keine Aufgabe. Es ist eine Zustandsaufnahme des Repos vom 04.06.2026. Sie wurde in 89 Tagen kein einziges Mal kommentiert und beschreibt einen Codestand, den es so nicht mehr gibt.

Solche Berichte in der Liste der offenen Punkte zu führen, macht die Liste unbrauchbar: Von 571 offenen Einträgen über alle Repos waren 60 solche Berichte — jeder 10 bis 30 KB lang, keiner mit einer Aufgabe darin, die jemand abarbeiten könnte.

Es geht nichts verloren. Forgejo behält geschlossene Einträge vollständig; der Text bleibt hier lesbar und durchsuchbar.

Wenn aus dieser Analyse etwas offen ist, gehört es als eigener Eintrag mit einer klaren Aufgabe hierher — nicht als Bericht.

Geschlossen beim Aufräumen am 01.09.2026. **Das hier ist ein Bericht, keine Aufgabe.** Es ist eine Zustandsaufnahme des Repos vom 04.06.2026. Sie wurde in 89 Tagen kein einziges Mal kommentiert und beschreibt einen Codestand, den es so nicht mehr gibt. Solche Berichte in der Liste der offenen Punkte zu führen, macht die Liste unbrauchbar: Von 571 offenen Einträgen über alle Repos waren **60 solche Berichte** — jeder 10 bis 30 KB lang, keiner mit einer Aufgabe darin, die jemand abarbeiten könnte. **Es geht nichts verloren.** Forgejo behält geschlossene Einträge vollständig; der Text bleibt hier lesbar und durchsuchbar. Wenn aus dieser Analyse etwas offen ist, gehört es als eigener Eintrag mit einer klaren Aufgabe hierher — nicht als Bericht.
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.