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:
parent
20b0919676
commit
11bad459be
54
CHANGELOG.md
54
CHANGELOG.md
@ -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.
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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:
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user