diff --git a/CHANGELOG.md b/CHANGELOG.md index eadec1f..cd4e6bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,59 @@ # Änderungen +## V1 — Release Candidate 8, 18. August 2026 + +Wiederherstellung von Dateien und Ordnern mit Auswahl statt Textfeld — und die +Erklärung, warum vorher gar keine Wiederherstellung funktionierte. + +### Warum keine Wiederherstellung ging + +Nicht die Rechte des Zielverzeichnisses, sondern die Härtung des Dienstes: Er +läuft mit `ProtectSystem=strict` und `ReadWritePaths` nur auf Repository und +Sicherungsordner. Jedes Ziel außerhalb endete mit `mkdir: permission denied` — +und zwar **nach** der Vorabprüfung, an der unangenehmsten Stelle. `/tmp` +scheiterte anders: Mit `PrivateTmp=yes` hat der Dienst ein eigenes `/tmp`, und +was dort landet, ist von außen unsichtbar. + +`setup.sh` legt jetzt `/srv/syncova-restore` an und trägt es ein; +`--wiederherstellungsziel` ergänzt weitere. Der Ort liegt unter `/srv`, weil +`/var/lib` auf der Sperrliste des Zielschutzes steht — beide Regeln zugleich zu +erfüllen lässt genau `/srv` übrig. + +### Auswahl statt Textfeld + +- **Ordnerbaum für das Ziel.** Er meldet je Verzeichnis, ob der Dienst dort + schreiben darf — **gemessen** durch eine Probedatei, nicht aus den Rechtebits + abgeleitet. Gesperrte Orte werden gezeigt, nicht versteckt: Sonst bliebe + offen, warum ein Pfad fehlt. +- **Browser für den Backup-Inhalt.** Ordner **und** einzelne Dateien lassen + sich zurückholen. Der Baum entsteht aus den Pfaden, nicht aus + Verzeichniseinträgen — ein Manifest kann eine Datei enthalten, deren + Elternordner nicht als eigener Eintrag vorliegt. + +Zwei neue Endpunkte, der eingefrorene Vertrag ist entsprechend erweitert: +`GET /filesystem/browse` und `GET /backups/{id}/contents`. + +### Behoben + +- **„can't access property toLocaleString, chunks_checked is undefined"** beim + Integritätslauf. Die Ergebnisse liegen unter `details`, und die Felder heißen + `missing_chunks`/`corrupted_chunks`. Betrifft alle vier Prüfendpunkte — sie + tragen dieselbe Hülle. Derselbe Fehler wie zuvor bei `/retention-policies`: + die Antwortform angenommen statt geprüft. Alle konsumierten Endpunkte sind + jetzt gegen den laufenden Dienst abgeglichen. + +### Geist Mono liegt im Paket + +Drei Schnitte, 128 KB, OFL-Lizenz dabei. Ausgeliefert vom eigenen Ursprung — +das verlangt die CSP, und ein Backup-Server, dessen Oberfläche von der +Erreichbarkeit eines CDN abhängt, wäre auch ohne CSP falsch. + +### Bekannte Grenze + +**Eine Auswahl je Lauf**, kein Mehrfachhaken. Eine Liste ausgewählter Pfade +kennt die API nicht; mehrere Läufe hintereinander ergäben mehrere Ausgänge, und +ein „teilweise fehlgeschlagen" ließe sich dann nicht mehr erklären. + ## V1 — Release Candidate 7, 18. August 2026 Behebt einen Absturz, macht die Sitzung brauchbar und stellt das Aussehen um. diff --git a/docs/installation.md b/docs/installation.md index d33a52d..d1fc3e5 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -187,12 +187,17 @@ ExecStart=/opt/syncova/bin/syncova-api Restart=on-failure RestartSec=5 -# Härtung: Der Dienst braucht Netz und sein Repository, sonst nichts. +# Härtung: Der Dienst braucht Netz, sein Repository und eine Fläche für +# Wiederherstellungen — sonst nichts. +# +# ReadWritePaths ist die Stelle, an der eine Wiederherstellung scheitert, wenn +# man sie vergisst: Mit ProtectSystem=strict ist alles andere für den Dienst +# schreibgeschützt, und die Rechte des Zielverzeichnisses helfen dann nicht. NoNewPrivileges=yes PrivateTmp=yes ProtectSystem=strict ProtectHome=yes -ReadWritePaths=/srv/syncova-repository +ReadWritePaths=/srv/syncova-repository /srv/syncova-restore ProtectKernelTunables=yes ProtectKernelModules=yes ProtectControlGroups=yes @@ -285,6 +290,25 @@ sudo firewall-cmd --permanent --add-service=https # firewalld sudo firewall-cmd --reload ``` +## 8b. Wohin Wiederherstellungen schreiben dürfen + +`setup.sh` legt `/srv/syncova-restore` an und trägt es in `ReadWritePaths` der +systemd-Einheit ein. Ohne diesen Eintrag scheitert **jede** Wiederherstellung: +Der Dienst läuft mit `ProtectSystem=strict`, und die Rechte des +Zielverzeichnisses helfen dann nicht. + +Weitere Ziele beim Einrichten nennen: + +```bash +sudo ./setup.sh --wiederherstellungsziel /srv/wiederherstellung \ + --wiederherstellungsziel /mnt/nas/restore +``` + +Nicht möglich sind `/tmp` (privater Namensraum des Dienstes) und die +Systemverzeichnisse `/etc`, `/usr`, `/var/lib`, `/root` — Letztere sperrt der +Zielschutz, weil eine Wiederherstellung dorthin das System überschriebe, auf dem +die Anlage läuft. + ## 9. Erstes Repository Ein Repository entsteht **auf einem Datenträger**, nicht in einer diff --git a/docs/recovery-runbook.md b/docs/recovery-runbook.md index 8f7b044..a6a553f 100644 --- a/docs/recovery-runbook.md +++ b/docs/recovery-runbook.md @@ -51,9 +51,44 @@ Original nicht mehr. ## 1. Dateien und Ordner +### Wohin darf zurückgeschrieben werden? + +**Die wichtigste Frage, und sie ist nicht offensichtlich.** Der Dienst läuft mit +`ProtectSystem=strict`: Außerhalb weniger Pfade ist das Dateisystem für ihn +schreibgeschützt, unabhängig von den Rechten des Verzeichnisses. Ein Ziel +außerhalb endet mit `mkdir: permission denied` — und zwar erst **nach** der +Vorabprüfung. + +| Ort | Ergebnis | +| --- | --- | +| `/srv/syncova-restore` | ✓ von `setup.sh` angelegt und eingetragen | +| weitere aus `--wiederherstellungsziel` | ✓ | +| `/tmp/…` | ✗ landet im privaten `/tmp` des Dienstes und ist von außen unsichtbar | +| `/etc`, `/usr`, `/var/lib`, `/root` … | ✗ vom Zielschutz gesperrt | +| alles andere | ✗ schreibgeschützt durch `ProtectSystem=strict` | + +Der Ordnerbaum in der Oberfläche beantwortet das direkt: Er meldet je +Verzeichnis, ob der Dienst dort schreiben darf — **gemessen** durch eine +Probedatei, nicht aus den Rechtebits abgeleitet. + +Ein weiteres Ziel nachträglich freigeben: + +```bash +sudo systemctl edit syncova-api # ReadWritePaths= ergänzen +sudo systemctl restart syncova-api +``` + ### Über die Oberfläche -Wiederherstellungspunkte → Punkt wählen → *Wiederherstellen* → Zielpfad angeben. +Wiederherstellungspunkte → Punkt wählen → *Wiederherstellen*. + +1. **Ziel** über den Ordnerbaum wählen. Beschreibbare Orte stehen oben als + Vorschlag; ein Unterverzeichnis lässt sich anlegen. +2. **Umfang** über den Backup-Browser wählen — das gesamte Backup, ein Ordner + oder eine einzelne Datei. +3. **Vorabprüfung** — sie schreibt nichts und stellt fest, ob jeder benötigte + Block noch da ist. +4. **Ausführen.** ### Über die API @@ -68,7 +103,16 @@ curl -X POST https:///api/v1/restores \ }' ``` -`path_prefix` beschränkt auf einen Teilbaum. Ohne ihn kommt alles zurück. +`path_prefix` trifft **einen Ordner oder eine einzelne Datei**: Der Server +vergleicht auf Gleichheit oder Präfix mit Verzeichnisgrenze — `dokumente` +trifft dabei nicht `dokumentation`. Ohne ihn kommt alles zurück. + +Den Inhalt eines Backups durchsehen, ohne etwas zurückzuschreiben: + +```bash +curl -s -H "Authorization: Bearer " \ + "https:///api/v1/backups//contents?path=berichte" | jq '.data.entries' +``` Fortschritt: