Dokumentation und Aenderungsliste fuer rc8
Some checks failed
CI / Backend (Go) (push) Failing after 32s
CI / Frontend (React/TypeScript) (push) Successful in 46s
CI / Sicherheitsprüfungen (push) Successful in 28s

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 b78a6fb51c
3 changed files with 126 additions and 4 deletions

View File

@ -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.

View File

@ -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

View File

@ -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://<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: