Commit Graph
4 Commits
Author SHA1 Message Date
alientimandClaude Opus 5 160675e368 upgrade.sh und update.sh genuegen als einzelne Datei
Auf einer 1.2.8 liegt nichts von dieser Fassung -- upgrade.sh verlangte aber
ein install.sh daneben und brach sonst ab. Das war die falsche Voraussetzung
fuer genau den Fall, fuer den das Skript gedacht ist. Beide Skripte holen sich
das Release jetzt selbst:

    curl -fsSLO .../raw/branch/main/deploy/upgrade.sh
    sudo bash upgrade.sh --app tesm

Liegt das Skript in einem entpackten Release, wird dessen install.sh benutzt
statt eines Downloads: wer ein Paket ausgepackt hat, will nicht, dass ungefragt
ein anderes geladen wird. Mit --tag laesst sich eine Version festlegen.

Der Bootstrap steht wortgleich in beiden Dateien -- zwei eigenstaendige
Skripte koennen sich keine Datei teilen, und beide sollen allein genuegen. Ein
Hygienetest vergleicht die Bloecke, ein zweiter prueft, dass upgrade.sh kein
entpacktes Release mehr verlangt, ein dritter fuehrt den Block mit leerem PATH
aus und erwartet, dass er das fehlende Werkzeug benennt.

update.sh ruft install.sh nicht mehr per exec auf: dadurch lief die
Aufraeumfalle nie, und jedes Update liess ein entpacktes Release unter /tmp
liegen.

Ausserdem "opus" aus allen Beispielen genommen. Das war der Name der
Testinstanz neben der Fassung 1.x; seit dem Umbenennen heissen die
Installationen wie ihre Anwendung, und in einer Hilfe, die jemand anders liest,
ist "opus" ein Raetsel. In BETRIEB.md stand dabei zweimal /opt statt /srv.

Geprueft am System, nicht behauptet: die einzelne upgrade.sh hat eine echte
1.2.8 (Kopie des Archivs) **in dasselbe Verzeichnis** auf 2.0.8 gebracht --
Release geladen, 4 Clients, 2 Zugangsdaten und die DHCP-Konfiguration
uebernommen, Dienst laeuft, /login 200. Die Sicherung enthaelt die 1.2.8 samt
sqlite.db und fernet.key (Verzeichnis 0700, Passphrase 0600), und /tmp bleibt
leer. Danach dieselbe Probe mit der einzelnen update.sh.

Version 2.0.9.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 16:18:52 +02:00
alientimandClaude Opus 5 4065b3586b Freigaben einbinden, apt-Installation und RPC-Neustart korrigiert
Drei Fehler, alle drei gemessen statt vermutet.

1. Freigaben wurden nie eingebunden ("mount error(1): Operation not
   permitted"). Ursache war NICHT der Mount-Namensraum, sondern
   SystemCallFilter=@system-service: darin fehlen mount/umount2, und
   SystemCallErrorNumber=EPERM macht daraus genau diese Meldung. Nachgewiesen
   in einem nachgebauten Sandkasten: mit "@mount" gelingt die Einbindung,
   ohne nicht. Die Unit von TESM erlaubt jetzt "@system-service @mount"; alles
   andere an der Haertung bleibt. Der zuvor eingebaute Umweg ueber nsenter ist
   zurueckgenommen -- RestrictNamespaces=yes verbietet setns, er konnte nie
   funktionieren.

   Eingebunden wird damit im Namensraum des Webprozesses. Deshalb ist die
   Aufraeumaufgabe fuer abgelaufene Einbindungen aus dem Ueberwachungsdienst in
   den Webprozess gewandert: ein anderer Dienst sieht diese Einbindungen nicht
   und haette Datenbankzeilen als geloest markiert, waehrend die Freigabe
   eingebunden blieb.

2. apt-Installationen aus der Oberflaeche scheiterten mit "dpkg returned an
   error code (1)". Der Sandkasten wird an dpkg und dessen Maintainer-Skripte
   weitervererbt; mit ProtectKernelLogs=yes liefert "dmesg" ein EPERM und ein
   Postinst-Skript bricht daran ab. apt laeuft jetzt ueber systemd-run, also
   von PID 1 gestartet und damit ohne unsere Haertung.

3. Der RPC-Neustart loeste SSH aus. run_reboot entschied den Weg anhand von
   device["category"] -- und dieser Schluessel bedeutet je Herkunft etwas
   anderes: die Wartungsabfrage legt die Kategorie der *Zugangsdaten* darunter,
   inventory.get_device die des *Geraets*. Ueber die Statusuebersicht kam ein
   Windows-Geraet mit leerer Geraetekategorie an, wurde fuer Linux gehalten und
   ueber SSH auf Port 22 angesprochen, bis das Zeitlimit griff. Der Weg wird
   jetzt uebergeben -- entschieden wird er ohnehin schon vorher in
   restart.resolve. Ausserdem zeigte die Neustart-Historie alles ausser "ssh"
   als "PoE-Port"; RPC hat jetzt einen eigenen Eintrag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 21:49:40 +02:00
alientimandClaude Opus 5 5bb0809009 Freigaben einbinden: Mount im Namensraum des Wirts
Eine Freigabe wurde nie eingebunden -- "mount error(1): Operation not
permitted". Gemessen: mit denselben Optionen und Zugangsdaten gelingt die
Einbindung aus einer normalen Root-Shell sofort. Ursache ist der eigene
Mount-Namensraum des Dienstes (ProtectSystem, ProtectHome, PrivateTmp,
ReadWritePaths); darin laesst sich kein neues Dateisystem einbinden.

Nachgebaut und belegt: derselbe Aufruf scheitert in einem transienten Unit mit
dieser Haertung und gelingt, sobald er ueber nsenter im Namensraum des Wirts
laeuft. Von dort wird der Mount in den Namensraum des Dienstes weitergegeben,
die Anwendung sieht ihn also -- geprueft, inklusive Lesbarkeit fuer den
Dienstbenutzer.

mount-cifs und umount laufen deshalb ueber nsenter. Ohne nsenter im System
bleibt das Verhalten unveraendert. Die Haertung des Dienstes bleibt vollstaendig
erhalten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 21:20:51 +02:00
alientimandClaude Opus 5 7354ff352b TESM 2.0.0 -- Neubau
Vollstaendiger Neubau der Anwendung. Der vorherige Stand bleibt unveraendert
im Zweig SONNET5 erhalten.

Aufbau: apps/tesm (Anwendung), packages/tesm-core (gemeinsamer Kern),
packages/tesm-licensing (Lizenzprotokoll), deploy (Installation, systemd,
privilegierter Helfer), docs, tests. Der Lizenzserver liegt in seinem eigenen
Repository; beide Repositorien bringen die gemeinsamen Pakete mit, damit sich
jedes allein installieren laesst.

Die wichtigsten Unterschiede zum Vorgaenger, jeweils an der Stelle im Code
kommentiert, an der der Fehler entstanden ist:

* Der Webprozess laeuft unprivilegiert. Alles, was Root braucht, geht ueber
  einen einzigen Helfer mit Positivlisten fuer jedes Argument.
* CSRF-Schutz ueberhaupt -- der Vorgaenger hatte keinen.
* Rechte werden serverseitig geprueft, nicht nur im Template ausgeblendet.
* Die nginx-Site wird bei jedem Lauf inhaltlich verglichen und erneuert.
* Jede erzeugte Konfiguration wird vor dem Uebernehmen geprueft (nginx, Kea).
* Kein Hostname im Lizenz-Fingerabdruck.
* Zwei Installationen auf einem Host stoeren sich nicht (eigener SITE_KEY).
* Verschachtelte Datenbankverbindungen sind ein Fehler, kein Deadlock.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 18:00:06 +02:00