100 Commits
Author SHA1 Message Date
alientim 65a7810cf2 Version 2.8.49: das Verzeichnis sagt, wen es nennt 2026-09-17 17:26:43 +02:00
alientim a6d9a46d8f Version 2.8.48: belegter Code sichtbar, Geraetewerte zaehlen mit 2026-09-17 17:17:37 +02:00
alientim 5cc34f2a1f Version 2.8.47: Verzeichnis der eigenen Optionen 2026-09-17 16:22:19 +02:00
alientim e284d70855 Version 2.8.46: DHCP-Optionen im Klartext auf dem Client 2026-09-17 11:37:17 +02:00
alientim b4e81959e7 Version 2.8.45: Auslesezeile fuer den Client 2026-09-17 11:28:06 +02:00
alientim 29b62714cb Version 2.8.44 / Lizenzserver 2.8.22: Client-Konfiguration am richtigen Ort, Fusszeile bleibt stehen 2026-09-17 11:24:17 +02:00
alientim f59ba42e55 Version 2.8.43: ein Netz, ein Eintrag -- und die Seite sagt, was wirklich laeuft 2026-09-17 11:10:41 +02:00
alientim b1275b2c71 Version 2.8.42: sichtbare Pfeile an allem Aufklappbaren 2026-09-17 10:41:58 +02:00
alientim 1d8f92fd2d Version 2.8.41: Kea-Fassung ohne Herkunft 2026-09-17 10:27:20 +02:00
alientim 5324174f90 Version 2.8.40: Client-Konfiguration, Kea-Fassung, DHCP-Seite aufgeraeumt 2026-09-17 10:26:12 +02:00
alientim d69d177995 Version 2.8.39: gescheitertes pip bricht ab, keine ==-Bindung mehr 2026-09-17 09:39:01 +02:00
alientim f481a91773 Version 2.8.38: eine Rechnung fuer die Resttage, Module benannt 2026-09-17 09:26:31 +02:00
alientim 970f45cdf7 Version 2.8.37: eigene Sprachumgebung fuer die Skripte 2026-09-17 09:01:04 +02:00
alientim c9ceb871b6 Version 2.8.36: Lizenzabfrage fuer ein RMM auf der Maschine 2026-09-17 08:49:24 +02:00
alientim 37c508297f Version 2.8.35: der reparierte venv bleibt fuer den Dienstbenutzer lesbar 2026-09-16 21:32:20 +02:00
alientim 13bf07fecf Version 2.8.34: Skripte aus dem Baum ueber bash aufrufen 2026-09-16 21:23:51 +02:00
alientim 849b821501 Version 2.8.33: Selbstreparatur der Python-Umgebung nach einem Release-Upgrade 2026-09-16 21:17:06 +02:00
alientim 00a27018d9 Version 2.8.32: Rueckbau einer Installation (deploy/uninstall.sh) 2026-09-16 19:55:03 +02:00
alientim 95238b781f Version 2.8.31: Protokollverlauf verlangt keine Bestaetigung mehr 2026-09-16 18:07:29 +02:00
alientim 3ea7937b5b Version 2.8.30: Begruessungstext schweigt ueber entfernte Installationen 2026-09-16 17:56:53 +02:00
alientim 80d9e30bd4 Version 2.8.29 / Lizenzserver 2.8.5: Release-Upgrade von Ubuntu bricht den venv nicht mehr 2026-09-16 17:44:32 +02:00
alientim bde2df2b44 Version 2.8.28: dynamische Lease als Client uebernehmen 2026-09-16 12:28:02 +02:00
alientim 76a73017db Version 2.8.27: Live-Protokoll mit Stufen, Auftraege fallen nicht mehr heraus 2026-09-16 11:32:00 +02:00
alientim db06ddc054 Version 2.8.26: die Ordnerauswahl zeigt wieder Ordner 2026-09-15 07:11:53 +02:00
alientim e0a048fbcc Version 2.8.25: Wartungsseite ohne Neuladen, Ausweich auf die Adresse 2026-09-13 22:23:17 +02:00
alientim 9d736bb91f Version 2.8.24: Massenbefehl, Mitlesen, F5 2026-09-13 15:11:22 +02:00
alientim 914609b758 Version 2.8.23: nicht das teure Verfahren zuerst 2026-09-13 14:52:11 +02:00
alientim af81c92695 Version 2.8.22: Alt+F4, Sitzung im Fenster, bewaehrtes Verfahren zuerst 2026-09-13 14:30:37 +02:00
alientim a528e9f3b2 Version 2.8.21: die Seite wartet nicht mehr stumm 2026-09-13 14:14:38 +02:00
alientim 3b3ce96678 Version 2.8.20: einstellbares Leerlauflimit, Stille beim Aufbau benannt 2026-09-13 14:05:21 +02:00
alientim 42316ba137 Version 2.8.19: Sitzung haelt Stille aus, kein Aenderungsprotokoll 2026-09-13 13:56:57 +02:00
alientim d34baa67be Version 2.8.18: Versionspruefung im Update, zweiter Anlauf beim Bildschirm 2026-09-13 13:23:39 +02:00
alientim 491724beb5 Version 2.8.17: keine Vorauswahl, keine Messung im Seitenaufbau 2026-09-13 13:07:05 +02:00
alientim b54b87ca6f Version 2.8.16: die Ueberwachung sperrt sich nicht mehr selbst aus 2026-09-13 12:22:31 +02:00
alientim 270ba455a8 Version 2.8.15: Probe der Strecke, Grund aus _fail, RFB 3.3 2026-09-13 12:04:50 +02:00
alientim f3b312046f Version 2.8.14: Diagnose in der Bildschirmsitzung, Vorauswahl ohne Passwort 2026-09-13 11:31:41 +02:00
alientim 436b080deb Version 2.8.13: Bildschirmsitzung im Browser (noVNC) 2026-09-13 10:35:12 +02:00
alientim 85c40ccfbd Version 2.8.12 / tesm-core 2.8.4 2026-09-13 10:10:30 +02:00
alientim 0ac651a1b9 Version 2.8.11: die Kachel oeffnet den Bildschirm 2026-09-13 10:09:54 +02:00
alientim 4275c84a6c Version 2.8.10: der Name gilt nur, wenn ihn jemand aufloesen kann 2026-09-13 09:55:36 +02:00
alientim 4f4310bfe4 Version 2.8.9: VNC-Zugang, wo ein VNC-Server antwortet 2026-09-13 09:49:27 +02:00
alientim 1ad2f3f9a5 Version 2.8.8: der Notausgang holt die Gruppe aus dem Papierkorb 2026-09-13 00:27:02 +02:00
alientim 9d5eac1db2 Version 2.8.7: drei Standardgruppen, Module abschaltbar 2026-09-13 00:19:54 +02:00
alientim 2fd78ac26b Verzeichnisanmeldung: Wiederholversuch, weniger Runden, Zeiten 2026-09-12 23:46:51 +02:00
alientim 86c09d8a0f Version 2.8.5: Prompt hinter Steuerzeichen wird erkannt 2026-09-12 23:25:49 +02:00
alientim 70f6b005a9 Version 2.8.4: Konsole meldet jede Stufe, Befehl switch-test 2026-09-12 21:10:39 +02:00
alientim 57eb7764cc Version 2.8.3: Switch-Sitzung wird abgemeldet, Erfolg wird belegt 2026-09-12 20:26:30 +02:00
alientim 30c2c56656 Verzeichniskonfiguration aus 1.2.8 uebernehmen; Sicherungen setzten Schalter falsch 2026-09-12 19:26:41 +02:00
alientim 292ea622a7 Version 2.8.1: das Upgrade von 1.2.8 nimmt die Freigaben mit 2026-09-12 19:06:52 +02:00
alientim 0d99760d89 Version 2.8.0: Rechtekonzept -- eine Zeile je Funktion, Administrator heisst Verwaltung 2026-09-12 13:27:45 +02:00
alientim 713ff12db2 Version 2.7.8: die Vorschau haengt an derselben Kante wie die Datei 2026-09-12 11:37:03 +02:00
alientim 2db7e03154 Version 2.7.7: Schriftgroesse der Vorschau wird gerechnet 2026-09-12 01:34:02 +02:00
alientim 5dcb87d6ec Version 2.7.6: die Vorschau der Unterschrift zeigt das Ergebnis 2026-09-12 01:12:05 +02:00
alientim dc94a8e666 Version 2.7.5: jede Aenderung nennt alt und neu 2026-09-12 00:43:09 +02:00
alientim c639f4f507 Version 2.7.5: die Ordnerzeile sagt, was im Ordner liegt 2026-09-12 00:30:34 +02:00
alientim ad0195bab0 Version 2.7.4: Unterschriften in der Sicherung, unterschrieben ist abgeschlossen 2026-09-12 00:26:22 +02:00
alientim ce22239d78 Version 2.7.3: Zeugenvermerk einmal und in den Dokumenteigenschaften 2026-09-11 23:45:17 +02:00
alientim 92c8abb79b Zahlen im Kommentar geradegerueckt 2026-09-11 23:28:28 +02:00
alientim dcb4f57eeb Version 2.7.2: Umlaute in der Oberflaeche, Einbindungen an der Sitzung 2026-09-11 23:24:28 +02:00
alientim 11a55b20f8 Version 2.7.1: Signaturverzeichnis ueberlebt die Archivierung 2026-09-11 21:36:24 +02:00
alientim ed17bce40a Version 2.7.0: Pruefung beim Oeffnen, Unterschrift in menschlichem Mass 2026-09-11 21:23:11 +02:00
alientim 5282cd8f2d Version 2.6.1: die Speichernzeile fuehrt zur Entscheidung 2026-09-11 21:03:24 +02:00
alientim 754cbea6bb Version 2.6.0: Unterschreiben mit dem Finger, Ablage in eine andere Freigabe 2026-09-11 20:41:47 +02:00
alientim 07ae69e3b7 Version 2.5.2: Wartung ist auch in der Rechtematrix ein eigener Bereich 2026-09-11 20:16:37 +02:00
alientim d3c700283a Version 2.5.1: Sitzungsdauer im Lizenzserver, Umlaute, Umleitung alter Adressen 2026-09-11 19:16:26 +02:00
alientim 61a47debdc Version 2.5.0: englische Adressen entlang der Navigation, sparsameres Protokoll 2026-09-11 18:57:22 +02:00
alientim bec74e6936 Version 2.4.1: die Wiederanmeldung kommt aus dem Rechtemodell 2026-09-10 02:00:27 +02:00
alientim d2679361bc Version 2.4.0: eigene Rechtezeile fuer PDF-Formulare, Download ist Export 2026-09-10 00:08:21 +02:00
alientim 20c7fd8813 Version 2.3.3: weiter ausfuellbar oder abgeschlossen 2026-09-09 23:43:46 +02:00
alientim eaca6f7990 Version 2.3.2: Namen ohne Endung, lesbare Haken, hochkant mehr Hoehe 2026-09-09 23:35:42 +02:00
alientim 4eb1c0c2d8 Version 2.3.1: Formularfelder sitzen richtig, Bildfeld nutzbar 2026-09-09 23:11:49 +02:00
alientim c0a6dd057c Version 2.3.0: Speichern mit Ordner und Namen 2026-09-09 22:41:07 +02:00
alientim 8c2cd10ee4 Version 2.2.1: pdf.js unter .js -- .mjs kennt kein Webserver 2026-09-09 22:06:15 +02:00
alientim 2c3ca4acc1 Version 2.2.0: Vorschau mit Zoom und PDF-Formularen, eine Uploadgrenze 2026-09-09 21:48:05 +02:00
alientim f16ba7d875 Version 2.1.2: Wurzelinstanz auch an der Lizenz erkennen 2026-09-09 00:27:00 +02:00
alientim 7bfe328e4b Version 2.1.1: update.sh mit --yes, ohne Terminal kein stiller Ausstieg 2026-09-09 00:20:30 +02:00
alientim 5b9373bb24 release.sh nimmt den Namen des Repositoriums 2026-09-09 00:12:59 +02:00
alientim f77c8b221c Version 2.1.0 2026-09-09 00:10:39 +02:00
alientim 985deb7a24 README: vier Repositorien, zwei Ausgaben des Lizenzservers 2026-09-09 00:08:32 +02:00
alientim 258e90bf4f Rueckweg bei jedem Fehlschlag, install.sh oben im Paket, eigener Port je Instanz 2026-09-09 00:06:44 +02:00
alientimandClaude Opus 5 337a52cc38 sudoers ohne requiretty, und ein Rueckweg fuer fehlgeschlagene Upgrades
Auf einem frisch aufgesetzten Server brach das Upgrade mitten drin ab:

    /tmp/tmp.XXXX:8:24: syntax error: unknown setting: 'requiretty'
    visudo: invalid sudoers file
     !! sudoers-Datei ist fehlerhaft

"Defaults:<user> !requiretty" stand in beiden sudoers-Dateien. Auf Debian und
Ubuntu ist requiretty nie gesetzt -- die Zeile war von Anfang an wirkungslos --
und ab sudo 1.9.16 kennt visudo die Einstellung nicht mehr und lehnt die ganze
Datei ab. Sie ist entfernt; ein Hygienetest haelt fest, dass sie nicht
zurueckkommt, und prueft gleich mit, dass in diesen Dateien genau eine Regel
steht und die auf den Helfer zeigt.

Schlimmer als der Fehler war die Folge: der alte Dienst war zu diesem Zeitpunkt
gestoppt und deaktiviert, das Verzeichnis teils ersetzt, der neue Dienst nicht
vorhanden. upgbrade.sh faengt den Fehlschlag jetzt ab und dreht den Lauf
zurueck -- und mit "--rollback" auch spaeter noch, aus einer vorhandenen
Sicherung.

Dafuer muss die Sicherung mehr enthalten als das Verzeichnis. Bei einem Upgrade
in dasselbe Verzeichnis schreibt install.sh auch systemd-Unit, nginx-Site,
logrotate und Banner neu und ersetzt das venv; ohne Kopie davon liesse sich der
alte Stand nicht herstellen. Ein Manifest haelt Quelle und Art des Umzugs fest,
damit ein spaeterer Rueckweg nicht raten muss.

Beim Nachstellen des Fehlschlags fiel ein zweiter Fund auf, gefaehrlicher als
der erste: die Liste der "alten Units" war fest verdrahtet -- fuer --app tesm
immer tesm.service. Nach einem rename.sh heisst so aber die *laufende*
Installation. Wer die archivierte 1.x in eine eigene Instanz hochzieht und
--keep-old-running vergisst, haette damit den Produktionsdienst gestoppt und
deaktiviert. Die Units werden jetzt daran erkannt, dass sie in genau das
Quellverzeichnis zeigen; Timer und Hilfsdienste kommen ueber den Namen der so
gefundenen Unit mit.

Am System geprueft, nicht behauptet: Fehlschlag nachgestellt (1.2.8 mit eigener
Unit, eigener Site und erkennbarem venv), Rueckweg lief -- VERSION 1.2.8, das
alte venv und die alte Unit wieder da, die neue Struktur weg, die laufende
Produktion unberuehrt. Danach derselbe Lauf mit heiler sudoers-Datei bis zum
Ende (4 Clients, 2 Zugangsdaten, DHCP), und zuletzt "--rollback" als eigener
Aufruf auf dieselbe Installation.

Version 2.0.10.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 23:13:43 +02:00
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 3bbddd7d29 upgrade.sh findet die Fassung 1.x auch im Archiv
Nach einem Umbenennen liegt unter /srv/<app> die laufende Installation und die
Fassung 1.x unter /srv/<app>-sonnet5 -- dorthin verschiebt rename.sh sie. Die
Vorgabe von upgrade.sh zeigte danach auf die neue Installation und brach ab
(sauber, aber unbrauchbar). Gesucht wird jetzt an beiden Orten; erkannt wird
eine 1.x an der sqlite.db im Wurzelverzeichnis.

Den Weg selbst habe ich gegen die echten Altdaten geprueft, nicht behauptet:
aus /srv/tesm-sonnet5 (Version 1.2.8) kamen 4 Clients, 2 Zugangsdaten und die
DHCP-Konfiguration in eine Probeinstanz, aus /srv/tesm-license-sonnet5
(Version 1.2.7) 2 Kunden, 2 Tickets und 2 neu signierte Lizenzen samt
uebernommenem Signaturschluessel und Anbieterblock. Die laufenden
Installationen blieben unberuehrt, die Probeinstanzen sind abgeraeumt.

Zwei Tests halten die beiden Skripte zusammen: derselbe Namenszusatz, und die
Suche laeuft ueber die echten Zeilen aus upgrade.sh.

Version 2.0.8.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 14:53:36 +02:00
alientimandClaude Opus 5 7407f4bc00 Anmeldeseite: Wortmarke fuer beide, Karte ohne Wiederholung
* Die Wortmarke stand nur bei TESM -- sie hing an der Funktionszeile, und die
  hatte der Lizenzserver nicht. Jetzt zeigen beide die Marke; die Zeile
  darunter ist optional und beim Lizenzserver "LIZENZIEREN".
* Der Kartenkopf ist weg: eine Kachel mit zwei Buchstaben, die Ueberschrift
  "Anmelden" und der Anwendungsname darunter sagten dasselbe wie die Marke
  darueber und der Knopf darunter. Die Ueberschrift bleibt fuer die
  Titelzeile des Browsers.
* Marke und Karte stehen jetzt uebereinander im Fluss statt uebereinander
  gestapelt: auf einem flachen Fenster schnitt die Karte mitten durch den
  Schriftzug.
* Die Marke ist kuerzer und symmetrisch um die Mitte aufgebaut -- Schriftzug
  ueber text-anchor, Zacken spiegelbildlich, Linie links so lang wie der Punkt
  rechts. Volle Deckkraft, weil sie kein Wasserzeichen hinter der Karte mehr
  ist.
* Funktionszeile gekuerzt auf "UEBERWACHEN . BOOTEN . ANBINDEN" -- mit echtem
  Umlaut. "(PXE)" stand fuer etwas, das es noch nicht gibt.
* Der Farbverlauf im Hintergrund hat wieder Geometrie und Staerke der Fassung
  1.x. Der zweite Kreis lag auf --info und 10 %: ein kaltes Blau, das man auf
  dunklem Grund nicht sah und das nicht zur Marke gehoert.
* "Bitte melden Sie sich an." stand auf einer Seite aus Anmeldefeld,
  Passwortfeld und einem Knopf "Anmelden". Statt dessen erfaehrt jetzt der,
  dessen Sitzung gerade ablief, warum er wieder hier ist.

Dabei drei Dinge gefunden, die lautlos nichts taten:

* __version__ stand fest verdrahtet in drei __init__.py. Die Fusszeile zeigte
  vier Releases lang 2.0.2, waehrend die Anwendung 2.0.6 war. Die Nummer kommt
  jetzt aus den Metadaten des installierten Pakets; Quelle ist pyproject.toml.
* "gap: var(--sp-7)" -- die Skala kennt kein --sp-7 (1 bis 6, dann 8, 10, 12,
  16). Eine undefinierte Variable verwirft die ganze Deklaration ohne Meldung:
  der Abstand war "normal", und Marke und Karte stiessen auf den Pixel
  aneinander.
* Ein Test dagegen fand sofort ein zweites: --surface-0 wird dreimal benutzt
  und nirgends definiert. Die Schrift auf der Kachel "kritisch" blieb
  dunkelgrau auf Rot, die Dateivorschau hatte keinen Grund, und das Feld
  "Recht nicht vorhanden" in der Rechtematrix war durchsichtig -- also so hell
  wie die Karte, obwohl es dunkler sein sollte.

Version 2.0.7.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 14:44:32 +02:00
alientimandClaude Opus 5 635722089e rename.sh: aus einer Instanz die Hauptinstallation machen
Die laufenden Installationen hiessen "tesm-opus" und "tesm-license-opus" --
ein Instanzname aus der Zeit, in der sie neben der Fassung 1.x getestet wurden.
Jetzt heissen sie "tesm" und "tesm-license".

Umbenennen ist mehr als ein verschobenes Verzeichnis, und drei Stellen sind
leicht zu uebersehen:

* SITE_KEY in der Umgebungsdatei -- daraus entsteht der Name des
  Sitzungscookies. Bleibt er alt, heisst das Cookie weiter wie die alte
  Instanz: unauffaellig und falsch.
* web_cert_path/web_key_path/web_acme_webroot in der Datenbank enthalten den
  Namen. Ein Zertifikat unter dem alten Pfad findet nginx nicht mehr.
* server_name der nginx-Site. install.sh schreibt die Datei aus seiner Vorlage
  neu, sobald sich die alias-Pfade aendern -- und die aendern sich hier
  zwangslaeufig. Ohne den Namen aus der Datenbank stehen danach zwei Sites mit
  "server_name _" auf Port 80, und die erste gewinnt. web-setup braucht dafuer
  --apply; ohne ihn speichert es nur.

Zwei Fehler hat erst der Lauf am System gezeigt:

* Das venv wandert nicht mit. Seine Konsolenskripte tragen den absoluten Pfad
  im Shebang, und danach zeigt venv/bin/gunicorn auf einen Interpreter, den es
  nicht mehr gibt -- systemd meldet "No such file or directory" fuer eine
  Datei, die sichtbar da ist. Es wird jetzt verworfen und neu gebaut.
* Den Zielnamen belegt nicht nur /srv/<name>, sondern auch /var/log/<name>,
  der ACME-Pfad und die logrotate-Datei. Der Umzug brach mitten drin ab. Jetzt
  wandert alles, was den Namen belegt, in ein Archiv -- geloescht wird nichts,
  die Units und die Site der alten Fassung liegen darin unter systemd-alt/.

Ein Test vergleicht die Pfade, die install.sh unter dem Namen anlegt, mit
denen, die rename.sh kennt. Genau diese Luecke war der zweite Fehler; ohne den
Test faellt der naechste erst wieder auf einem Server auf.

Version 2.0.6.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 14:12:40 +02:00
alientimandClaude Opus 5 6dff1ed137 Banner: Einzahl, wo eines gemeint ist
"1 Clients online" liest man jeden Tag einmal zu oft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 12:48:32 +02:00
alientimandClaude Opus 5 b4529a0e31 Anmeldebanner wieder in Betrieb -- ohne die Anwendung zu starten
Das Banner der Vorgaengerfassung hing an /srv/tesm/motd_banner.py und
importierte dafuer die ganze Flask-Anwendung samt deren venv. Nach dem
Umstieg zeigte es damit die Zahlen einer Datenbank, die niemand mehr fuellt --
eingefroren, aber unverdaechtig. Aufgefallen ist es erst, als der alte
Ueberwachungsdienst abgeschaltet wurde.

deploy/tesm-motd loest das anders: **nur Standardbibliothek**, kein venv, kein
Import der Anwendung, die Datenbank wird nur lesend geoeffnet (mode=ro). Ein
Lauf dauert Millisekunden statt eines Flask-Starts. install.sh legt das Skript
nach /usr/local/lib/tesm/ und schreibt /etc/update-motd.d/50-<name>, abgesichert
mit "timeout 3" und "|| true" -- ein Banner darf eine Anmeldung nie blockieren.
Ein Banner der Vorgaengerfassung wird entfernt, aber nur, wenn es genau auf
motd_banner.py zeigt.

Damit es nicht zwei Wahrheiten ueber "online" gibt, steht die Zaehlung der
Statusuebersicht jetzt als Konstante DASHBOARD_COUNT_SQL in monitor.py; das
Banner traegt sie wortgleich, und ein Hygienetest vergleicht beide. Dasselbe
fuer die Zeile unter der Wortmarke. Ein weiterer Test verbietet dem Banner
jeden Import ausserhalb der Standardbibliothek -- genau dieser Import war die
Ursache.

Der Lizenzserver bekommt sein eigenes Banner (Kunden und ausgestellte
Lizenzen). Eine Tagline hat er bewusst nicht: die Funktionsliste von TESM waere
dort falsch, und eine erfundene waere schlimmer als keine.

Version 2.0.5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 12:44:21 +02:00
alientimandClaude Opus 5 313eb4bbf9 Leerlaufabmeldung: die zweite Schreibstelle und ein Tab, der das alte Skript faehrt
Die Abmeldung hat weiterhin nicht ausgeloest. Zwei Gruende, beide fuer sich
ausreichend:

* **save_session** schreibt ``idle_expires_at`` bei jeder Anfrage, die die
  Sitzung anfasst -- ein neu erzeugtes CSRF-Token genuegt. Die Pruefung in
  ``open_session`` lief damit ins Leere. Sitzungsdaten werden weiter
  gespeichert, nur die Fristen bleiben stehen. Dieselbe Stelle benutzte
  ausserdem ``idle_minutes`` statt der einstellbaren Zeit; bei der Vorgabe von
  dreissig Minuten fiel das nicht auf.
* **Der Kopf allein reicht nicht.** Er setzt voraus, dass der Browser das
  aktuelle Skript faehrt -- ein Tab, der seit gestern Abend offen ist, faehrt
  das alte und schickt ihn nicht. Genau dieser Tab ist der Fall, um den es
  geht. Der Server weiss es ohne Zutun des Browsers: die Endpunkte, die eine
  Kachel oder ein Protokoll nachlaedt, sind als Aktualisierungsausschnitt
  gekennzeichnet (``@fragment``) und gelten damit immer als automatisch.
  ``request.endpoint`` steht in ``open_session`` noch nicht -- Flask oeffnet
  die Sitzung vor dem Routing --, deshalb sieht die Erkennung dort selbst nach.

Dass es auf dem Lizenzserver zuverlaessig funktionierte, war der Hinweis: dort
pollt keine Kachel.

Dazu ein Kopf ``X-Session-Expired`` fuer Seiten, die auch oeffentlich
antworten. Die Statusuebersicht liefert nach dem Ablauf eine 200 mit den
oeffentlichen Kacheln -- am Status ist der Verlust der Sitzung also nicht zu
erkennen, und der offene Tab zeigte weiter eine Oberflaeche, als sei alles in
Ordnung. Jetzt laedt er neu und zeigt die Anmeldemaske.

Version 2.0.4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 12:21:36 +02:00
alientimandClaude Opus 5 51ae39dd53 Upgrade von 1.x, Leerlaufabmeldung, Mitschrift im Audit
upgrade.sh -- ein Weg vom Stand SONNET5 auf diese Fassung, mit Daten. Der
Ablauf braucht keine Schalter: alte Installation sichern, abschalten, neu
installieren, exportieren, uebersetzen, einspielen. Die Sicherung steht
bewusst vor dem Export -- ohne --instance installiert install.sh in dasselbe
Verzeichnis, und wer erst exportiert und dann sichert, sichert im
schlechtesten Fall nichts mehr. Gelesen wird nur aus der Kopie.

Dafuer zwei neue Befehle: "legacy-export" liest eine alte Installation
unmittelbar (der Vorgaenger kann nur ueber die Weboberflaeche exportieren --
fuer ein Upgrade der falsche Weg, und unmoeglich, wenn die alte Anwendung nicht
mehr startet) und schreibt eine Datei im alten Format, die deshalb auch als
Rueckweg taugt. "legacy-import" liest eine Datei im neuen Format ein, ueber
transfer.apply_import -- dieselbe Funktion wie die Seite "Sicherung", kein
zweiter Schreibpfad.

Am Lizenzserver hat der Lauf gegen echte Altdaten zwei Fehler gezeigt, die
jede Uebernahme unmoeglich machten:

* Der alte Signaturschluessel ist URL-sicher kodiert (- und _). Das neue
  Protokoll prueft Base64 streng -- richtig so, aber beim Lesen einer alten
  Datei brach die Uebernahme mit einem Traceback ueber "kein gueltiges Base64"
  ab. Umkodiert wird jetzt an der Grenze zum Altformat; der kanonische Decoder
  bleibt streng.
* Der Anbieterblock wurde aus den Einstellungen der *neuen* Installation
  gebaut, und ohne Endpunkt brach die Uebernahme ab. Bei einem Upgrade ist die
  neue Installation frisch -- dort steht nichts. Endpunkt und Anbieterdaten
  kommen jetzt aus der alten Installation, aber nur dort, wo neu nichts steht.
  Der alte Signaturschluessel wird uebernommen: sonst muesste jeder Kunde
  einen Ausstellerwechsel bestaetigen.

Leerlaufabmeldung: sie hat nie ausgeloest. Ein offener Tab fragt seine
Kacheln alle 15 Sekunden neu ab, und jede Abfrage verlaengerte das
Leerlauffenster -- nachweisbar an einer Sitzung, deren last_seen_at eine
Minute alt war, obwohl seit zehn Stunden niemand am Rechner sass. Der Client
kennzeichnet automatische Anfragen jetzt mit einem Kopf, der Server
verlaengert daraufhin nichts, und last_seen_at bleibt, was der Name sagt.
Faellt die Sitzung waehrend des Pollens, antwortet der Server mit 401 statt
mit einer Umleitung: der Tab laedt neu und zeigt die Anmeldemaske, statt
stumm mit alten Zahlen stehenzubleiben.

Im Audit ist der Name der Mitschrift jetzt ein Verweis auf die Datei -- es ist
derselbe Weg wie zuvor, nur einen Klick weit. Verlinkt wird nur, wenn die
Datei existiert und der Betrachter Protokolle lesen darf; der Rest des
Eintrags wird maskiert, denn ein Auditeintrag enthaelt Fremdeingaben.

Ausserdem: Version 2.0.3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 11:43:02 +02:00
alientimandClaude Opus 5 a8bd5763fb Aktualisierung: zwei Pruefungen, die nie zugegriffen haben
Der Lauf gegen die echte Installation hat zwei Fehler gezeigt, die den
Aktualisierungsweg fuer jede Version unbrauchbar machten:

* Die Suche nach install.sh im entpackten Paket lief mit "-maxdepth 2".
  release.sh packt mit dem Praefix "<name>/", das Skript liegt also drei
  Ebenen tief -- gefunden wurde nie etwas, und die Meldung schob es auf den
  Download ("Im Paket fehlt deploy/install.sh").
* Die CRLF-Pruefung rief "file" auf. Das Paket gehoert nicht zur
  Grundinstallation eines Servers; fehlt es, endete die Pipeline in "command
  not found", grep bekam nichts zu sehen, der if-Zweig wurde nicht betreten --
  und genau der Fehler, den die Pruefung abfangen soll, ging unbemerkt durch.
  Der Wagenruecklauf wird jetzt ohne Zusatzpaket gesucht, mit "-U": unter Linux
  ohne Wirkung, auf einer Windows-Buildmaschine entscheidend, weil grep dort
  den Wagenruecklauf beim Lesen entfernt.

Beide Pruefungen fuehren die echten Zeilen aus dem Skript aus -- die eine
gegen den Verzeichnisaufbau, den release.sh erzeugt, die andere gegen zwei
Dateien mit und ohne Wagenruecklauf.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 00:16:59 +02:00
alientimandClaude Opus 5 d6ba98782e Release-Pakete gehoeren nicht ins Repository
Der gebaute Tarball lag im Arbeitsbaum und wanderte in den Commit; das
naechste Paket enthielt daraufhin das vorige -- doppelte Groesse,
verschachtelter Inhalt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 00:12:05 +02:00
alientimandClaude Opus 5 47ab97a0ac Aktualisierungsweg gangbar machen
Drei Fehler, die erst beim Aktualisieren auffallen -- also genau dann, wenn
niemand sie sehen will:

* update.sh zeigte auf "gitea.example.invalid" und den Besitzer "wis". Auf
  keinem Host konnte das funktionieren, und die Doku erwaehnte die Variablen
  nicht, mit denen man es haette umlenken koennen. Die Vorgaben zeigen jetzt
  dorthin, wo die Releases liegen; das Repository heisst wie die Anwendung.
* update.sh gab nichts an install.sh weiter. Eine benannte Instanz war damit
  nicht aktualisierbar: ohne --instance entsteht neben "tesm-opus" eine
  zweite Installation namens "tesm", mit eigener Datenbank und eigener
  nginx-Site.
* install.sh setzte bei einer Instanz die Ports auf 8080/8443 zurueck, auch
  wenn sie seit der Installation auf Port 80 lief. Ein Reverse Proxy davor
  haette danach ins Leere gezeigt. Bestehende Ports werden jetzt aus
  Umgebungsdatei und nginx-Site uebernommen -- dieselbe Regel wie beim
  Secure-Flag: eine Aktualisierung nimmt nichts weg, was nicht ausdruecklich
  neu gesetzt wird.

Zwei Tests fuehren dazu die echten Zeilen aus den Skripten aus, statt sie
nachzubauen. Beide fallen ohne die Korrektur durch.

Ausserdem: die vier subprocess-Aufrufe im Textmodus nageln die Kodierung auf
UTF-8 fest. "text=True" allein nimmt die Locale des Prozesses -- unter systemd
haeufig C/ASCII --, und das Lesen bricht ab, sobald ein Werkzeug einen Umlaut
ausgibt. Der Fehler entstand im Leser-Thread von subprocess und damit weit weg
von seiner Ursache; im Testlauf war er als Warnung sichtbar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 00:11:21 +02:00
alientimandClaude Opus 5 fbbf8eb87b Umlaute in der Oberflaeche, Sitzungskopplung, Statusanzeigen
Echte Umlaute in allen Texten der Oberflaeche und in den Markdown-Dateien.
Die Einbindung von Dateifreigaben haengt jetzt an der Sitzung: wird sie
widerrufen oder laeuft sie ab, verschwinden die Freigaben mit ihr. Neu
einstellbar ist die automatische Abmeldung bei Leerlauf (Vorgabe 30 Minuten).
Ein Geraet, das nicht antwortet, bietet nur noch "Einschalten (PoE)" an --
Neustart ueber SSH oder RPC braucht ein erreichbares Geraet. Der Zeitgeber der
naechsten Pruefung und die Restlaufzeit der Lizenz stehen jetzt oben in der
Kopfzeile; der doppelte Knopf darunter ist weg. Millisekunden werden ab einer
Sekunde als Sekunden und ab einer Minute als m:ss dargestellt.

Ausserdem: Release-Tarball nicht mehr im Repository -- er haengt am Release.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 23:54:33 +02:00
alientimandClaude Opus 5 9a760274f8 Herkunft eines gepinnten Ausstellers in Klartext
In der Spalte "Quelle" stand das Kuerzel des Protokolls: "tofu". Das ist
Fachjargon (Trust On First Use) und als Wert in einer Tabelle unbrauchbar --
es sieht aus wie ein Tippfehler.

Jetzt: "Erstkontakt" (beim ersten Einspielen automatisch uebernommen) und
"Bestaetigt" (Ausstellerwechsel von einem Administrator freigegeben).

Die Uebersetzung liegt in tesm_core.ui als ISSUER_SOURCES mit zwei
Jinja-Filtern, nicht in zwei Vorlagen: der Lizenzserver zeigt dieselbe Angabe
unter "Eigene Lizenz", und zwei Texte fuer denselben Sachverhalt laufen
auseinander. Unbekannte Werte bleiben unveraendert sichtbar statt hinter einem
Platzhalter zu verschwinden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 22:26:42 +02:00
alientimandClaude Opus 5 cf16809ee2 Kurze Hostnamen in Freigaben aufloesen, Protokolle am Ende oeffnen
Freigaben mit kurzem Hostnamen (\S2025\Share) scheiterten mit "could not
resolve address for S2025". Ursache: dieser Server hat keine Suchdomaene
(search . in resolv.conf), ein Windows-Client hat eine. Der Name ist also
richtig, nur hier nicht auflösbar. Die AD-Domaene ist aus den Einstellungen
des Verzeichnisdienstes bekannt und wird jetzt zum Vervollstaendigen benutzt;
laesst sich der Name gar nicht aufloesen, sagt die Meldung was zu tun ist
statt "Unknown error". Auf POETEST gegen echtes DNS geprueft:
\S2025\LDAP_Share -> \S2025.ad.eertmoed.net\LDAP_Share, und dieser Pfad
bindet ein.

Protokollansichten standen beim Oeffnen oben. Die neueste Zeile steht aber
unten, und weil die Aktualisierung nur mitzieht, wenn man ohnehin am Ende ist,
zog sie danach nie mit -- es sah aus wie ein kaputter Autoscroll, war aber nur
die falsche Anfangsposition. Die Protokollansichten sind jetzt per data-tail
markiert und springen beim Laden nach unten. Konfigurationsvorschauen (nginx,
Kea) und der Offline-Code sind bewusst nicht markiert: die beginnen oben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 22:21:42 +02:00
alientimandClaude Opus 5 d8368fc200 Windows-Konto: ein Backslash im Hinweis, toleranter Split
Der Hinweistext empfahl "DOMAENE\benutzer" mit zwei Backslashes. Genau so
wurde es dann eingetragen -- und der einfache split() schickte daraufhin
"\benutzer" an Windows. Die Anmeldung scheiterte mit LOGON_FAILURE bei formal
richtigen Zugangsdaten, und die Meldung zeigte auf die falsche Ursache. Der
Fehler in der Anleitung wurde damit zum Fehler in den Daten.

Behoben an beiden Enden: der Hinweis nennt jetzt ausdruecklich *einen*
Backslash, und der Split fasst mehrfache Backslashes zusammen, damit ein
bereits falsch eingetragenes Konto trotzdem funktioniert.

Dazu Tests, die die Anmeldedatei pruefen statt nur den Code: ein Backslash,
zwei Backslashes, Konto ohne Domaene, und die beiden Hinweistexte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 22:03:32 +02:00
alientimandClaude Opus 5 e343aee026 Dateifeld sichtbar machen, RPC-Fehler verstaendlich melden
Der Knopf im Dateifeld kommt vom Browser und ignoriert jede Aussenfarbe: im
dunklen Thema ein hellgraues Kaestchen mit dunkler Schrift, kaum zu lesen und
passend zu nichts. Jetzt explizit wie ein Sekundaerknopf gestaltet -- einmal
zentral, denn es betrifft vier Felder (Sicherung, Lizenz, Profilbild,
Dateifreigaben).

Dazu zwei neue Hinweise fuer den Windows-Neustart. "Could not initialise pipe
winreg / NT_STATUS_OBJECT_NAME_NOT_FOUND" liest sich wie ein technisches
Detail, hat aber fast immer eine Ursache: das Konto ist auf dem Zielgeraet kein
Administrator. An einem echten Fall nachgemessen -- die Anmeldung gelang, aber
schon "net rpc info" und der Dienstmanager antworteten mit ACCESS_DENIED. Ein
Standardkonto bekommt die winreg-Pipe gar nicht zu sehen. Die Meldung sagt das
jetzt und nennt den Pruefbefehl.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 21:58:02 +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 64e25bb9ae Nur noch, was zum Installieren und Betreiben von TESM noetig ist
Entfernt: Tests, Architekturdokumentation und die Serverhaelfte des
Lizenzprotokolls. Beides liegt im Entwicklungsrepository alientim/TESM-DEV.

Das Lizenzprotokoll ist geteilt. TESM braucht nur die gemeinsame Haelfte
(tesm-licensing): Lizenzen verifizieren, Status bewerten, Anfragen stellen,
Antworten pruefen. Ausstellen, erneuern, Antworten signieren und
Schluesselerzeugung liegen jetzt in tesm-licensing-server und damit
ausschliesslich beim Lizenzserver -- ein Client soll den Code zum Ausstellen
nicht einmal mitbringen. Nachgeprueft: kein Modul von TESM oder tesm-core
importiert eine der verschobenen Funktionen.

install.sh installiert entsprechend je Anwendung nur die noetigen Pakete und
bricht mit klarer Meldung ab, wenn die verlangte Anwendung nicht im Baum liegt.

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