main
9
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b9342d384c |
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>
|
||
|
|
f062314a0a |
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> |
||
|
|
3295583591 |
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> |
||
|
|
47aeaba9c8 |
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> |
||
|
|
05885bfff1 |
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> |
||
|
|
168d10bf87 |
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> |
||
|
|
2dea198bcc |
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> |
||
|
|
ab5fda658e |
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> |
||
|
|
f7805a2180 |
TESM-Lizenzserver 2.0.0 -- Neubau
Vollstaendiger Neubau der Anwendung. Der vorherige Stand bleibt unveraendert im Zweig SONNET5 erhalten. Aufbau: apps/tesm-license (Anwendung), packages/tesm-core (gemeinsamer Kern), packages/tesm-licensing (Lizenzprotokoll), deploy (Installation, systemd, privilegierter Helfer), docs, tests. Die verwaltete Anwendung liegt in ihrem eigenen Repository; beide Repositorien bringen die gemeinsamen Pakete mit, damit sich jedes allein installieren laesst. Die wichtigsten Unterschiede zum Vorgaenger: * Keine doppelte licensing.py -- ein Paket, das beide Anwendungen installieren, statt zweier Dateien, die byte-identisch bleiben sollen. * 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. * Keine Lizenz ohne master_endpoint: eine Ausstellung ohne Endpunkt wird abgelehnt statt eine Lizenz zu erzeugen, die sich nie aktivieren kann. * Offline-Aktivierung in beide Richtungen; die Lizenz bleibt als "Aktivierung offen" markiert, bis sie zurueckkommt. * Getrennte Signaturkontexte je Nachrichtenart, Nonce gegen Wiedereinspielung, seq gegen das Zurueckrollen auf eine aeltere Lizenz. * Kein Hostname im Maschinen-Fingerabdruck. * Verschachtelte Datenbankverbindungen sind ein Fehler, kein Deadlock. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |