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.
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.