Deep Analysis 2026-06-04 — ci-workflows #5
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Deep Analysis 2026-06-04 — ci-workflows
Autonome Multi-Agent-Analyse (Recon + 5 Blickrichtungen + adversariale Verifikation). Stand 2026-06-04.
1. Ueberblick & Einordnung
full(zentrale, oeffentliche Reusable-Forgejo-Actions-Library der vr6syncro-Flotte).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) undpromotion-gate.yml(v1.0.0, erzwingt Pflichtdateien in Public-Repos). Konsumenten binden via thin callersecrets: inheritein.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.
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.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_OKvs.SECURITY_FINDINGS,trap write_findings EXITals Close-Gate-Schutz,fp-basiertes Notify-Dedup, alle zustandsaendernden Schritte per
github.event_name != 'pull_request'gegated, und dasRepo ist credential-clean (nur
${{ secrets.* }}/${{ vars.* }}-Referenzen, kein Klartext-Secret). Abwertung von Aauf 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,
mainungeschuetzt,~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 zufindingsbei →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 imif: 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 >0findings=1setzen, Section (RuleID/Severity/Title/Datei) ansecurity_sections.mdhaengen, insecurity_summary.txt+security_fp_lines.txt(Fingerprint) aufnehmen, Severity (Trivy-Secrets meist CRITICAL) insmax_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 mitGHSA-/PYSEC-/RUSTSEC-/GO--IDs ohne zugeordnete CVE. Solche HIGH/CRITICAL-Funde fallen komplett austrivy_rows.md; sind sie die einzigen Funde, bleibtfindings=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-sednutzt 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 schlichtselect(.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, ohneif:) /security-hardened.yml:79-84— Der erste Step schlaeftRANDOM % 300Sekunden 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 aufif: github.event_name == 'schedule'begrenzen.[LOW] Pinning-Inkonsistenz
@v2vs.@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) — Dasv2-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 manuellemgit tag -f v2 && git push -f. Empfehlung: Einheitliches Modell festlegen (empfohlen@v2als gepinntes Tag mit dokumentiertem Promote-Schritt, ODER bewusst@mainmit Begruendung) und konsistent in Caller/Header/README abbilden.4. Security
[MEDIUM] osv-scanner und hadolint werden ohne Checksum-Verifikation und mit
|| truevon github.com/releases geladen —security-hardened.yml:129-130— Beide Binaries werden percurl -fsSL -o /usr/local/bin/... && chmod +x ... || truedirekt installiert, ohne jede Integritaetspruefung. Das steht im Widerspruch zum gehaerteten Trivy-Pfad im selben Step, der den Release-Tarball gegenchecksums.txtmitsha256sum -cverifiziert (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|| truemaskiert 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 mitsha256sum -cverifizieren, bei Mismatch fail-closed (kein|| trueals 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@mainziehen, wird jeder Direkt-Push ohne Review/Status-Check sofort fleet-weit aktiv; ein fehlerhafter Push kann alle Scans gleichzeitig brechen. Empfehlung: Branch-Protection aufmainaktivieren (Required-Status-Check = neue Self-CI, mind. 1 Approval bzw. bei Solo-Betrieb wenigstens Required-Status-Check) und@v2als 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 vianpm install -g pnpm --silent) — Installiert ueberpip install --break-system-packages --quietohne Version/Hash bzw. globallatest. 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-hashesueber 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 Pin0.58.1greift nur bei unerreichbarer API. Diesha256sum-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-Secretsrequired: 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: nurmain) — Die gesamte Logik lebt in inline-Bash (set -euo pipefail, je >700 Zeilen); jede Aenderung wirkt bei@mainsofort fleet-weit. Genau diese Pipeline hatte bereits eine produktive Regression (PR #4 / Commit4586d50:clean scans no longer red the job (fp pipeline pipefail + -e abort)) — ein leeres Clean-Scan-Resultat brach den Job unter Actions' defaultbash -eo pipefailab. Ohne automatisches Netz (actionlint + shellcheck +bash -n+ yamllint) gibt es kein Gate, das pipefail-/jq-/YAML-Fehler vor dem Wirksamwerden abfaengt. Empfehlung: Schlankeci.yml(push/PR): actionlint + yamllint + jedenrun:-Block viabash -n+ shellcheck (Actions-faithfulbash -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:25Header: „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 EINERsecurity.ymlmithardened-(bool)/sast-Inputs konsolidieren (Extra-Scanner perif:),security-hardened.ymlals duenner Alias-Caller; alternativ den gemeinsamen Issue-/Notify-Teil in einen separaten reusableworkflow_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.jsonnicht 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.jsonmit 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.ymlSteps 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 nachdocs/in dieses public Repo portieren und die Fehlermeldungen/Summary auf public Pfade umbiegen.[LOW] Fehlende Beispiel-/Doku-Dateien:
examples/caller-public.ymlreferenziert, aber nicht vorhanden; kein CHANGELOG —promotion-gate.ymlHeader nenntexamples/caller-public.yml(API 404 bestaetigt nicht vorhanden); keinexamples/promotion-gate-caller.yml; keinCHANGELOG.md; Header-Versionierungv2.2.0/v1.0.0ohne 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.ymlergaenzen, tote Verweise korrigieren,CHANGELOG.mdje 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, keinactions/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 Runneractions/upload-artifactunterstuetzt, 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=100ohne 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.ymlSteps Check LICENSE/README/SECURITY.md/CONTRIBUTING.md (exit 1bei Fehlen); Forgejo-API: LICENSE / SECURITY.md / CONTRIBUTING.md je 404, nur README.md (3619 B) vorhanden; Repoprivate: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.ymlHeader (examples/caller-public.yml,docs/promotion-gate.md,docs/extern-rules.md) — Keine dieser Dateien/Ordner existiert im Repo (keindocs/, keinexamples/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@mainstattsecurity-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 aufsecurity-hardened.ymlkorrigieren.[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.jsonergaenzen (Action-/Release-Binary-Pins tracken);.gitignore/.editorconfigoptional, niedrige Prioritaet.[INFO] Saubere Struktur, keine Dateileichen, kein
.github-Anti-Pattern (positiv) — git-tree (ref4586d50): 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
list_repo_issues(state=open)undlist_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.main(kein vergessener Feature-Branch). Tagv2zeigt aktuell auf denselben Commit wie main HEAD (4586d50) → kein Pinning-Drift zur Analysezeit; das Restrisiko ist rein zukuenftig (manueller Tag-Move noetig).main). Kein Drift feststellbar.8. Priorisierte Empfehlungen
.Secrets[]im Report auswerten (findings/Notify/fp/max_sev) — verhindert unsichtbare Secret-Leaks + faelschliches Auto-Closestartswith("CVE")auf alle Vuln-ID-Praefixe (GHSA/PYSEC/RUSTSEC/GO …) aufweitenci.yml: actionlint/yamllint/bash -n/shellcheck + Dry-Run-Fixtures)|| true-Erfolgsmaske entfernenmain-Branch-Protection (Required-Status-Check + Approval)if: github.event_name == 'schedule'begrenzen@main/@v2vereinheitlichen + dokumentierenrenovate.jsonergaenzenexamples/caller-public.yml,docs/*, hardened-Header-Pfad), CHANGELOG9. Methodik & Vertrauensgrad
main@4586d50) per Forgejo-APInachgelesen —
security.ymlundsecurity-hardened.yml(813 Zeilen, vollstaendig base64-dekodiert),promotion-gate.yml,examples/security-caller.yml,README.md. Codestellen (Datei:Zeile) der Kernbefunde direktbestaetigt:
--scanners vuln,secret, der.Vulnerabilities[]-only Report-jq,startswith("CVE"), das.Secrets[]-only im failure-Step, das Close-GateSCAN_OK==1 && SECURITY_FINDINGS != '1', osv/hadolint ohneChecksum +
|| 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.
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.
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.
keine internen Hosts/IPs im Issue.