syncova-backup/docs/backup-format.md
Jerrit Fritzsche 610719c316
Some checks failed
CI / Backend (Go) (push) Failing after 3m7s
CI / Frontend (React/TypeScript) (push) Successful in 37s
CI / Sicherheitsprüfungen (push) Successful in 44s
Syncova Backups V1
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>
2026-08-17 09:10:54 +02:00

6.7 KiB

Backup-Format

Dieses Dokument beschreibt den aktuell implementierten Stand nach Phase 3.

Zweck

Der Syncova Backup Container ist die portable Form eines Backups: eine einzelne, in sich geschlossene Datei mit allem, was zur Wiederherstellung nötig ist. Er dient der Übertragung an ein zweites Repository (PROMPT.md §17), der Archivierung und dem Austausch zwischen Installationen.

Das Repository (Phase 2) legt ein Backup verteilt ab — Chunks und Manifest getrennt. Der Container fasst dasselbe Backup in eine Datei. Beide Formen sind selbstprüfend und brauchen keine Datenbank.

Aufbau

+--------------------------------------------------+
| Magic "SYNCOVA1"           8 Byte                |
| Formatversion              2 Byte (Big Endian)   |
| Headerlänge                4 Byte                |
| Header                     JSON                  |
+--------------------------------------------------+
| Abschnitt 1: Typ 1 | Flags 1 | Länge 8 | SHA 32  |
|              Inhalt                              |
| Abschnitt 2 ...                                  |
+--------------------------------------------------+
| Footer-Magic "SYNFOOT1"    8 Byte                |
| Footerlänge                4 Byte                |
| Footer                     JSON                  |
+--------------------------------------------------+

Alle Mehrbyte-Zahlen sind Big Endian. Die Byte-Reihenfolge ist Teil des Formats und darf nicht von der Rechnerarchitektur abhängen.

Abschnittstypen: Manifest (1), Chunk-Verzeichnis (2), Blockzuordnung (3), Datenblöcke (4), Quellenangaben (5), Integritätsangaben (6). Die Zahlenwerte sind Teil des Vertrags und dürfen niemals neu belegt werden — ein bestehender Container würde sonst falsch gedeutet.

Das ist die tragende Entscheidung des Entwurfs. Erst am Ende stehen alle Prüfsummen fest — und genau daraus folgt die Aussagekraft:

Ein abgebrochener Schreib- oder Übertragungsvorgang hinterlässt einen Container ohne Footer. Er wird dadurch zuverlässig als unvollständig erkannt.

Erst Close() macht einen Container gültig. Wer den Vorgang vorher abbricht, hinterlässt Bruchstücke — aber nie ein Gebilde, das sich als vollständiges Backup ausgibt.

Versionsverhandlung

Der Leser kennt MinimumReadableVersion und MaximumReadableVersion. Ein Container außerhalb dieser Spanne wird nicht angetastet, und die Meldung unterscheidet die Richtung:

  • zu neu → „Bitte Syncova aktualisieren" (ein Update hilft)
  • zu alt → Hinweis auf die Mindestversion (ein Update hilft nicht)

Ein falsch interpretiertes Backup ist schlimmer als ein nicht gelesenes.

Erweiterbarkeit

Jeder Abschnitt trägt seine Länge. Eine spätere Programmversion darf deshalb neue Abschnitte ergänzen — eine ältere überspringt sie, ohne sie zu deuten.

Die Grenze zieht FlagRequired:

Abschnitt Verhalten einer älteren Version
unbekannt, optional wird übersprungen, Container bleibt gültig
unbekannt, erforderlich Verarbeitung wird verweigert

Ohne diese Unterscheidung würde eine alte Version einen Container lesen, dem wesentliche Teile fehlen, und Vollständigkeit vortäuschen (PROMPT.md §140).

Streaming und aufgeschobene Prüfsumme

Der Datenbereich kann beliebig groß werden und darf nie vollständig in den Arbeitsspeicher (PROMPT.md §80). Er wird deshalb als Datenstrom geschrieben — was einen Konflikt erzeugt:

Die Prüfsumme eines Abschnitts steht erst fest, wenn er vollständig geschrieben ist. Sein Kopf ist zu diesem Zeitpunkt längst in der Ausgabe.

Der naheliegende Ausweg — den Kopf nachträglich überschreiben — verlangt eine rückspulbare Senke und schlösse Pipes und Netzwerkziele aus. Stattdessen trägt ein solcher Abschnitt FlagDeferredDigest: sein Kopf-Digest bleibt leer und wird beim Lesen nicht herangezogen.

Es entsteht dadurch keine Prüflücke. Die Unversehrtheit ist doppelt gesichert:

  1. Jeder einzelne Chunk trägt seine Prüfsumme im Chunk-Verzeichnis; der Import prüft jeden Block gegen seine Kennung.
  2. Die Gesamtprüfsumme im Footer deckt Header und alle Abschnittsinhalte ab.

Was die Integritätsprüfung abdeckt

Angriff / Fehler Erkannt durch
Einzelnes Bit verfälscht Abschnitts-Prüfsumme, sonst Gesamtprüfsumme
Container abgeschnitten fehlender Footer
Abschnitt entfernt Abschnittszahl im Footer
Abschnitt samt passender Prüfsumme ausgetauscht Gesamtprüfsumme im Footer
Manifest ausgetauscht Manifest-Hash im Footer
Abschlussvermerk auf false gesetzt ausdrückliche Prüfung
Fremde Datei Magic Bytes

Prüfsummenvergleiche laufen in konstanter Zeit — eine Prüfsumme ist ein Sicherheitsmerkmal, kein bloßer Vergleichswert.

Export und Import

syncova-repo export --path <repo> --backup <id> --out backup.syncova
syncova-repo inspect --in backup.syncova          # prüfen ohne einzulesen
syncova-repo import --path <ziel-repo> --in backup.syncova

Export liest jeden Chunk über ReadChunk — die Integritätsprüfung greift also, bevor ein Block in den Container gelangt. Fehlt ein Chunk oder ist er beschädigt, bricht der Export ab und das Kommando löscht die angefangene Zieldatei. Ein halber Container wäre eine Falle: er sähe aus wie ein Backup, wäre aber keines.

Import macht das Manifest erst sichtbar, nachdem alle Abschnitte, Prüfsummen und der Abschlussvermerk stimmen. Ein fehlgeschlagener Import hinterlässt allenfalls Chunks — nie ein scheinbar gültiges Backup. Bereits vorhandene Chunks werden dabei erkannt: dieselbe Deduplizierung wie beim Sichern.

Inspect liest den Container vollständig (und prüft damit alle Prüfsummen), ohne etwas zu schreiben. Der Exit-Status ist bei einem unbrauchbaren Container ungleich 0, damit ein Skript oder Monitoring daran anschlägt.

Grenzen des aktuellen Stands

  • Chunks sind unkomprimiert und unverschlüsselt. Die Felder encryption und compression sind bereits Teil des Header-Formats und überstehen die Rundreise — die Verarbeitung folgt in Phase 4. Eine spätere Ergänzung der Felder wäre ein Formatbruch, deshalb stehen sie jetzt schon dort.
  • Der Import lädt den Datenbereich vollständig in den Speicher. Für Container jenseits weniger Gigabyte ist das nicht tragbar; der Weg über ChunkIndexEntry.ContainerOffset ist vorbereitet, aber noch nicht als Datenstrom umgesetzt.
  • Die Blockzuordnung (SectionBlockMap) ist definiert, wird aber noch nicht geschrieben. Sie wird für Disk-Images gebraucht, bei denen logische Bereiche auf Chunks abgebildet werden müssen.
  • Kein Wiederaufsetzen einer abgebrochenen Übertragung. Ein unvollständiger Container muss vollständig neu erzeugt werden.