diff --git a/STATUS.md b/STATUS.md index 768952d..8b4a31e 100644 --- a/STATUS.md +++ b/STATUS.md @@ -84,13 +84,11 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md). | [0072](docs/issues/0072-gitops-34-dsgvo-datenschutz-compliance-konkretisieren.md) | low | open | DSGVO/Datenschutz-Compliance konkretisieren | -## Active design docs (1) +## Active design docs (0) -| Design | Gate | Title | -|---|---|---| -| [2026-08-22-k3s-patch-1-34-10](docs/design/2026-08-22-k3s-patch-1-34-10.md) | gate-4 | Design: k3s v1.34.6 → v1.34.10 — die mitgelieferten Komponenten nachziehen | +_none active_ -## ADRs (27) +## ADRs (28) | ADR | Status | Title | |---|---|---| @@ -121,8 +119,9 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md). | [0025](docs/adr/0025-egress-ausnahmen-als-cidr-ausser-hinter-cdn.md) | accepted | ADR-0025: Egress-Ausnahmen werden als CIDR gepinnt — außer hinter einem CDN | | [0026](docs/adr/0026-pruefziele-werden-abgeleitet-nicht-gepflegt.md) | accepted | ADR-0026: Prüfziele werden abgeleitet, nicht gepflegt — und das Ausbleiben der Herleitung alarmiert | | [0027](docs/adr/0027-zuletzt-eigener-meilenstein.md) | accepted | ADR-0027: „Zuletzt" wird ein eigener Meilenstein (M6) | +| [0028](docs/adr/0028-ingress-bleibt-k3s-verwaltet-flags-gestrichen.md) | accepted | ADR-0028: Der Ingress bleibt vorerst k3s-verwaltet — die drei nie wirksamen Flags werden gestrichen | -## Open AARs (10) +## Open AARs (11) - [AAR — Alle geplanten Prüfungen waren dauerhaft rot und meldeten damit nichts mehr](docs/aar/2026-08-18-alle-pruefungen-dauerhaft-rot.md) - [AAR — Nach der Freischaltung sendete Safari ungefiltert weiter](docs/aar/2026-08-18-safari-sendete-ungefiltert.md) @@ -134,6 +133,7 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md). - [AAR: Deploy der abgeleiteten CVE-Zielmenge (#0106)](docs/aar/2026-08-21-cve-zielmenge-deploy.md) - [AAR: Die Anmeldung brach nach dem ESS-Sprung — eine Netzregel von heute Morgen](docs/aar/2026-08-21-mas-haproxy-netzregel.md) - [AAR: Die Ausrollstrecke stand eine Stunde — der Push-Spiegel kam nicht durch](docs/aar/2026-08-21-spiegel-ausfall.md) +- [AAR: 42 Scan-Berichte gelöscht, und das Dashboard meldete dafür „vollständig"](docs/aar/2026-08-23-zielmenge-eingebrochen.md) ## Fehlerklassen (18) diff --git a/docs/aar/2026-08-23-zielmenge-eingebrochen.md b/docs/aar/2026-08-23-zielmenge-eingebrochen.md new file mode 100644 index 0000000..9806921 --- /dev/null +++ b/docs/aar/2026-08-23-zielmenge-eingebrochen.md @@ -0,0 +1,120 @@ +--- +type: aar +status: open +date: 2026-08-23 +related: + - "docs/design/done/2026-08-22-k3s-patch-1-34-10.md" + - "docs/adr/0026-pruefziele-werden-abgeleitet-nicht-gepflegt.md" + - "docs/issues/0106-cve-scan-deckt-nur-die-haelfte-zielliste-ist-handgepflegt.md" +--- + +# AAR: 42 Scan-Berichte gelöscht, und das Dashboard meldete dafür „vollständig" + +**Schwere:** MEDIUM (kein Dienstausfall; die Schwachstellen-Sicht war blind und +sah dabei perfekt aus) · **Dauer:** ~00:20 bis ~00:40 · **Ursache:** eigener +Entwurfsfehler in Code vom Vortag + +## What was planned / expected + +Nach dem k3s-Patch sollte eine Scan-Runde die neuen Fassungen aufnehmen und die +alten Berichte abräumen. Erwartet: Zielmenge bleibt 54, sechs `rancher/*`-Ziele +tauschen ihre Fassung, `cve_targets_orphaned` steigt kurz und fällt wieder. + +## What happened + +Der k3s-Neustart nahm kube-state-metrics und Alloys Log-Tailer mit. Beide kamen +**nicht von selbst zurück** — ksm hing im CrashLoop, Alloy protokollierte +`"tailer stopped; will retry"` und lieferte danach nichts mehr. Damit war +`kube_pod_container_info` in Prometheus für rund zwölf Minuten **leer**. + +Genau in dieses Fenster fiel die stündliche Herleitung der Zielmenge. + +``` +Cluster-Quelle: 39 Ziele -> 0 (Abfrage erfolgreich, null Zeilen) +Betriebs-Host: 12 Ziele -> 12 +Registry: 7 Ziele -> 0 +Soll gesamt: 54 -> 12 +``` + +Der Exporter schrieb `targets.txt` mit 12 Zeilen. Die Scan-Runde las die Datei +und **löschte jeden Bericht, dessen Ziel nicht mehr darin stand — 42 Stück.** + +Danach meldete die Anlage: + +| | | +|---|---| +| `cve_target_coverage_ratio` | **1,0** | +| `cve_targets_missing` | **0** | +| `cve_targets_orphaned` | **0** | +| `cve_critical_offen` | **0** | +| CRITICAL / HIGH | 99 / 1392 → **9 / 286** | + +⚠️ **Die Zahlen sahen makellos aus, weil die Daten weg waren.** + +Behoben durch Neustart des Exporters (Zielmenge zurück auf 54, mit den neuen +k3s-Fassungen) und eine zweite Scan-Runde. Verloren sind nur die +Erstfund-Zeitstempel der 42 Ziele. + +## Why the difference + +**Routing-Klasse: spec issue.** Der Code tat, was er sollte; was er sollte, war +falsch gedacht. + +Die Herleitung kennt zwei Ausgänge — Erfolg und Ausnahme. **Sie kennt den +dritten nicht: erfolgreich und leer.** Eine PromQL-Abfrage gegen eine Datenbank +ohne Daten ist kein Fehler; sie liefert null Zeilen und HTTP 200. + +Und die drei Absicherungen, die ich am Vortag genau gegen „still schrumpfende +Zielmenge" gebaut hatte, greifen alle daneben — jede aus einem für sich +vertretbaren Grund: + +| Regel | warum sie schwieg | +|---|---| +| `CveTargetsNoneDesired` | prüft die **Gesamtzahl** auf 0. Sie war 12. | +| `CveTargetSourceStale` | prüft den **Zeitstempel**. Ein leerer Erfolg erneuert ihn. | +| Wache `brauchbar` | prüft die **Vereinigung** auf „nicht leer", nicht jede Quelle. | + +Die Lücke saß exakt zwischen den dreien. Alle drei zusammen decken „alles weg" +und „nichts mehr gehört" ab — **nicht** „zwei von drei Quellen liefern nichts, +und das gilt als Erfolg". + +⚠️ **Der zweite Fehler ist der ältere:** Auch bei einer echten Ausnahme setzte +die Herleitung die Ziele der Quelle auf `set()`. Ein Prometheus-Ausfall hätte +also denselben Schaden angerichtet — nur wäre dann wenigstens der Zeitstempel +gealtert. + +## Learnings + +- ⚠️ **„Erfolgreich" und „brauchbar" sind zwei verschiedene Aussagen.** Bei + jeder Abfrage, deren Ergebnis eine Menge ist, gehört die leere Menge + ausdrücklich behandelt — und zwar mit der Frage „hat diese Quelle vorher + schon einmal geliefert?". +- **Absicherungen, die einzeln richtig sind, lassen zusammen eine Lücke.** Drei + Regeln gegen dieselbe Gefahr sind kein Beweis, dass die Gefahr abgedeckt ist. + Was fehlt, ist der Fall dazwischen — und den findet man nicht durch Nachdenken + über die Regeln, sondern durch das Ereignis. +- ⚠️ **Ein Werkzeug, das Zustand löscht, braucht eine strengere Eingangsprüfung + als eines, das nur meldet.** Der Scanner löscht Berichte anhand einer Liste, + die er nicht selbst verantwortet. Ein Einbruch dieser Liste hätte ihn stutzig + machen müssen, nicht nur den Exporter. +- **Der Schaden wäre ohne Nachmessen unbemerkt geblieben.** Ich habe ihn nur + gesehen, weil ich nach dem k3s-Sprung die Zielmenge von Hand geprüft habe. + Ein Blick aufs Dashboard hätte „alles grün" gezeigt. + +## Actions + +- [x] **Leerer Erfolg gilt als Ausfall**, wenn die Quelle vorher geliefert hat: + alter Stand bleibt, Zeitstempel altert, `CveTargetSourceStale` greift + (`9a3b1d1`). +- [x] **Eine Ausnahme verliert die Ziele der Quelle nicht mehr** — vorher + `set()`, jetzt der letzte bekannte Stand. +- [x] **Fünfte Regel `CveZielmengeEingebrochen`**: Rückgang um mehr als 40 % + gegenüber 24 h. Feuert bewusst auch bei gewolltem Rückbau. +- [x] Fünf Zusicherungen gegen die echte `herleiten()`, drei Sabotagen fahren + sie rot. +- [ ] **Offen:** Der Fix ist **nicht ausgerollt**. Auf dem Host läuft weiter die + Fassung, die einen leeren Erfolg für einen Erfolg hält. +- [ ] **Offen:** Nichts meldet, wenn kube-state-metrics oder Alloys Tailer nach + einem Neustart nicht zurückkommen. Zwölf Minuten ohne Cluster-Logs sind + niemandem aufgefallen — auch das gehört gemeldet, und zwar unabhängig von + der CVE-Kette. diff --git a/docs/adr/0028-ingress-bleibt-k3s-verwaltet-flags-gestrichen.md b/docs/adr/0028-ingress-bleibt-k3s-verwaltet-flags-gestrichen.md new file mode 100644 index 0000000..11d83b9 --- /dev/null +++ b/docs/adr/0028-ingress-bleibt-k3s-verwaltet-flags-gestrichen.md @@ -0,0 +1,95 @@ +--- +type: adr +id: "0028" +status: accepted +date: 2026-08-23 +supersedes: null +superseded_by: null +related: + - "docs/design/done/2026-08-22-k3s-patch-1-34-10.md" + - "docs/issues/0110-haertung-lebt-auf-dem-host-das-repo-weiss-nichts-davon.md" +--- + +# ADR-0028: Der Ingress bleibt vorerst k3s-verwaltet — die drei nie wirksamen Flags werden gestrichen + +## Kontext + +Die systemd-Unit des Clusters trug seit der Installation am 2026-04-21 +unverändert diese Startzeile: + +``` +/usr/local/bin/k3s server server --disable=traefik --disable=servicelb --node-ip=10.0.0.2 +``` + +⚠️ **`server` steht zweimal.** Das zweite ist ein Positionsargument; alles +danach wird nicht mehr als Flag gelesen. Vier Monate lang hat also **keines** +der drei Flags gewirkt. Belegt am laufenden System, nicht hergeleitet: + +| Beleg | Wert | +|---|---| +| `k3s.io/node-args` | `["server","server","--disable","traefik","--disable","servicelb","--node-ip","10.0.0.2"]` | +| `k3s.io/internal-ip` | `49.13.132.245` — die **öffentliche** Adresse | +| `server/manifests/` | enthält `traefik.yaml`, geschrieben beim letzten Start | +| Cluster | Traefik **und** `svclb-traefik` laufen | + +Aufgefallen ist das beim Vorbereiten des Patches auf v1.34.10, weil das +Installationsskript die Unit **neu schreibt**. Damit stand die Frage nicht mehr +offen: Was in der neuen Zeile steht, wird beim nächsten Start wirksam — und +zwar sofort und vollständig. + +## Optionen + +**A — Die Flags streichen, den Ist-Zustand zur Absicht machen.** Traefik und +servicelb bleiben k3s-verwaltet; `--node-ip` wird bewusst gesetzt, weil es ein +echter Parameter ist und der Knoten sonst weiter seine öffentliche Adresse als +`InternalIP` führt. + +**B — Die Flags wirksam machen.** Setzt voraus, dass vorher ein Ersatz für den +Ingress bereitsteht. Ohne den heißt „wirksam" schlicht: **kein eingehender +Verkehr mehr**, `axion1337.chat` und `wiki.axion1337.chat` inbegriffen. + +**C — Die kaputte Zeile wörtlich erhalten.** Das Installationsskript müsste +daran gehindert werden, und der nächste Mensch stolpert genauso. + +## Entscheidung + +**A**, mit zwei Ergänzungen, die beim Ausarbeiten dazukamen: + +``` +k3s server --node-ip=10.0.0.2 --node-external-ip=49.13.132.245 --tls-san=49.13.132.245 +``` + +- ⚠️ **`--node-external-ip`**, weil `servicelb` die Knoten-Adresse + veröffentlicht: der Traefik-Dienst **und jeder Ingress** trugen bis dahin + `49.13.132.245`. Ohne dieses Flag stünde dort künftig `10.0.0.2`. +- ⚠️ **`--tls-san`**, weil die SANs des API-Zertifikats `10.0.0.2` nicht + enthielten. Beim Adresswechsel wird es neu erzeugt; ohne das Flag kann die + öffentliche Adresse herausfallen — und die Kubeconfig zeigt genau dorthin. + +Beide waren in der ersten Fassung dieser Entscheidung **nicht** enthalten und +kamen erst durch Nachsehen dazu. Das gehört hierhin, weil es zeigt, dass +„einen Parameter setzen" bei k3s selten nur einen Parameter betrifft. + +## Konsequenzen + +- Der Ingress gehört **k3s**, nicht dem Repo. Wer ihn ändern will, ändert + k3s-Vorgaben oder legt eine `HelmChartConfig` an — heute existiert keine. +- Der Knoten führt endlich eine private `InternalIP` und eine öffentliche + `ExternalIP`. Die öffentliche **IPv6** verliert dabei ihre Rolle als + `InternalIP`; die Pod-Netze sind ohnehin IPv4-only. +- ⚠️ **Option B bleibt der nachhaltigere Weg und ist nicht verworfen, sondern + vertagt.** Traefik unter Flux wäre im Repo statt in einem Binary — genau die + Richtung, in die dieses Projekt sonst geht. Es braucht einen eigenen Zuschnitt + mit eigenem Ausfallfenster, nicht eine Zeile in einem Patch-Upgrade. Wer das + angeht, setzt danach `--disable=traefik --disable=servicelb` — und dann sind + sie zum ersten Mal wirklich gemeint. +- ⚠️ **Die Unit liegt weiterhin in keinem Repository.** Diese Entscheidung + beschreibt sie, sie versioniert sie nicht. Das ist der Cluster-Anteil von + [#0110](../issues/0110-haertung-lebt-auf-dem-host-das-repo-weiss-nichts-davon.md). + +## Warum das aufgeschrieben wird + +Ohne diesen Eintrag schreibt der nächste Mensch die Flags aus guter Absicht +zurück — sie sahen ja vernünftig aus. Und die vier Monate, in denen sie nichts +taten, sind kein Argument gegen sie, sondern gegen die Annahme, eine +Konfigurationsdatei beschreibe den Zustand, den sie beschreibt. diff --git a/docs/design/2026-08-22-k3s-patch-1-34-10.md b/docs/design/done/2026-08-22-k3s-patch-1-34-10.md similarity index 86% rename from docs/design/2026-08-22-k3s-patch-1-34-10.md rename to docs/design/done/2026-08-22-k3s-patch-1-34-10.md index b93f4ca..ed92d11 100644 --- a/docs/design/2026-08-22-k3s-patch-1-34-10.md +++ b/docs/design/done/2026-08-22-k3s-patch-1-34-10.md @@ -1,6 +1,6 @@ --- type: design -status: gate-4 +status: done date: 2026-08-22 size: L related: @@ -280,7 +280,7 @@ Helm-Wert, keine Zeile in einem Repo. ⚠️ **Und das ist selbst ein Befund.** Die gesamte Konfiguration dieses Clusters steht in einer Unit auf einem Host und in **keinem** Repository. Genau die -Lücke, die [#0110](../issues/0110-haertung-lebt-auf-dem-host-das-repo-weiss-nichts-davon.md) +Lücke, die [#0110](../../issues/0110-haertung-lebt-auf-dem-host-das-repo-weiss-nichts-davon.md) für den Betriebs-Stack beschreibt — hier trifft sie den Cluster selbst. **Neue ExecStart-Zeile:** @@ -362,3 +362,55 @@ wird bewusst gesetzt." Mit Beleg, warum die Flags vier Monate lang nichts taten — sonst schreibt der Nächste sie aus guter Absicht zurück. > **STOP — wartet auf Gate-3/4-Freigabe.** + +## Gate 5 — Abnahme + +Durchgeführt 2026-08-23, 00:11:44 CEST. Der Dienst war von der Sicherung bis +zum Start unten; alle Container waren binnen ~70 s wieder oben. + +| | Kriterium | Ergebnis | +|---|---|---| +| 1 | v1.34.10+k3s1, sechs Komponenten auf den mitgelieferten Fassungen | ✅ alle sechs, dazu containerd 2.2.2 → **2.2.5-k3s2** | +| 2 | −15 CRITICAL, **−189 HIGH** auf den Komponenten; die sechs Einträge entfernt | ✅ **278 → 89 HIGH, 15 → 0 CRITICAL**, exakt die Vorhersage; Einträge entfernt | +| 3 | Plattform vollständig oben | ✅ nur der `concierge-bot`, der schon 13 Tage vorher an einem fehlenden Secret hing | +| 4 | Ingress von außen mit gültigem Zertifikat | ✅ sechs Hosts, alle TLS-verify 0; `_matrix/client/versions` 200, MAS-OIDC 200 | +| 5 | NetworkPolicies passen noch | ✅ sie verweisen auf `kube-system` per Label — unberührt | +| 6 | Rückweg vor dem Start hergestellt | ✅ Binary, Unit und 60-MB-`db` geprüft vorhanden | + +**Die zwei nachgezogenen Flags haben getan, wofür sie da waren:** Der +Traefik-Dienst und jeder Ingress veröffentlichen weiterhin `49.13.132.245` +(`--node-external-ip`), und die Zertifikats-SANs tragen jetzt **beide** +Adressen, `kubectl` von außen antwortet `ok` (`--tls-san`). + +### ⚠️ Zwei Bauteile kamen nicht von selbst zurück + +| | | +|---|---| +| **kube-state-metrics** | CrashLoop — startete, während die API noch nicht da war, und blieb im Backoff. Pod neu → läuft. | +| **Alloys Log-Tailer** | ⚠️ **Zwölf Minuten ohne Cluster-Logs.** Das Protokoll sagte `"tailer stopped; will retry"` und lieferte danach nichts mehr. Pod neu → Logs 1 s alt. | + +Beide fielen nur auf, weil nachgemessen wurde. Nichts hat gemeldet, dass die +Log-Strecke des gesamten Clusters stillstand — der Betriebs-Host lieferte +weiter, also sah die Überwachung lebendig aus. + +### ⚠️ Und ein Vorfall, den dieser Sprung ausgelöst hat + +Ebendieses Fenster ohne Cluster-Metriken traf die stündliche Herleitung der +Scan-Zielmenge. Die Abfrage lief **erfolgreich und leer** durch, die Zielmenge +fiel von 54 auf 12, und die folgende Scan-Runde löschte **42 Berichte** — +während das Dashboard Deckung **1,0** meldete. Eigener AAR: +`docs/aar/2026-08-23-zielmenge-eingebrochen.md`. Behoben, abgesichert, und der +Fix wartet auf das Ausrollen. + +**Das ist die eigentliche Lehre dieses Vorhabens.** Der Fassungssprung selbst +war so unspektakulär wie geplant. Teuer war, was ein Neustart in den *anderen* +Bauteilen auslöst — und dass zwei davon ihr eigenes Scheitern als „retry" +protokollieren. + +### Was noch aussteht + +- Der Fix an der Herleitung ist gepusht (`9a3b1d1`), aber **nicht ausgerollt**. +- Nichts meldet, wenn die Cluster-Log-Strecke stillsteht. +- Option B aus [ADR-0028](../../adr/0028-ingress-bleibt-k3s-verwaltet-flags-gestrichen.md) + — Traefik unter Flux — bleibt der nachhaltigere Weg und ist vertagt, nicht + verworfen. diff --git a/docs/ledger/2026-08-22-k3s-patch-1-34-10.md b/docs/ledger/2026-08-22-k3s-patch-1-34-10.md index 7beb870..bda87c5 100644 --- a/docs/ledger/2026-08-22-k3s-patch-1-34-10.md +++ b/docs/ledger/2026-08-22-k3s-patch-1-34-10.md @@ -2,9 +2,9 @@ type: ledger date: 2026-08-22 size: L -status: open +status: closed related: - - "docs/design/2026-08-22-k3s-patch-1-34-10.md" + - "docs/design/done/2026-08-22-k3s-patch-1-34-10.md" - "docs/issues/0051-cve-remediation-pass.md" --- @@ -17,11 +17,18 @@ related: | 1 | bf2d87a | sorb | DONE | Umfang, sechs Abnahmekriterien, zwei offene Entscheidungen (Ausfallzeit, Traefik-Chart-Major); ⚠️ korrigiert die eigene Aussage „grosses Vorhaben" — es ist ein Patch auf der eigenen Minor-Reihe. | | 2 | 1d0d5f1 | sorb | DONE_WITH_CONCERNS | Fassungen gepinnt, Traefik-Major gerendert (identisch), Ausfallzeit aus der Historie gemessen (~70 s); ⚠️ Fund: drei k3s-Flags sind seit der Installation unwirksam, und das Installationsskript schreibt die Unit neu. | | 3+4 | 3e55a42 | sorb | DONE | Eine Datei, sechs Slices; ExecStart um `--node-external-ip` und `--tls-san` ergaenzt, weil `--node-ip` allein die veroeffentlichte Adresse und das API-Zertifikat mitreisst. | +| 5 | PENDING | sorb | DONE_WITH_CONCERNS | Alle sechs Kriterien erfuellt, 278 -> 89 HIGH und 15 -> 0 CRITICAL exakt wie vorhergesagt; ⚠️ der Neustart hat zwei Bauteile lahmgelegt und einen Vorfall an der Scan-Zielmenge ausgeloest. | ## Slices | slice | commit | status | note | |---|---|---|---| +| 0 Vorher-Bild | — | DONE | Knoten, Pods, SANs, Ingress-Antworten, CVE-Zahlen festgehalten; Images vorgezogen. | +| 1 Sicherung | — | DONE | Binary, Unit und 60-MB-`db` bei gestopptem Dienst; unabhaengig nachgesehen, nicht auf Zuruf geglaubt. | +| 2 Installation | — | DONE | Mit `SKIP_START`; die geschriebene Unit gelesen: `server` einmal, kein `--disable`, drei Flags. | +| 3 Start | — | DONE | 00:11:44, alle Container binnen ~70 s oben. | +| 4 Abnahme | — | DONE_WITH_CONCERNS | Sechs Kriterien erfuellt; ⚠️ ksm im CrashLoop und Alloys Tailer tot, beide von Hand nachgestartet. | +| 5 Nacharbeit | 9a3b1d1 | DONE | Sechs `rancher/*`-Entscheidungen entfernt; Herleitung gegen leere Antworten gehaertet, fuenfte Alarmregel. | ## Ladder @@ -37,6 +44,8 @@ related: | wie lange ein k3s-Neustart wirklich kostet, statt „einige Minuten" zu schaetzen | der Neustart vom 2026-08-01 steht in den Container-Startzeiten: 19:37:06 Dienst, 19:38:14 letzter Container | reused: die eigene Historie als Messung — ~70 s statt einer Vermutung, und kein Pod-Objekt wurde neu erzeugt | | | was der Adresswechsel sonst anfasst, statt nur an die Kubeconfig zu denken | `servicelb` veroeffentlicht die Knoten-Adresse: der Traefik-Dienst UND jeder Ingress tragen heute 49.13.132.245 — ohne `--node-external-ip` stuende dort kuenftig 10.0.0.2 | built: die ExecStart-Zeile traegt jetzt drei Flags statt einem; der Fund kam aus dem Nachsehen, nicht aus dem Nachdenken | | | ob Alloy oder cert-manager an der Knoten-Adresse haengen | Alloy scrapt ausschliesslich `role = "pod"`, kein Kubelet, keine Knoten-Rolle; cert-manager loest HTTP01 ueber den oeffentlichen Namen | reused: die eigene Konfiguration als Pruefmassstab — zwei vermutete Risiken sind damit gegenstandslos, statt sie vorsorglich zu behandeln | | +| warum die Zielmenge nach dem Sprung auf 12 stand, statt es fuer einen Uebergang zu halten | die Cluster-Abfrage war ERFOLGREICH und LEER — ksm und Alloy waren beim Neustart ausgefallen; der leere Erfolg erneuerte den Zeitstempel und keine der drei Regeln schlug an | built: leerer Erfolg gilt als Ausfall, Ausnahme verliert die Ziele nicht mehr, fuenfte Regel auf den Einbruch der Gesamtmenge | 9a3b1d1 | +| ob Alloys „will retry" tatsaechlich retried | nein — zwoelf Minuten ohne eine einzige Cluster-Logzeile, waehrend der Betriebs-Host weiterlieferte und alles lebendig aussah | reused: Loki als Messpunkt statt des Protokolltextes; ein Bauteil, das sein Scheitern als „retry" meldet, ist von einem gesunden nicht zu unterscheiden | | | ob die Unit ueberhaupt das tut, was sie sagt | NEIN: `server` steht zweimal in ExecStart, alles danach wird als Positionsargument gelesen. `k3s.io/node-args` fuehrt die Flags, `k3s.io/internal-ip` zeigt die oeffentliche Adresse, `traefik.yaml` ist ausgerollt | built: nichts — aber der Fund bestimmt das ganze Vorhaben: das Installationsskript schreibt die Unit neu, und dann werden drei seit vier Monaten stille Flags scharf | | ## Notes @@ -54,3 +63,16 @@ eine gar nicht erst gestellte Frage. **Kein Issue dahinter** — sorb hat den Posten aus einer Liste gewaehlt. Ob er einen bekommt, entscheidet sorb; ohne Zustimmung wird keiner angelegt. + +⚠️ **Der Sprung selbst war unspektakulaer; teuer war, was ein Neustart in den +ANDEREN Bauteilen ausloest.** kube-state-metrics blieb im CrashLoop haengen, +Alloys Log-Tailer starben und meldeten das als „will retry", und die +Scan-Zielmenge brach ein, weil eine leere Antwort als Erfolg zaehlte. Keines +dieser drei Dinge stand in der Risikoliste von Gate 1 oder Gate 2 — dort stand +der Traefik-Chart-Major, und der war ein Nicht-Ereignis. + +**Die Lehre ist nicht „mehr Risiken auflisten".** Sie ist: Ein Neustart der +Steuerebene prueft alles, was sich auf sie stuetzt — und was dabei nicht von +selbst zurueckkommt, meldet sich in aller Regel nicht. + +Eigener AAR zum Vorfall: `docs/aar/2026-08-23-zielmenge-eingebrochen.md`. diff --git a/docs/wiki/stolpersteine/meldet-erfolg-ist-aber-blind.md b/docs/wiki/stolpersteine/meldet-erfolg-ist-aber-blind.md index 2b053ca..c30f353 100644 --- a/docs/wiki/stolpersteine/meldet-erfolg-ist-aber-blind.md +++ b/docs/wiki/stolpersteine/meldet-erfolg-ist-aber-blind.md @@ -28,6 +28,33 @@ verschiedenen Werkzeugen. Deshalb steht sie hier und nicht in einzelnen Issues. ## Die belegten Vorkommen +### Nachtrag 2026-08-23 — zwei neue Vorkommen an einem Abend + +⚠️ **Diese Seite ist als „geerntet" markiert. Sie ist es nicht.** Die Regel, die +das Rahmenwerk daraus gemacht hat („eine Prüfung schuldet den Beweis, dass sie +rot werden kann"), deckt die beiden folgenden Fälle **nicht** ab — beide +Prüfungen *konnten* rot werden und waren es nachweislich schon. Sie schwiegen +trotzdem. + +**1. Der leere Erfolg.** Eine PromQL-Abfrage gegen eine Datenbank ohne Daten +liefert HTTP 200 und null Zeilen. Die Herleitung der Scan-Ziele kannte nur +„Erfolg" und „Ausnahme" — der dritte Ausgang fehlte. Ergebnis: Zielmenge 54 → 12, +**42 gelöschte Berichte**, Dashboard meldet Deckung 1,0. +Siehe `docs/aar/2026-08-23-zielmenge-eingebrochen.md`. + +**2. „will retry" ohne retry.** Alloys Log-Tailer verloren beim k3s-Neustart die +Verbindung zur API, protokollierten `"tailer stopped; will retry"` — und +lieferten danach nichts mehr. Zwölf Minuten ohne Cluster-Logs, ohne dass etwas +gemeldet hätte. Ein Bauteil, das sein eigenes Scheitern als Wiederholungsversuch +beschreibt, ist von einem gesunden **am Protokoll nicht zu unterscheiden**. + +**Was beide Fälle gemeinsam haben und die geerntete Regel nicht trifft:** Nicht +die Prüfung war blind, sondern **ihre Eingangsdaten waren leer und das galt als +gültig**. Die nächste Iteration braucht dafür eine eigene Formulierung — etwa: +*Wer aus einer Menge ableitet, behandelt die leere Menge ausdrücklich; „nichts +gefunden" und „nicht nachgesehen" sind verschiedene Ergebnisse.* + + | Wo | Was meldete Erfolg | Was tatsächlich geschah | |---|---|---| | LiveKit `setProcessor` | Prozessor geladen, 23 MB Modell aktiv | `sender?.replaceTrack` übersprang den Tausch stumm — das rohe Mikrofon blieb auf der Leitung |