Beglaubigte Alt-Luecken: Dauer-Alarm im Gegenbuch beendet
Das Gegenbuch auf Prod meldete stuendlich exit=2, weil die CRM-Pruefung
wegen 6 struktureller Luecken valid:false lieferte (IDs 33, 44, 45, 922,
1434, 2583).
Diagnose: harmlos. Jede Luecke liegt innerhalb eines Schwungs von
Eintraegen mit identischer Sekunde, betrifft nur /login und /refresh,
kein Eintrag fehlt, tamperedEntries ist leer. Das ist die Signatur der
Race-Condition, die am 19.08. mit AuditChainLock geschlossen wurde
(R166-01). Die Zeilen datieren ihren eigenen Code: Eintrag 2583 stammt
vom 21.08., ist aber noch hashVersion=1.
Das eigentliche Problem war nicht die Luecke, sondern der Dauer-Alarm.
Diese Luecken sind nicht heilbar - die Verkettung ist gebrochen, die
Inhalte sind unversehrt. Ohne Aenderung haette das Gegenbuch fuer immer
Alarm gemeldet, und ein Signal, das immer schreit, warnt nicht mehr.
Dieselbe Klasse wie R162, R174, R179, R182, R183-02.
Loesung: Beglaubigung statt Unterdrueckung. Eine Luecke zaehlt nicht mehr
als offener Befund, wenn sie im versiegelten Bereich liegt UND im
Vorbefund des Siegel-Markers steht - also im Zustand, den der Betreiber
beim Siegeln ausdruecklich festgeschrieben hat. Der Vorbefund liegt in
changesBefore und ist ab Version 3 mitgehasht; ohne AUDIT_HMAC_KEY laesst
sich die Liste nicht nachtraeglich erweitern (gleiche Absicherung wie
beim Loeschungs-Manifest, R171-01). Beglaubigt heisst nicht verschwunden:
die Luecken bleiben in chainGaps, stehen zusaetzlich in attestedGaps und
werden im Bericht ausdruecklich benannt.
Nebenbefund derselben Klasse mitbehoben: backlogSealStatus meldete
"nicht_noetig" ("Es gibt keine unsignierten Alteintraege"), wenn
v3FromId === null - das bedeutet aber das Gegenteil, naemlich dass
ueberhaupt nichts signiert ist, etwa weil AUDIT_HMAC_KEY fehlt. Ein
vollstaendig unsigniertes Log bekam damit Entwarnung fuer genau den
Zustand mit der geringsten Beweiskraft. Die Bedingung haengt jetzt an der
Zahl der unsignierten Zeilen; R183-03 bleibt behoben (Regressionstest).
Getestet ueber HTTP gegen eine eigene Wegwerf-Datenbank, nicht am Service
vorbei: Prod-Zustand nachgebaut (10 v1-Zeilen, Bruch bei id 5) ->
valid:false; nach seal-backlog -> valid:true, attestedGaps:[5]. Drei
Gegenproben: neue Luecke nach dem Siegeln -> valid:false; gesiegelte
Altzeile veraendert -> Siegel gebrochen, nichts mehr beglaubigt;
Beglaubigungsliste im Marker gefaelscht (DB-Schreibrecht, kein
Schluessel) -> Marker ungueltig, Status entfernt, valid:false.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -97,6 +97,54 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
||||
|
||||
## ✅ Erledigt
|
||||
|
||||
- [x] **🧾 Beglaubigte Alt-Lücken: Dauer-Alarm im Gegenbuch beendet** (2026-08-26)
|
||||
- **Ausgangslage.** Das Gegenbuch auf Prod meldete stündlich `exit=2`. Die
|
||||
CRM-Prüfung lieferte `valid: false` wegen **6 struktureller Lücken**
|
||||
(IDs 33, 44, 45, 922, 1434, 2583).
|
||||
- **Diagnose: harmlos.** Jede Lücke liegt innerhalb eines Schwungs von
|
||||
Einträgen mit **identischer Sekunde**, betrifft nur `/login` und
|
||||
`/refresh`, kein Eintrag fehlt (kein 404), `tamperedEntries` leer. Das ist
|
||||
die Signatur der Race-Condition, die am 19.08. mit `AuditChainLock`
|
||||
geschlossen wurde (R166-01). Bestätigt durch die Zeilen selbst: Eintrag
|
||||
2583 stammt vom 21.08., ist aber noch `hashVersion=1` – auf Prod lief zu
|
||||
dem Zeitpunkt also der alte Stand.
|
||||
- **Das eigentliche Problem war nicht die Lücke, sondern der Dauer-Alarm.**
|
||||
Diese Lücken sind nicht heilbar: die Verkettung ist gebrochen, die Inhalte
|
||||
sind unversehrt. Ohne Änderung hätte das Gegenbuch für immer Alarm gemeldet
|
||||
– und ein Signal, das immer schreit, warnt nicht mehr. Dieselbe Klasse wie
|
||||
R162, R174, R179, R182, R183-02.
|
||||
- **Lösung: Beglaubigung statt Unterdrückung.** Eine Lücke zählt nicht mehr
|
||||
als offener Befund, wenn beides gilt: sie liegt im **versiegelten Bereich**
|
||||
UND steht im **Vorbefund des Siegel-Markers**, also im Zustand, den der
|
||||
Betreiber beim Siegeln ausdrücklich festgeschrieben hat. Der Vorbefund
|
||||
liegt in `changesBefore` und ist ab Version 3 mitgehasht – die Liste lässt
|
||||
sich ohne `AUDIT_HMAC_KEY` nicht nachträglich erweitern (gleiche
|
||||
Absicherung wie beim Löschungs-Manifest, R171-01).
|
||||
- Beglaubigt heißt **nicht verschwunden**: die Lücken bleiben in `chainGaps`,
|
||||
stehen zusätzlich in neuem Feld `attestedGaps` und werden im Bericht
|
||||
ausdrücklich benannt.
|
||||
- **Nebenbefund derselben Klasse mitbehoben:** `backlogSealStatus` meldete
|
||||
`nicht_noetig` ("Es gibt keine unsignierten Alteinträge"), wenn
|
||||
`v3FromId === null` – das bedeutet aber das **Gegenteil**: dass überhaupt
|
||||
nichts signiert ist, etwa weil `AUDIT_HMAC_KEY` fehlt. Ein vollständig
|
||||
unsigniertes Log bekam damit Entwarnung für genau den Zustand mit der
|
||||
geringsten Beweiskraft. Die Bedingung hängt jetzt an der Zahl der
|
||||
unsignierten Zeilen. R183-03 (unauflösbare Warnung bei frisch signiertem
|
||||
Log) bleibt behoben – per Regressionstest geprüft.
|
||||
- **Getestet über HTTP gegen eine eigene Wegwerf-Datenbank**, nicht am
|
||||
Service vorbei: Prod-Zustand nachgebaut (10 v1-Zeilen, Bruch bei id 5) →
|
||||
`valid:false`; nach `seal-backlog` → `valid:true`, `attestedGaps:[5]`.
|
||||
Drei Gegenproben: **neue Lücke** nach dem Siegeln → `valid:false`;
|
||||
**gesiegelte Altzeile verändert** → Siegel `gebrochen`, nichts mehr
|
||||
beglaubigt; **Beglaubigungsliste im Marker gefälscht** (DB-Schreibrecht,
|
||||
kein Schlüssel) → Marker ungültig, Status `entfernt`, `valid:false`.
|
||||
- Doku: Abschnitt „Wenn der erste Lauf `exit=2` meldet" in
|
||||
`tools/audit-notary/README.md` – inklusive der Warnung, **vor** dem
|
||||
Siegeln zu prüfen, was man da festschreibt.
|
||||
- Dateien: `backend/src/services/audit.service.ts`,
|
||||
`backend/src/controllers/auditLog.controller.ts`,
|
||||
`frontend/src/services/api.ts`, `tools/audit-notary/README.md`
|
||||
|
||||
- [x] **🔓 Dienstkonto-Flag: Gate in beide Richtungen, richtige Rechte-Domaene (Pentest R184-01/-02)** (2026-08-24)
|
||||
- **R184-01** – Setzen war gegatet, **Entfernen nicht**. Und das Entfernen ist
|
||||
der gefaehrlichere Weg: Der Heartbeat-Wachhund fragt `isServiceAccount:
|
||||
|
||||
Reference in New Issue
Block a user