Dokumentation und Aenderungsliste fuer rc8

Der Abschnitt "Wohin darf zurueckgeschrieben werden?" im Runbook ist der
wichtigste Zusatz: Dass ein Ziel an ProtectSystem=strict scheitert und nicht an
den Rechten des Verzeichnisses, sieht man dem Fehler nicht an. Die Tabelle nennt
die vier Faelle samt Grund.

Die Beispiel-Einheit in der Installationsanleitung fuehrte in denselben Fehler —
sie nannte nur das Repository in ReadWritePaths. Eine Anleitung, deren
Ergebnis keine Wiederherstellung zulaesst, ist schlimmer als keine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Jerrit Fritzsche 2026-08-18 15:55:52 +02:00
parent 20b0919676
commit 11bad459be
3 changed files with 126 additions and 4 deletions

View File

@ -1,5 +1,59 @@
# Änderungen # Ä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 ## V1 — Release Candidate 7, 18. August 2026
Behebt einen Absturz, macht die Sitzung brauchbar und stellt das Aussehen um. Behebt einen Absturz, macht die Sitzung brauchbar und stellt das Aussehen um.

View File

@ -187,12 +187,17 @@ ExecStart=/opt/syncova/bin/syncova-api
Restart=on-failure Restart=on-failure
RestartSec=5 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 NoNewPrivileges=yes
PrivateTmp=yes PrivateTmp=yes
ProtectSystem=strict ProtectSystem=strict
ProtectHome=yes ProtectHome=yes
ReadWritePaths=/srv/syncova-repository ReadWritePaths=/srv/syncova-repository /srv/syncova-restore
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectControlGroups=yes ProtectControlGroups=yes
@ -285,6 +290,25 @@ sudo firewall-cmd --permanent --add-service=https # firewalld
sudo firewall-cmd --reload 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 ## 9. Erstes Repository
Ein Repository entsteht **auf einem Datenträger**, nicht in einer Ein Repository entsteht **auf einem Datenträger**, nicht in einer

View File

@ -51,9 +51,44 @@ Original nicht mehr.
## 1. Dateien und Ordner ## 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 ### Ü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 ### Über die API
@ -68,7 +103,16 @@ curl -X POST https://<server>/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 <token>" \
"https://<server>/api/v1/backups/<id>/contents?path=berichte" | jq '.data.entries'
```
Fortschritt: Fortschritt: