Commit Graph

15 Commits

Author SHA1 Message Date
b50ad2b9bc Sitzung ueberlebt Neuladen, Umlaute, Fehlergrenze
**Sitzung.** Die Tokens lagen nur im Arbeitsspeicher — jedes Neuladen warf den
Betreiber auf die Anmeldemaske. Das war die sicherste Variante und praktisch
unbrauchbar; mitten in einer Stoerung ist es kein Sicherheitsgewinn, sondern ein
Hindernis. Jetzt `sessionStorage` (nicht `localStorage`: stirbt mit dem Tab),
begrenzt durch zwei Uhren:

- **Harte Obergrenze** von 30 Minuten ab Anmeldung, durch keine Interaktion
  verschiebbar. Sonst waere "30 Minuten" keine Zusage.
- **Untaetigkeitsgrenze** von 30 Minuten.
- Der sofortige serverseitige Widerruf bleibt die eigentliche Absicherung — die
  Tokens sind opak, kein JWT, und genau dafuer wurden sie gewaehlt.

Dazu die Sitzungsuhr oben rechts neben "Abmelden", unter fuenf Minuten
auffaellig. Umgesetzt mit `useSyncExternalStore`: Die Restzeit haengt an der Uhr
und am Speicher, also an zwei Dingen ausserhalb von React. Sie beim Rendern
auszurechnen waere ein unreiner Aufruf, sie in einem Effekt zu setzen eine
zweite Renderrunde je Sekunde — beides hat der Linter gemeldet.

Sechs Tests halten die Grenzen fest, zwei davon durch Mutation als fangend
bestaetigt (Obergrenze mitverschieben schlaegt fehl).

**Fehlergrenze.** Ein Fehler in einer Komponente riss bisher den gesamten Baum
ab; uebrig blieb eine leere Seite — im dunklen Thema ein schwarzer Bildschirm
ohne jeden Hinweis. Die Grenze sitzt **um den Inhalt**: Menue und Kopfzeile
bleiben stehen, der Fehlertext ist lesbar und kopierbar.

**Umlaute.** Die Oberflaeche schrieb durchgehend ae/oe/ue/ss. Jetzt aeoeuess.

Dabei ein selbst verursachter Schaden, gefunden und behoben: Eine Regel
"ue → ü" ist falsch, weil die Buchstabenfolge nicht immer ein Umlaut ist. Sie
machte aus "Quelle" ein "Qülle", aus "neue" ein "neü", aus "aktuell" ein
"aktüll", aus "Dauer" ein "Daür". Die Abbildung laeuft jetzt ueber eine
gepruefte Wortliste mit Ausschluss englischer Bezeichner (`value`, `message`,
`session`, `queued`, `true`); die 23 zerstoerten Woerter sind einzeln
zurueckgesetzt. Ein alter Tippfehler ("geprueter") ist dabei mit aufgefallen.

82 Tests gruen, tsc sauber, eslint ohne Warnung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 14:42:37 +02:00
698f3a17d9 Dokumentation und Aenderungsliste fuer rc6
Some checks failed
CI / Backend (Go) (push) Failing after 31s
CI / Frontend (React/TypeScript) (push) Successful in 44s
CI / Sicherheitsprüfungen (push) Successful in 27s
docs/web-ui.md beschrieb die Oberflaeche aus Phase 12 — eine, die es nicht mehr
gibt. Eine Anleitung, die auf Bereiche verweist, die anders heissen und anders
funktionieren, ist schlimmer als keine: Der Leser sucht den Fehler bei sich.
Neu geschrieben.

Eine Aussage darin habe ich beim Nachpruefen korrigiert: `/api/v1/events/stream`
steht zwar in SYNCOVA_API.md, ist aber **auch serverseitig** nicht umgesetzt.
"Nicht angebunden" haette den Mangel der Oberflaeche zugeschoben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 14:05:15 +02:00
6e23696fcb Weboberflaeche: letzte Seiten auf das Design-System gezogen
Some checks failed
CI / Backend (Go) (push) Failing after 30s
CI / Frontend (React/TypeScript) (push) Successful in 43s
CI / Sicherheitsprüfungen (push) Successful in 27s
Damit gibt es nur noch ein Stylesheet. Uebersicht, Meldungen, Kennzahlen,
Berichte, Security Center, Wiederherstellungspunkte, Anmeldung, Backup-Assistent
und Gesundheitsanzeige nutzten noch das alte — sie funktionierten, sahen aber
anders aus als der Rest.

Der Backup-Assistent wurde als **Klassenabbildung** umgestellt, nicht neu
geschrieben: Seine Logik ist geprueft und richtig; eine Neufassung haette 500
Zeilen Verhalten ohne Not angefasst. Die elf Tests des Assistenten pruefen
Verhalten und blieben unveraendert gueltig.

Entfernt, weil ersetzt und nirgends mehr verwendet: JobsPanel, StatusIndicator,
PageState, App.css, tokens.css und vier weitere Stylesheets. Das ausgelieferte
CSS faellt von 54 auf 30 KB.

Drei Funde beim Umbau, alle von Tests aufgedeckt:

- **`describeApiError` warf die genauere Servermeldung weg.** Sie ersetzte sie
  durch den allgemeinen Satz aus der Codetabelle. Ein `SERVICE_UNAVAILABLE` mit
  der Meldung "Fuer diesen Bericht ist keine Sicherheitspruefung eingerichtet."
  wurde zu "Der Dienst ist derzeit nicht vollstaendig verfuegbar" — der
  Betreiber haette den Fehler bei seiner Anlage gesucht statt bei der
  Einrichtung dieses einen Berichts. Jetzt hat die Servermeldung Vorrang; die
  Tabelle springt nur ein, wenn keine mitkommt.
- **Einem Fehler nach einer Handlung fehlte `role="alert"`.** Ein Screenreader
  haette ihn nicht angesagt. `Callout` nimmt jetzt eine Rolle entgegen; Standard
  bleibt `note`, weil die meisten Hinweise schon beim Oeffnen dastehen.
- **Zwei Statusbeschriftungen wichen von den etablierten ab** (`Gesund` statt
  `Fehlerfrei`, `Nicht verbunden` statt `Nicht erreichbar`). Die etablierten
  gewinnen — sie stehen in Tests fest und sind treffender.

Dazu zwei kleinere Korrekturen: Die Gesundheitsanzeige hing kurzzeitig in der
Uebersicht und verband damit zwei Ladewege, die nichts miteinander zu tun haben;
sie steht jetzt wieder daneben. Und ein frueherer Regex hatte
`(row) => void | undefined` erzeugt — gemeint war eine optionale Eigenschaft,
geschrieben stand "gibt void oder undefined zurueck".

Nachgewiesen gegen Debian 12 mit nginx: alle 18 Seiten liefern 200, das
Design-System steckt im ausgelieferten CSS samt Dark-Mode-Regeln, und vom alten
Stylesheet ist kein Klassenname mehr darin.

76 Tests gruen, tsc sauber, eslint ohne Warnung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 13:50:15 +02:00
ccfff87d3f Weboberflaeche: vollstaendige Verwaltungskonsole
Some checks failed
CI / Backend (Go) (push) Failing after 30s
CI / Frontend (React/TypeScript) (push) Successful in 43s
CI / Sicherheitsprüfungen (push) Successful in 27s
Von 95 fachlichen Endpunkten erreicht die Oberflaeche jetzt 89 statt 23.
Schreibend waren es neun (vier davon An- und Abmeldung) — jetzt ist jede
Handlung der Anlage bedienbar.

Neu bedienbar:

- **Wiederherstellung** als vierstufiger Assistent. Die Vorabpruefung ist ein
  eigener Schritt, weil sie den Unterschied zwischen Hoffnung und Nachweis
  macht: Sie schreibt nichts und stellt fest, ob **jeder benoetigte Block noch
  da ist**. Ein Manifest allein belegt nur, dass jemand einmal etwas gesichert
  hat. Die drei Huerden vor dem Ueberschreiben sind sichtbar umgesetzt; laeuft
  die dritte ins Leere, entfaellt sie — ein Ritual ohne Anlass gewoehnt das
  Wegklicken an.
- **Wiederherstellungspunkte** mit Bewertung, Schutz, Ransomware-Einschaetzung,
  Legal Hold, Fristverlaengerung und Loeschung. Eine unbelastbare Prozentzahl
  wird als Vermutung gekennzeichnet, ungemessene Eingangsgroessen erscheinen als
  "ungemessen" statt als null Punkte.
- **Pruefung** mit allen fuenf Pruefarten. Zustand und Ergebnis stehen
  nebeneinander: Eine gescheiterte Pruefung ist kein Befund am Backup.
- **Repositories** mit Integritaetslauf, Katalog-Neuaufbau, Gesundheitspruefung
  und gemessener Durchsetzungsstufe. Die Uebernahme sagt ausdruecklich, dass
  hier nichts angelegt wird.
- **Aufbewahrung** mit Regeln und Vorschau vor dem Loeschen.
- **Proxmox** (neun Endpunkte, bisher ohne jede Oberflaeche) und **Agenten**
  samt einmaliger Anzeige des Aufnahme-Tokens.
- **Benutzer, Rollen, Benachrichtigungswege, eigener zweiter Faktor.**

Zwei Funde beim Nachweis gegen den laufenden Dienst:

- **Die Einstufung heisst `successful`, nicht `unverified`.** Das Vokabular
  lautet failed/corrupted/successful/verified/recoverable. `successful` ist die
  Falle: Es bedeutet "der Lauf ist durchgelaufen" — nicht "wiederherstellbar".
  Es ist deshalb **neutral**, nicht gruen; ein gruenes Abzeichen laese sich als
  "geprueft und in Ordnung", und genau diese Verwechslung soll die Anlage
  verhindern. Regressionstest, durch Mutation als fangend bestaetigt.
- **Der Geheimnis-Scanner griff korrekt** beim Platzhaltertext des
  SSH-Schluesselfelds. Gekennzeichnet statt das Muster aufzuweichen.

Die Statuszuordnung steht an genau einer Stelle und faellt fuer unbekannte
Werte auf neutral zurueck, nie auf gruen: Ein neuer Serverzustand darf nicht
als "in Ordnung" durchgehen.

Nachgewiesen im Container gegen Debian 12 mit echtem PostgreSQL und nginx,
ueber genau die Aufrufe, die die Konsole macht: Repository uebernommen,
Durchsetzungsstufe gemessen (advisory — korrekt auf overlayfs), Auftrag
angelegt, Lauf 202, zweiter Anstoss 409, Sicherung erfolgreich (2 Objekte,
3.000.006 Byte, 0 uebergangen), Blockpruefung clean (5 Bloecke), Vorabpruefung
"wiederherstellbar: 2 Dateien, 2,9 MiB", Wiederherstellung nach /etc
abgewiesen.

76 Tests gruen, tsc sauber, eslint ohne Warnung, Bau 460 KB (136 KB gzip).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 13:35:05 +02:00
b3f0a99243 Weboberflaeche: Design-Fundament und bedienbare Auftraege
Some checks failed
CI / Backend (Go) (push) Failing after 30s
CI / Frontend (React/TypeScript) (push) Successful in 44s
CI / Sicherheitsprüfungen (push) Successful in 27s
Ausgangslage, gemessen statt geschaetzt: Von 99 fachlichen Endpunkten rief die
Oberflaeche 23 auf. Schreibend waren es neun, vier davon An- und Abmeldung.
Real verwaltbar war: einen Auftrag anlegen, einen Bericht erzeugen, eine
Meldung bestaetigen. Das ist ein Leseinstrument, keine Verwaltungskonsole.

Dieser Schritt legt das Fundament und macht den ersten Bereich vollstaendig
bedienbar.

Fundament:

- Tailwind v4 und Radix-Primitive (shadcn-Muster). Alles gebuendelt, keine
  externen Ressourcen — die CSP der Auslieferung laesst sie ohnehin nicht zu.
- Farbsystem nach PROMPT.md §106: Semantische Farben ausschliesslich fuer
  Status, sonst neutral. Die Zuordnung der Fachbegriffe auf die fuenf
  Bedeutungen steht an genau **einer** Stelle (StatusBadge). Verteilt ueber die
  Seiten erschiene frueher oder spaeter irgendwo "partial_failure" gruen, und
  ein Betreiber haelt einen Teilfehler dann fuer einen Erfolg. Ein unbekannter
  Zustand wird neutral dargestellt, nie gruen.
- Neue Seitenhuelle mit fuenf Bereichen, einklappbarer Seitenleiste, Schublade
  auf schmalen Geraeten und Dark Mode ueber ein Attribut am Wurzelelement (nicht
  allein ueber die Medienabfrage — eine Konsole, die nachts waehrend einer
  Stoerung von selbst umschaltet, ist laestig).
- `useMutation` fuer schreibende Aufrufe: Doppelklickschutz, Vorgangsnummer bis
  in die Meldung, kein setState nach dem Aushaengen. `describeApiError`
  uebersetzt die bekannten Fehlercodes in Saetze **mit Abhilfe**.
- Der API-Client sendet jetzt `Idempotency-Key`. Ohne ihn erzeugt ein
  Doppelklick zwei Auftraege — und bei einer Wiederherstellung zwei
  gleichzeitige Laeufe in dasselbe Ziel.
- Fehlermeldungen nennen immer die `request_id`, kopierbar.

Auftraege (Endpunkte, die vorher keine Oberflaeche hatten):

- Lauf anstossen, anhalten, fortsetzen, loeschen, laufenden Lauf abbrechen.
- Detailseite mit Laufhistorie: Fehlercode, Fehlerklasse und die Auskunft, ob
  eine Wiederholung ueberhaupt etwas bringt — ein Anmeldefehler behebt sich
  nicht durch Warten.
- **Ein zweiter Anstoss ist kein Fehler, sondern eine Auskunft.** Der 409 wird
  als Hinweis gezeigt, nicht als Fehlschlag: Der Auftrag laeuft ja, und genau
  das wollte der Betreiber.
- **Loeschen nennt die Folgen.** Die Wiederherstellungspunkte bleiben bestehen;
  sie gehoeren zum Repository, nicht zum Auftrag. Ohne diesen Hinweis loescht
  jemand einen Auftrag in der Annahme, Platz zu schaffen.

Der Wiederherstellungs-Assistent ist gebaut (vier Schritte, Vorabpruefung als
eigener Schritt, die drei Huerden vor dem Ueberschreiben sichtbar umgesetzt),
aber noch nicht in eine Seite eingebunden.

Drei Lint-Befunde behoben, alle dieselbe Sorte wie in Phase 8 und 12:
setState im Effektkoerper und ein Schreibzugriff auf eine Referenz waehrend des
Renderns. Der Bestaetigungsdialog haelt seinen Zustand jetzt im Portalinhalt —
beim Schliessen verschwindet er von selbst, ein Zuruecksetzen im Effekt
entfaellt, und die Huerde steht beim naechsten Oeffnen wieder.

Die noch nicht umgebauten Seiten behalten vorerst das alte Stylesheet. Es faellt
weg, sobald die letzte umgebaut ist.

69 Tests gruen, tsc sauber, eslint ohne Warnung, Bau 373 KB (115 KB gzip).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 09:25:42 +02:00
b6668c600d Weboberflaeche richtet sich mit ein (rc5)
Some checks failed
CI / Backend (Go) (push) Failing after 29s
CI / Frontend (React/TypeScript) (push) Successful in 33s
CI / Sicherheitsprüfungen (push) Successful in 24s
Bisher endete setup.sh mit einer laufenden API auf 127.0.0.1:8080 und der
Aufgabe, einen Webserver von Hand davorzusetzen. Das war der haeufigste Punkt,
an dem eine Einrichtung liegen blieb.

setup.sh richtet jetzt nginx ein und stellt ein selbst signiertes Zertifikat
aus. Es gilt fuer Rechnernamen, vollstaendigen Namen und jede globale
IPv4-Adresse (subjectAltName — moderne Browser lesen den CN nicht mehr), 3650
Tage; der SHA-256-Fingerabdruck wird genannt.

Drei Entscheidungen:

- Die API bleibt an 127.0.0.1:8080 gebunden. Sie auf alle Schnittstellen zu
  legen waere der kuerzere Weg und der falsche: Die Verschluesselung liesse
  sich dann umgehen, indem man Port 8080 direkt anspricht.
- Die Firewall wird gemeldet, nicht geaendert. Eine Einrichtung, die
  selbsttaetig einen Port ins Netz oeffnet, hebelt genau die Entscheidung aus,
  fuer die jemand die Firewall aufgesetzt hat.
- Scheitert die Oberflaeche, scheitert nicht die Einrichtung. Geprueft wird mit
  nginx -t, bevor die Konfiguration uebernommen wird; haelt sie nicht, wird sie
  entfernt und der Nachholweg gezeigt.

Zwei Funde beim Erproben:

- http2 on; gibt es erst ab nginx 1.25.1. Debian 12 liefert 1.22, wo HTTP/2 ein
  Parameter von listen ist — die neue Schreibweise ergibt dort "unknown
  directive http2", und nginx startet nicht. Die Fassung wird jetzt gelesen.
- setup.sh kopierte nur diagnose.sh neben die Programme. Der eigene Hinweis
  "Spaeter nachholen: /opt/syncova/setup.sh --weboberflaeche" verwies damit auf
  eine Datei, die es nicht gab; schwerer wiegt uninstall.sh — wer das
  ausgepackte Paket aufraeumte, haette die Anlage nie wieder entfernen koennen.
  Jetzt kommen alle vier Skripte mit.

Nachgewiesen im Container gegen Debian 12 mit nginx 1.22: Neuinstallation von
Grund auf, Oberflaeche und /api/ von aussen ueber HTTPS erreichbar (200),
SPA-Fallback traegt, Anmeldung und Repository-Anlage durch nginx hindurch,
Durchsetzungsstufe gemessen, HTTP leitet mit 301 auf HTTPS, Fingerabdruck
stimmt mit dem genannten ueberein, Neuausstellung des Zertifikats geprueft.

Regressionstests fuer beide Funde, beide durch Mutation als fangend bestaetigt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 08:53:15 +02:00
22763f927f Fehler #2: Bereitschaftspruefung haengt an curl
Some checks failed
CI / Backend (Go) (push) Failing after 31s
CI / Frontend (React/TypeScript) (push) Successful in 33s
CI / Sicherheitsprüfungen (push) Successful in 23s
Gemeldet wurde ein Abbruch der Einrichtung mit "Der Dienst meldet sich nicht als
betriebsbereit". Der Dienst lief einwandfrei — das Protokoll im Bericht zeigt
einen vollstaendigen Start, und genau fuenfzehn Sekunden spaeter beendet ihn der
Rueckbau. Fuenfzehn Sekunden sind genau fuenfzehn Pruefversuche.

Die Ursache stand ebenfalls im Bericht, eine Zeile weiter oben:

  ## Gesundheit
  curl ist nicht vorhanden.

setup.sh prueft die Betriebsbereitschaft ausschliesslich mit curl. Auf einem
schlanken Serverabbild ist der nicht installiert; das ist der Normalfall und
nicht die Ausnahme. Die Pruefung kam nicht an den Dienst heran, hielt das fuer
einen gescheiterten Start und baute eine funktionierende Anlage zurueck.

Ein Einrichtungsskript darf nicht voraussetzen, was es nicht selbst mitbringt.

Jetzt drei Wege: curl, sonst wget, sonst /dev/tcp der Bash — letzteres gehoert
zur Shell selbst und ist damit ueberall vorhanden. Betrifft setup.sh, update.sh
und diagnose.sh; der Diagnosebericht nennt zusaetzlich, womit er gemessen hat.

Real nachgewiesen auf einem System ohne curl UND ohne wget: rc3 bricht ab, die
korrigierte Fassung laeuft durch. Regressionstest vorhanden und als fangend
geprueft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 08:22:47 +02:00
a37631c501 Fehler #1: Repository unter /tmp macht den Dienst startunfaehig
Some checks failed
CI / Backend (Go) (push) Failing after 32s
CI / Frontend (React/TypeScript) (push) Successful in 35s
CI / Sicherheitsprüfungen (push) Successful in 24s
Gemeldet wurde ein Abbruch der Einrichtung mit "Der Dienst meldet sich nicht als
betriebsbereit". Der Diagnosebericht enthielt die Ursache woertlich:

  syncova-api.service: Failed to set up mount namespacing:
      /tmp/syncova-repository: No such file or directory
  status=226/NAMESPACE

Die Diensteinheit setzt PrivateTmp=yes. Der Dienst bekommt damit ein eigenes
/tmp, und der in ReadWritePaths genannte Ablageort existiert in seiner Sicht
nicht — systemd bricht ab, bevor das Programm ueberhaupt laeuft.

Der technische Fehler ist der kleinere. Der groessere ist, dass setup.sh einen
Ablageort unter /tmp ueberhaupt angenommen hat: systemd-tmpfiles raeumt dort
regelmaessig auf, und auf einem tmpfs ist nach einem Neustart nichts mehr da.
Ein Backupsystem, das jede Nacht Erfolg meldet und keine Daten hat, ist
schlimmer als gar keines.

Deshalb:

- Fluechtige Ablageorte werden abgelehnt: /tmp, /var/tmp, /dev/shm, /run und
  jedes tmpfs oder ramfs. Geprueft wird VOR der Datenbankeinrichtung — ein
  unbeaufsichtigter Lauf scheitert damit in Sekunden statt nach Minuten und
  einem Rueckbau.
- SYNCOVA_SETUP_ALLOW_VOLATILE_REPOSITORY=ja laesst es ausdruecklich zu; dann
  wird PrivateTmp abgeschaltet, sonst startet der Dienst nie. Real geprueft:
  Einheit traegt PrivateTmp=no, Dienst laeuft.
- Kommt der Dienst nicht hoch, liefert setup.sh die letzten Journalzeilen gleich
  mit und erklaert 226/NAMESPACE. Der Verweis auf journalctl allein war
  wertlos: Beim Rueckbau ist der Dienst weg, und der Meldende brauchte einen
  zweiten Anlauf, um ueberhaupt zu erfahren, was los war.

Regressionstest vorhanden und als fangend geprueft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 16:14:29 +02:00
0b5ce96c51 CHANGELOG: Abschnitt fuer rc2
Some checks failed
CI / Backend (Go) (push) Failing after 30s
CI / Frontend (React/TypeScript) (push) Successful in 34s
CI / Sicherheitsprüfungen (push) Successful in 24s
Was seit rc1 dazukam und was daran eine Korrektur ist, nicht nur eine Ergaenzung
— PostgreSQL 15 statt 17 und die nicht existierende Umgebungsvariable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 16:00:10 +02:00
4762fa29c3 Fehlervorlage und ein Diagnoseskript, das sie fuellt
Some checks failed
CI / Backend (Go) (push) Failing after 31s
CI / Frontend (React/TypeScript) (push) Successful in 34s
CI / Sicherheitsprüfungen (push) Successful in 24s
Eine Vorlage allein bringt wenig — sie stellt Fragen, die der Meldende meist
nicht beantworten kann. Deshalb zwei Teile:

diagnose.sh sammelt in einem Zug, was zur Analyse gebraucht wird: Fassungen
aller acht Programme, Betriebssystem, Container ja/nein, Dateisystem des
Repositorys, PostgreSQL-Fassung, Schemastand, Dienstzustand, Gesundheitsbericht
(der auch bei 503 den vollstaendigen Bericht traegt), Bestand, die letzten nicht
erfolgreichen Laeufe mit Fehlercode UND Fehlerklasse, die gemessene
Durchsetzungsstufe und die letzten Fehlerzeilen. Es liest nur.

Geheimnisse kommen nicht hinein, und der Weg dahin ist umgekehrt: Es gibt eine
Liste der Werte, die gezeigt werden duerfen. Eine Sperrliste vergaesse den
naechsten neuen Wert. Zusaetzlich werden die tatsaechlichen Geheimnisse gelesen
und aus JEDER Ausgabe entfernt — auch aus Protokollzeilen, in die sie auf einem
unvorhergesehenen Weg geraten sind. Real geprueft: weder Datenbankpasswort noch
Schluessel noch Administratorpasswort stehen im Bericht.

Die Vorlage beginnt mit sieben Faellen, die wie ein Fehler aussehen und gewolltes
Verhalten sind — "advisory" statt "filesystem", ein Teilfehler, "geloescht aber
nichts frei", 503 mit vollstaendigem Bericht. Das ist keine Abwehr, sondern
spart beiden Seiten einen halben Tag. Pflichtfelder sind Beobachtung, Erwartung,
Schritte, Bereich, Datenrisiko, Haeufigkeit und der Diagnosebericht; Fehlercode
und request_id stehen eigens da, weil sie die beiden wertvollsten Angaben sind.

Beim Erproben zwei Funde:

- Die Installationsanleitung verlangte PostgreSQL 17. setup.sh installiert auf
  Debian 12 aber 15 — und alles lief, bis hin zu einem echten Sicherungslauf.
  Die Anforderung lautet jetzt 15 (geprueft gegen 17 in CI und Entwicklung,
  gegen 15 auf Debian 12), und setup.sh lehnt aeltere Fassungen ab statt sie
  stillschweigend zu nehmen.
- Ein Repository auf der Platte, das nicht in der Control Plane eingetragen ist,
  faellt niemandem auf: Die Sicherung laeuft nie, weil der Server das Ziel nicht
  kennt. Der Bericht benennt diesen Fall jetzt ausdruecklich.

Gegen das echte v1.0.0-rc1-Paket gefahren: Installation, erzeugte Stoerung
(ALL_SOURCES_FAILED / source), Bericht zeigt Code, Klasse, "overlayfs" und
"nie gemessen".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 15:58:00 +02:00
0c5a106a83 setup.sh, update.sh und uninstall.sh
Some checks failed
CI / Backend (Go) (push) Failing after 31s
CI / Frontend (React/TypeScript) (push) Successful in 33s
CI / Sicherheitsprüfungen (push) Successful in 24s
Drei Betriebsskripte fuer Linux, im Auslieferungspaket neben den Programmen.

setup.sh richtet eine Anlage vollstaendig ein: PostgreSQL auf Wunsch mit
(apt/dnf/yum/zypper/pacman), Dienstkonto, Verschluesselungsschluessel, Schema,
erster Administrator, gehaertetes Repository, gehaertete systemd-Einheit. Jeder
Schritt vermerkt, was er angelegt hat; bricht der Lauf ab, wird genau das
zurueckgebaut und nichts sonst. Eine bestehende Installation wird nicht
ueberschrieben — dafuer gibt es update.sh, und der Unterschied ist, dass ein
Update vorher sichert.

update.sh haelt die Reihenfolge ein, um die es geht: sichern, anhalten,
tauschen, migrieren, starten, pruefen. Kommt der Dienst danach nicht hoch, holt
es die vorige Fassung zurueck. Ohne pg_dump wird gar nicht erst begonnen — ohne
Sicherung gibt es nach einer misslungenen Migration keinen Weg zurueck.
Repository und Verschluesselungsschluessel bleiben unberuehrt.

uninstall.sh entfernt standardmaessig NUR Dienst und Programme. Datenbank,
Repository und Konfiguration bleiben liegen; jede dieser Loeschungen verlangt
ein woertlich getipptes Bestaetigungswort an einem Terminal. Ein
Deinstallationsskript, das nebenbei die Backups mitnimmt, vernichtet genau das,
wofuer jemand jahrelang Speicher bezahlt hat.

Gegen Debian 12 im Container gefahren — Installation, Anmeldung, Repository
eingetragen, Loeschschutz gemessen (advisory auf overlayfs, richtig), echter
Sicherungslauf, Update mit unveraendertem Bestand, beide Abbauarten.

Drei Fehler dabei gefunden und behoben, alle derselben Art:

- "tr </dev/urandom | head -c 32" und "psql | grep -q": Der frueh geschlossene
  Pipe schickt dem Schreiber SIGPIPE, und mit "set -o pipefail" bricht das
  Skript mitten in der Einrichtung ab, ohne erkennbaren Grund.
- update.sh las die laufende Fassung mit "grep -o" aus der Antwort von
  /health/ready. Die enthaelt gar kein Versionsfeld; grep endet mit 1, und das
  Skript nahm ein GELUNGENES Update wieder zurueck — wegen einer Zeile, die nur
  der Ausgabe dient.

Dazu: SYNCOVA_ADMIN_PASSWORD stand in der Doku und existiert nicht — das
Passwort kommt ueber die Standardeingabe. Und "syncova-repo break-lock" fehlte
zwar nicht mehr, aber der Test auf die Uebereinstimmung der drei Skripte ist
neu: Drei Skripte, die sich ueber den Installationsort uneinig sind, ergeben
eine Anlage, die sich nicht mehr entfernen laesst.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 15:33:41 +02:00
e1fd31e9c8 CI: Schema vor den Tests anlegen
Some checks failed
CI / Backend (Go) (push) Failing after 29s
CI / Frontend (React/TypeScript) (push) Successful in 34s
CI / Sicherheitsprüfungen (push) Successful in 23s
Der vorige Commit setzte SYNCOVA_TEST_DATABASE_URL, damit die Datenbanktests in
der CI nicht mehr still uebersprungen werden. Das haette die CI rot gemacht: Die
Tests laufen dort **vor** dem Migrationsschritt, die Datenbank ist zu dem
Zeitpunkt leer, und neun Testdateien scheitern an einem fehlenden Schema.

Aufgefallen ist es beim Nachbau der CI-Umgebung in einem Container — nicht in
der CI selbst, weil die Actions-API dieser Gitea-Fassung nicht erreichbar ist.

Jetzt:

- "Schema vor den Tests anlegen" laeuft als eigener Schritt vor den Tests.
- Der Migrationszyklus (down/up) bleibt danach. Zwischen down und up fehlt eine
  Migration; ein Test in genau diesem Moment scheiterte an einem Schemastand,
  den es im Betrieb nie gibt.

Die Verbindungszeichenkette des CI-Containers traegt secretscan:erlaubt — in
derselben Zeile, nicht darueber, sonst greift der Vermerk nicht.

Nachgewiesen gegen eine frische PostgreSQL 17 in der exakten Reihenfolge der
CI: gofmt, go vet, Schema, Tests mit Race-Detector, Migrationszyklus,
cross-build — alle sechs Schritte bestanden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 09:53:09 +02:00
c4f0b3e665 Anleitung zum Veroeffentlichen und Testen des Systems
Some checks failed
CI / Backend (Go) (push) Failing after 1m46s
CI / Frontend (React/TypeScript) (push) Successful in 33s
CI / Sicherheitsprüfungen (push) Successful in 23s
Zwei Teile: Release bauen und in Gitea veroeffentlichen, und das System in vier
Stufen durchtesten — Rauchtest, Rundlauf, Agent, Proxmox.

Jede Stufe endet mit dem, was danach belegt ist, und der Rundlauf hat eine
Gegenprobe: nicht leeres Ziel, rm -rf gegen ein gehaertetes Repository und ein
gekippter Block muessen scheitern beziehungsweise erkannt werden. Ein Test, der
nur den Erfolgsfall zeigt, belegt wenig.

Der Vorschlag fuer den ersten Tag ist v1.0.0-rc1, nicht v1.0.0: Solange
Windows-Dienst, systemd-Einheit und der Proxmox-Boot ungeprueft sind, waere
1.0.0 eine Zusage, die diese drei Punkte nicht deckt.

Jeder genannte Endpunkt wurde gegen den eingefrorenen API-Vertrag gehalten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 09:47:30 +02:00
9c48cb1c1c CI: Loeschschutz messen statt annehmen, Datenbanktests wirklich fahren
Some checks failed
CI / Sicherheitsprüfungen (push) Waiting to run
CI / Backend (Go) (push) Failing after 1m47s
CI / Frontend (React/TypeScript) (push) Has been cancelled
Der Angriffstest auf ein gehaertetes Repository scheiterte in der CI: "rm -rf
auf ein geschuetztes Repository gelang vollstaendig". Der Befund ist richtig —
und der Fehler lag im Test, nicht im Produktivcode.

immutableFlagSupported() sagt nur, ob das Betriebssystem das
Unveraenderlich-Kennzeichen *kennt*; unter Linux gibt es immer "ja" zurueck. Ob
es auch *durchgesetzt* wird, haengt am Dateisystem und an CAP_LINUX_IMMUTABLE.
In einem Container auf overlayfs ist beides nicht gegeben: Das Setzen scheitert
still, und der Angriff gelingt.

Die Anlage selbst macht es richtig — sie ist beim Setzen nachsichtig (ein Backup
ohne technischen Loeschschutz ist besser als gar keines) und sagt die Wahrheit
ueber die gemessene Stufe. Der Test tut das jetzt auch: Er misst zuerst und
prueft nur dort, wo es etwas zu pruefen gibt. Nachgewiesen in beide Richtungen —
auf macOS laeuft der Angriff wirklich, im Container wird mit Begruendung
uebersprungen.

Zwei Luecken in der CI dabei gefunden:

- SYNCOVA_TEST_DATABASE_URL fehlte. Neun Testdateien uebersprangen ihre
  Datenbanktests still, darunter der Upgrade- und der Rollback-Test. Ein
  uebersprungener Test sieht in der Zusammenfassung aus wie ein bestandener.
- make cross-build lief nicht mit. Genau daran ist in Phase 5 monatelang
  unbemerkt geblieben, dass der Agent sich fuer Windows gar nicht uebersetzen
  liess.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 09:45:27 +02:00
610719c316 Syncova Backups V1
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
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