Compare commits

..
2 Commits
Author SHA1 Message Date
alientimandClaude Sonnet 5 c7ad0d3d49 KRITISCH: install.sh loeschte license.json bei jedem Update (v1.2.3)
Live auf POETEST reproduziert: rsync --delete im App-Verzeichnis-Schritt
schliesst venv/sqlite.db/fernet.key/secret.key/known_hosts explizit aus,
vergisst dabei aber license.json (in Phase 1 neu hinzugekommen, als
Ausschluss schlicht uebersehen). Da license.json nur auf dem Zielsystem
existiert (nie im Release-Paket enthalten, korrekt .gitignored), loescht
--delete sie bei JEDEM 'sudo ./update.sh' auf einer bereits aktivierten
Instanz kommentarlos mit -- die Lizenz war danach weg, ohne dass update.sh
oder install.sh irgendeinen Fehler gemeldet haetten.

Der Master-seitige Installer (install.sh im tesm-license-Repo) hatte
diesen Ausschluss von Anfang an korrekt gesetzt -- betraf ausschliesslich
TESM-Kundeninstanzen.

Fix: license.json zur rsync --exclude-Liste hinzugefuegt, analog zu den
anderen laufzeit-generierten Secrets.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 11:08:02 +02:00
alientimandClaude Sonnet 5 f09aaae8a9 Lizenz: sofortiger erster Heartbeat direkt nach Aktivierung (v1.2.2)
Root Cause fuer 'Letzter Heartbeat: noch nie' trotz funktionierender
Verbindung (live auf POETEST untersucht und bestaetigt): der Heartbeat-
Hintergrund-Thread feuert einmal SOFORT beim Start von tesm.service und
danach erst wieder alle 6h. Im realistischen Ablauf (Dienst starten ->
danach erst Lizenz hochladen+aktivieren) faellt genau dieser erste,
sofortige Versuch immer ins Leere (noch keine Lizenz vorhanden, daher
stiller Abbruch ohne Fehlermeldung) -- der naechste ECHTE Versuch waere
erst bis zu 6h spaeter gekommen. Manuell nachgestellt: ein direkter Aufruf
von _send_heartbeat() nach erfolgter Aktivierung funktioniert einwandfrei
(Master verzeichnet den Heartbeat sofort) -- das Protokoll selbst war nie
kaputt, nur die Beobachtbarkeit unmittelbar nach der Aktivierung.

Fix: beide Aktivierungs-Erfolgspfade (online + Offline-Code-Bestaetigung)
loesen jetzt selbst sofort einen ersten Heartbeat aus, statt auf den
naechsten planmaessigen 6h-Durchlauf zu warten. Ein Fehlschlag hier (z.B.
Kunde tatsaechlich offline) wird wie jeder andere Heartbeat-Fehlschlag
behandelt -- rein informativ, schaltet nichts ab.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 11:00:15 +02:00
3 changed files with 26 additions and 2 deletions
+1 -1
View File
@@ -134,7 +134,7 @@ sudo chmod 755 /var/log/tesm
step "Deploying application to /srv/tesm" step "Deploying application to /srv/tesm"
sudo mkdir -p /srv/tesm sudo mkdir -p /srv/tesm
sudo rsync -a --delete --exclude 'venv' --exclude 'sqlite.db' --exclude 'fernet.key' --exclude 'secret.key' \ sudo rsync -a --delete --exclude 'venv' --exclude 'sqlite.db' --exclude 'fernet.key' --exclude 'secret.key' \
--exclude 'known_hosts' \ --exclude 'known_hosts' --exclude 'license.json' \
"$REPO_DIR/srv/tesm/" /srv/tesm/ >>/var/log/tesm-install.log 2>&1 "$REPO_DIR/srv/tesm/" /srv/tesm/ >>/var/log/tesm-install.log 2>&1
print_status "Application files copied" print_status "Application files copied"
+1 -1
View File
@@ -1 +1 @@
1.2.1 1.2.3
+24
View File
@@ -4595,6 +4595,18 @@ def license_activate():
def on_success(): def on_success():
set_setting("license_activation_status", "active") set_setting("license_activation_status", "active")
set_setting("license_export_grace", "") set_setting("license_export_grace", "")
# Sofort einen ersten Heartbeat auslösen, statt bis zu 6h auf den
# nächsten planmäßigen Durchlauf zu warten (siehe
# _license_heartbeat_loop) -- ohne das würde "Letzter Heartbeat"
# direkt nach der Aktivierung fälschlich wie ein Verbindungsproblem
# aussehen ("noch nie"), obwohl schlicht noch keine Zeit vergangen
# ist. Ein Fehlschlag hier (z.B. Kunde offline) wird wie jeder
# andere Heartbeat-Fehlschlag behandelt (nur vermerkt, nichts wird
# deswegen abgeschaltet).
try:
_send_heartbeat()
except Exception:
app.logger.error("Erster Heartbeat nach Aktivierung fehlgeschlagen:\n%s", traceback.format_exc())
return _license_handshake("activate", "/api/activate", on_success, "license.activated", "Lizenz erfolgreich aktiviert.") return _license_handshake("activate", "/api/activate", on_success, "license.activated", "Lizenz erfolgreich aktiviert.")
@@ -4609,6 +4621,18 @@ def license_activate_confirm():
def on_success(): def on_success():
set_setting("license_activation_status", "active") set_setting("license_activation_status", "active")
set_setting("license_export_grace", "") set_setting("license_export_grace", "")
# Sofort einen ersten Heartbeat auslösen, statt bis zu 6h auf den
# nächsten planmäßigen Durchlauf zu warten (siehe
# _license_heartbeat_loop) -- ohne das würde "Letzter Heartbeat"
# direkt nach der Aktivierung fälschlich wie ein Verbindungsproblem
# aussehen ("noch nie"), obwohl schlicht noch keine Zeit vergangen
# ist. Ein Fehlschlag hier (z.B. Kunde offline) wird wie jeder
# andere Heartbeat-Fehlschlag behandelt (nur vermerkt, nichts wird
# deswegen abgeschaltet).
try:
_send_heartbeat()
except Exception:
app.logger.error("Erster Heartbeat nach Aktivierung fehlgeschlagen:\n%s", traceback.format_exc())
return _license_handshake_confirm("activate", on_success, "license.activated", "Lizenz erfolgreich aktiviert.") return _license_handshake_confirm("activate", on_success, "license.activated", "Lizenz erfolgreich aktiviert.")