Logbuch#homeos#security#audit#docker#smart-home
Prod lief auf Mock-Geräten
Von Niclas Hennrich · veröffentlicht · geschehen am
Etwas ist ausgefallen oder kaputtgegangen. Gehört zum Vorhaben HomeOS — Control Center mit drei Säulen.
- Gelöschte Mock-Ereignisse
- 1160
- Echte Shellys in Prod (vorher nur Mock)
- 5
- Empfehlungen warm (vorher 442 ms)
- 17ms
HomeOS ist mein selbst gebautes Control Center fürs Homelab — aus dem Infrastruktur-NOC erwachsen, mit drei Säulen: Infrastruktur, Haus (Smart Home) und Family/Haushalt. Die Haus-Säule spricht mit ein paar Shellys, kleinen WLAN-Schaltaktoren mit Leistungsmessung.
Was ich wollte: einen zweiten Audit-Lauf, diesmal mit Security-Schwerpunkt — Auth-Flächen, API-Eingaben, Secrets, Dependencies, Docker-Hardening, die IoT-Integrationen — plus eine Effizienz-Runde über den Food-Code der Tage zuvor. Vier parallele, rein lesende Reviews, dazu eine Live-Baseline auf optimus: Latenzen per curl, Datenbank-Schreiblast über 60 Sekunden, docker stats. Rund 35 Findings, 28 davon direkt behoben.
Der größte Fund kam aus keinem Review. Er kam aus einer Logzeile der Baseline:
Poller für mock gestartetDie Haus-Säule lief in Produktion seit dem Deploy am Vortag komplett auf dem
Mock-Adapter. Alle Geräte, die Energie-Seite, sämtliche Zeitreihen:
erfundene Daten. Die echten Shellys hatte ich validiert — aber nur aus der
Dev-Umgebung heraus. In Prod fehlten die Werte in der .env, und der
Compose-Default sprang ein: mock.
Die Ursache ist unbequem, weil sie dokumentiert war. Der Handgriff stand
in der STATUS-Datei und in der Beispiel-Env: „Ohne diese Werte fällt das
Modul auf den Mock-Adapter zurück." Beim Deploy hat ihn niemand ausgeführt,
und nichts hat ihn erzwungen. Für eine andere Variable hatte ich das längst:
Compose bricht mit ${VAR:?} den Start ab, wenn sie fehlt. Für den Adapter
nicht. Dieselbe Fehlerklasse wie beim Mealie-Token und bei der
ARP-Tabelle: Ein
Kommentar ist kein Zustand.
Die Bereinigung: Vorab-Dump der Datenbank, dann Adapter auf shelly
und die Adressen der fünf Geräte in die Prod-Env, Mock-Integration samt
Geräten und Zuständen kaskadiert gelöscht, 1160 Mock-Ereignisse entfernt,
die HomeOS-Serien im Zeitreihen-Speicher gelöscht, damit der nächste Scrape
nur noch echte schreibt. Ergebnis: 5/5 Shellys online, reale
Leistungswerte (in Summe rund 444 W) in Datenbank und Zeitreihen. Prod
zeigt zum ersten Mal echte Hausdaten.
Was sonst passiert ist, im Schnelldurchlauf: Korrektheits-Fixes im Food-Code (eine Division durch null bei 100 % Rabatt, Eingabegrenzen, ein Größenlimit beim ICS-Abruf), Datenbank-Härtung mit Dedupe-Index und fehlenden FK-Indizes, Container-Hardening, ein Lockfile für die Python-Dependencies, ein Empfehlungs-Cache. Der brachte die Empfehlungen von 442 ms je Poll auf 16–18 ms warm — der Kaltstart kostet mit 651 ms allerdings mehr als vorher. Und die Datenbank-Schreiblast stieg von 71 auf 106 Commits pro Minute. Das ist keine Regression, sondern ehrlich benannt: Prod tut jetzt echte Arbeit, 28 statt 10 Entitäten im Poll. Tests von 1207 auf 1223.
Was ich mitnehme:
- Eine Baseline-Messung schlägt vier Code-Reviews. Der kritischste Befund stand in keinem File-Diff. Er fiel auf, weil eine Logzeile nicht zur dokumentierten Wirklichkeit passte.
- Ein dokumentierter Handgriff ohne Zwang geht verloren. Was beim Deploy nicht erzwungen wird, passiert nicht. Die Doku war korrekt und hat trotzdem nichts verhindert.
- Ein Cache braucht vier Antworten: Source of Truth, TTL, Invalidierung, Fallback. Mit einem Versionszähler ist die Invalidierung vollständig, ohne jeden Endpunkt einzeln zu verdrahten.
- Tests, die den HTTP-Client mocken, zementieren den Client. Der
Wechsel von
getaufstreamkostete drei Tests. Der Mock gehört an die Grenze — den Transport —, nicht an die Funktion. - Range-Pins sind keine Reproduzierbarkeit. Erst das Lock aus dem validierten Prod-Stand macht einen Build deterministisch; vorher zog jeder Build rund 40 ungeprüfte transitive Neuerscheinungen.