Enterprise-Backup-, Recovery-, Verification-, Security- und Monitoring-Plattform fuer Proxmox VE, Windows, Linux und Dateisysteme. Der Leitsatz, der fast jede Entscheidung erklaert: Ein Backup gilt erst als vertrauenswuerdig, wenn Integritaet geprueft und Wiederherstellbarkeit nachgewiesen wurde. Deshalb steigt ein Wiederherstellungspunkt erst nach einem tatsaechlich durchgefuehrten Restore-Test auf "recoverable", und Unbekanntes geht in keine Bewertung als "gut" ein. Umfang (Phasen 0-23): - Repository Engine: inhaltsadressierte Bloecke, atomares Commit-Protokoll, Katalogaufbau allein aus den Manifesten — ohne Datenbank - Backup Engine: inhaltsabhaengiges Chunking, Deduplizierung trotz Verschluesselung, zstd, AES-256-GCM, Streaming mit Gegendruck - Agenten fuer Windows und Linux mit Auftragsabholung (Pull-Modell) - Proxmox-Provider mit beiden Zugriffswegen auf die Sicherungsarchive - Scheduler, Recovery Engine mit Pruefpunkt, Verification, Unveraenderlichkeit - Weboberflaeche, Kennzahlen, Meldungen, Berichte, Security Center, Ransomware-Heuristik (meldet, handelt nie) - Disaster Recovery, Haertung, Leistungsmessung, Chaos Testing - Eingefrorene Vertraege fuer API, Migrationen, Backup-Format und Repository - Auslieferungspaket fuer linux/amd64, linux/arm64 und windows/amd64 Nicht enthalten und als solches gekennzeichnet: Kapazitaetsprognose, Backup Copy, Changed Block Tracking bei Proxmox, erweiterte Attribute und ACLs. Gebaut, aber nie auf echter Hardware gefahren: der Windows-Dienst, die systemd-Einheit und der verpflichtende Proxmox-Meilenstein — ob eine wiederhergestellte VM startet, ist ungeprueft. Einzelheiten in CHANGELOG.md und docs/release-candidate.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
211 lines
10 KiB
Markdown
211 lines
10 KiB
Markdown
# Berichte (Phase 17)
|
|
|
|
Neun Berichte, drei Formate, kein gespeicherter Bericht.
|
|
|
|
Ein Bericht ist das Dokument, das die Anlage **verlässt**. Er landet in einer
|
|
Tabellenkalkulation, in einer Präsentation und in einem Prüfordner. Was darin
|
|
steht, wird Monate später gelesen, ohne dass jemand nachfragen kann — und eine
|
|
erfundene Zahl überlebt dort jede mündliche Erläuterung, mit der man sie hätte
|
|
einordnen können. Das ist der Grund für die beiden Entscheidungen, die dieses
|
|
Paket tragen.
|
|
|
|
## Ein Modell, drei Sichten
|
|
|
|
Ein Bericht ist eine Sammlung aus Kennzahlen und Tabellen. CSV, JSON und PDF
|
|
sind drei Sichten auf dieselbe Struktur; kein Bericht weiß, in welchem Format er
|
|
ausgegeben wird.
|
|
|
|
Wären die Formate in die Berichte eingebaut, müsste jeder der neun dreimal
|
|
geschrieben werden — und beim zehnten vergisst jemand eines davon. Der praktische
|
|
Beleg steht in `report.go`: Die Zellen einer Tabelle sind bereits als **Text**
|
|
aufbereitet. Die Formatierung einer Datenmenge gehört zum Bericht, nicht zum
|
|
Ausgabeformat, sonst zeigten CSV und PDF dieselbe Zahl verschieden.
|
|
|
|
Ausnahme mit Absicht: Die **Kennzahlen** gehen als Rohwert ins CSV. Eine
|
|
Tabellenkalkulation soll rechnen können, und „1,4 GiB" ist Text.
|
|
|
|
## Eine ungemessene Zahl ist keine Null
|
|
|
|
Jede Kennzahl trägt `is_known`. Ist sie nicht gesetzt, gibt es keinen Wert —
|
|
sondern eine Begründung.
|
|
|
|
| Fall | Falsch | Richtig |
|
|
| --- | --- | --- |
|
|
| Zeitraum ohne Lauf | Erfolgsquote 100 % | nicht bestimmbar, „ohne Lauf gibt es keine Quote" |
|
|
| Repository ohne hinterlegte Kapazität | Auslastung 100 % | nicht bestimmbar |
|
|
| Kein Wiederherstellungspunkt | 0 % verschlüsselt | nicht bestimmbar, „es gibt keinen" |
|
|
| RTO ohne Wiederherstellung | geschätzt aus Datenmenge ÷ Durchsatz | nicht gemessen |
|
|
|
|
Im CSV bleibt die Wertspalte **leer** und die Anmerkung trägt den Grund. Eine
|
|
leere Zelle lässt sich nicht versehentlich summieren; eine Null wird summiert,
|
|
gemittelt und in ein Diagramm gezeichnet.
|
|
|
|
Umgekehrt gilt dasselbe: Eine **gemessene** Null bleibt sichtbar. „Null Läufe"
|
|
ist eine Aussage und darf nicht mit „nicht gemessen" verwechselt werden.
|
|
|
|
## Die neun Berichte
|
|
|
|
| Bericht | Zeitbezug | Besonderheit |
|
|
| --- | --- | --- |
|
|
| Tagesbericht | 24 h | Beantwortet die Frage, die morgens zuerst gestellt wird |
|
|
| Wochenbericht | 7 Tage | Zusätzlich nach Tagen aufgeschlüsselt — zeigt den Auftrag, der immer freitags scheitert |
|
|
| Monatsbericht | 30 Tage | Zusätzlich nach Aufträgen aufgeschlüsselt |
|
|
| Gescheiterte Sicherungen | 7 Tage | Teilfehler stehen ausdrücklich mit darin |
|
|
| Repository-Kapazität | Zustand | Löschschutz gemessen, nicht behauptet |
|
|
| Wiederherstellungen | 30 Tage | Die einzige Quelle gemessener Wiederherstellungszeiten |
|
|
| Sicherheit | Zustand | Nutzt das Security Center, rechnet nicht selbst |
|
|
| Für Prüfungen | Zustand | Messwerte, keine Urteile |
|
|
| RPO und RTO | Zustand | Der ehrliche Härtefall, siehe unten |
|
|
|
|
Die drei Sicherungsberichte teilen sich eine Implementierung. Sie unterscheiden
|
|
sich nur in der Aufschlüsselung — sie getrennt zu schreiben hieße, dieselbe
|
|
Erfolgsquote dreimal zu berechnen und beim nächsten Fund an zwei Stellen zu
|
|
vergessen.
|
|
|
|
**Ein Zustandsbericht bekommt keinen Zeitraum.** Die Belegung der Repositories
|
|
wird nicht historisiert; einen Bericht „vom letzten Dienstag" kann es nicht
|
|
geben. Wer trotzdem einen Zeitraum angibt, bekommt ihn ignoriert — ihn
|
|
anzunehmen und nicht auszuwerten wäre die freundlichste Art zu lügen.
|
|
|
|
### RPO lässt sich messen, RTO nicht
|
|
|
|
Der Abstand zur letzten erfolgreichen Sicherung steht in der Datenbank. Die
|
|
Zeit, die eine Wiederherstellung *bräuchte*, kennt niemand, bevor sie
|
|
stattgefunden hat.
|
|
|
|
In der RTO-Spalte steht deshalb entweder eine **Messung aus einer tatsächlich
|
|
durchgeführten Wiederherstellung** oder ein ausdrückliches „nicht gemessen" —
|
|
nie eine Hochrechnung aus Datenmenge und Durchsatz. Eine solche Schätzung wäre
|
|
die bequemste Zahl des ganzen Berichts und die einzige, auf die sich im Ernstfall
|
|
niemand verlassen könnte.
|
|
|
|
Der Bericht sagt das auch: Für einen Auftrag mit RTO-Vorgabe ohne Messung ist die
|
|
Einhaltung **unbekannt** — nicht erfüllt und nicht verletzt.
|
|
|
|
### Der Bericht für Prüfungen täuscht nichts vor
|
|
|
|
`PROMPT.md` §73 ist an dieser Stelle ausdrücklich: „Syncova soll keine
|
|
Compliance-Zertifizierung vortäuschen." Der Bericht liefert deshalb Messwerte
|
|
und keine Urteile — kein „erfüllt", kein Haken, keine Norm. Der erste Hinweis
|
|
unter dem Bericht sagt es wörtlich: *Dieser Bericht ist keine Zertifizierung und
|
|
ersetzt keine.*
|
|
|
|
„Kopie an einem zweiten Ort" erscheint als nicht messbar, weil Backup Copy nicht
|
|
umgesetzt ist. Weder null noch hundert Prozent wären wahr.
|
|
|
|
## PDF ist selbst geschrieben
|
|
|
|
Der Plan sagt „PDF where practical". Die bequeme Auslegung wäre, es für nicht
|
|
praktikabel zu erklären — aber ein Bericht für eine Prüfung wird als PDF
|
|
verlangt, nicht als CSV.
|
|
|
|
Gebraucht wird nur der einfachste Teil des Formats: Text in einer der vierzehn
|
|
Standardschriften, die jeder Betrachter mitbringt. Keine Einbettung, keine
|
|
Bilder, keine Transparenz.
|
|
|
|
Drei Dinge kosteten trotzdem Arbeit:
|
|
|
|
- **Die Zeichenbreiten von Helvetica** liegen als Tabelle im Code. Ohne sie ließe
|
|
sich weder umbrechen noch eine Spalte bemessen; mit geschätzten Breiten
|
|
überlappen Tabellenspalten, sobald ein Wert länger wird als erwartet.
|
|
- **Die Kodierung.** Die Standardschriften werden mit `/WinAnsiEncoding`
|
|
eingebunden, jedes Zeichen ist ein Byte. Ohne Umwandlung zeigt der Betrachter
|
|
„Sicherungslÿufe" — und zwar erst beim Empfänger, nicht beim Erzeuger.
|
|
- **Die Querverweistabelle.** Sie ist der einzige Teil eines PDF, bei dem ein
|
|
Fehler nicht auffällt, solange man die Datei nur ansieht: Ein falscher Offset
|
|
bricht das Dokument erst beim Empfänger, und dann heißt es, der Bericht sei
|
|
beschädigt angekommen. `TestPDFCrossReferenceOffsetsArePrecise` prüft jeden
|
|
Verweis auf einen tatsächlichen Objektbeginn.
|
|
|
|
**Fund bei der Sichtprüfung:** Ein gleichmäßiger Stauchfaktor für zu breite
|
|
Tabellen kürzte „TEILWEISE FEHLGESCHLAGEN" zu „TEILWEISE FEHL…", weil daneben
|
|
ein langer Pfad stand — ausgerechnet der Wert, wegen dessen man den Bericht
|
|
liest. Jetzt wird eine gemeinsame Obergrenze gesucht: Spalten darunter bleiben
|
|
unangetastet, nur die breitesten geben ab.
|
|
|
|
**Fund bei derselben Prüfung:** `**keine Zertifizierung**` stand mit Sternchen
|
|
im PDF. Das Modell ist formatunabhängig, sein Text darf deshalb keine
|
|
Auszeichnung tragen. Ein Test hält das fest.
|
|
|
|
## API
|
|
|
|
```bash
|
|
GET /api/v1/reports # Katalog der neun Berichte (reports.read)
|
|
POST /api/v1/reports/generate # erzeugt und liefert aus (reports.read)
|
|
```
|
|
|
|
```json
|
|
{ "type": "daily_backup", "from": "…", "to": "…", "format": "pdf" }
|
|
```
|
|
|
|
JSON kommt in der üblichen Antworthülle, CSV und PDF als Datei mit
|
|
`Content-Disposition`. Der Dateiname wird bereinigt, bevor er in den Kopf geht —
|
|
ein Zeilenumbruch darin ließe sich zum Einschleusen weiterer Kopffelder nutzen.
|
|
|
|
**Berichte werden nicht gespeichert.** Ein abgelegter Bericht veraltet mit jedem
|
|
Tag, ohne dass sich an ihm etwas ändert — dieselbe Überlegung wie bei der
|
|
Recovery Assurance (Phase 10) und der Sicherheitsbewertung (Phase 15). Wer einen
|
|
Bericht aufbewahren will, lädt ihn herunter; die Datei trägt ihren
|
|
Erzeugungszeitpunkt bei sich.
|
|
|
|
**Jeder Abruf wird auditiert** (`REPORT_GENERATED`). Ein Bericht liest nur und
|
|
verändert nichts — protokolliert wird er trotzdem, weil er ein *Datenexport*
|
|
ist: Der Bericht für Prüfungen und der Sicherheitsbericht nennen die
|
|
Schwachstellen der Anlage in geordneter Form, und wer eine solche Datei aus dem
|
|
System trägt, gehört zu den Fragen, die ein Prüfer als erstes stellt.
|
|
|
|
Scheitert das Protokollieren, wird der Bericht trotzdem ausgeliefert — anders als
|
|
bei einer destruktiven Handlung wäre es die falsche Abwägung, ein Leserecht
|
|
wegen eines Protokollfehlers zu verweigern.
|
|
|
|
## Oberfläche
|
|
|
|
Die Berichtsseite stand seit Phase 12 als benannte Lücke im Menü. Sie zeigt den
|
|
Katalog, eine Vorschau im selben Modell wie die Datei und zwei Schaltflächen für
|
|
CSV und PDF.
|
|
|
|
Der Download geht über `downloadApiFile` neben `requestApi`: Eine Datei trägt
|
|
keine Antworthülle. Durch `requestApi` geschickt, versuchte dieser ein PDF als
|
|
JSON zu lesen und meldete eine unverständliche Antwort — obwohl alles in Ordnung
|
|
ist. Der **Fehlerfall** geht dagegen sehr wohl durch die Hülle, deshalb wird der
|
|
Inhaltstyp geprüft: Sonst landete eine Fehlermeldung als „bericht.pdf" im
|
|
Download-Ordner, und der Anwender sähe statt einer Meldung eine kaputte Datei.
|
|
|
|
## Nachweis
|
|
|
|
Gegen die laufende Anlage geführt:
|
|
|
|
- **27 von 27** Kombinationen aus neun Berichten und drei Formaten erzeugt.
|
|
- Das PDF von CoreGraphics gerendert (macOS Quick Look nutzt dieselbe Engine wie
|
|
Vorschau) und **angesehen** — Umlaute, Tabellen, Seitenumbruch, Hinweise.
|
|
- Eine **echte Wiederherstellung** über die API ausgeführt, damit der RTO-Teil
|
|
nicht nur Code ist: Vorher „nicht gemessen, 0 Messungen", danach „RTO-Vorgabe
|
|
1 h 0 min, gemessene Dauer 36 ms, 1 Messung".
|
|
- Ein Zeitraum ohne jeden Lauf (2024) erzeugte **keine** 100-Prozent-Quote,
|
|
sondern drei ausdrücklich unbestimmbare Kennzahlen mit Begründung.
|
|
- Der Auditeintrag `REPORT_GENERATED` steht mit Art, Format und Zeitraum in der
|
|
Datenbank.
|
|
|
|
**Fund im Nachweis:** „Längste Laufzeit: 0" stand als Messung da, während
|
|
„Mittlere Laufzeit" korrekt als unbestimmbar galt. Die Datenbank liefert dank
|
|
`COALESCE` eine Null, und im Bericht sah sie aus wie ein Lauf, der in null
|
|
Sekunden durchlief. `TestEmptyPeriodProducesNoFabricatedNumbers` hält jetzt alle
|
|
drei Kennzahlen fest.
|
|
|
|
**Fund vor dem Nachweis:** Die Abfrage des Berichts für Prüfungen nutzte
|
|
`users.is_active` — eine Spalte, die es nie gab (das Schema führt `status`). Der
|
|
Bericht wäre bei jedem Abruf gescheitert.
|
|
|
|
## Bekannte Grenzen
|
|
|
|
- **Die Liste einzelner Läufe ist auf 500 Einträge begrenzt.** Die Begrenzung
|
|
wird im Bericht ausgesprochen; die Kennzahlen im Überblick zählen alle Läufe.
|
|
Eine stillschweigend gekürzte Liste liest sich wie eine vollständige.
|
|
- **Kein Zeitplan, keine Zustellung.** Berichte werden abgerufen, nicht
|
|
zugestellt. Der Plan verlangt das für diese Phase nicht; die Zustellwege aus
|
|
Phase 14 (E-Mail, Webhook) sind vorhanden und ließen sich anbinden.
|
|
- **Die Vorschau zeigt 25 Zeilen je Tabelle.** Die heruntergeladene Datei enthält
|
|
alle; die Vorschau sagt, wie viele sie zeigt.
|
|
- **PDF kennt keine Textauszeichnung.** Fett gesetzt sind nur Überschriften,
|
|
Spaltenköpfe und Kennzahlenwerte — der Fließtext ist einheitlich.
|