Files
checkbot/CLAUDE.md
T
patrickandClaude Sonnet 5.5 d2e2f829ad
test / pytest (3.11) (push) Waiting to run
test / pytest (3.13) (push) Waiting to run
feat: test base (logging with secret masking, timezone, Gitea workflow) and roadmap
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 01:24:24 +01:00

11 KiB

checkbot

Checkmk-Bot für Debian-LXC (Proxmox). Überwacht Checkmk per REST-API, lässt Alarme von externem Ollama analysieren, meldet in Telegram und/oder Element (Matrix). Konfiguration komplett über Web-UI.

Vollständiger Plan: /home/sysops/.claude/plans/ja-alle-bernehmen-eager-lark.md

Arbeitsregeln

  • Auf diesem Rechner wird nichts installiert (kein venv, kein pip, keine Pakete). Code nur schreiben, Ausführung und Tests passieren im Ziel-LXC.
  • Stand: Phase 1 bis 5 als Code, Phase 7 als Dateien geschrieben, nichts ausgeführt oder getestet (siehe README-Statustabelle).
  • Code-Kommentare nur bei echtem WHY.

Festgelegte Entscheidungen

  • Plattform: Debian-LXC, unprivileged, 1 Core, 1 GB RAM, Python 3, venv im LXC, systemd, Caddy (HTTPS, interne CA). Kein Docker.
  • Checkmk 2.3+: nur REST-API (Automation-User, Lese-Rolle). Kein Webhook, kein Notification-Script, kein eingehender Alarm-Port.
  • Poller: 30 s (UI einstellbar), nur Nicht-OK, Zustandsvergleich in SQLite, nur Hard-States, Mindestdauer einstellbar (Default 0 s), Flapping gebündelt.
  • Ollama extern office.sysops.de:11434. Zwei Modell-Einstellungen (Alarmtext, Agent), Start qwen3, Hermes zum Vergleich.
  • Chat: Adapter-Interface. Telegram (Long-Polling) und Matrix (direkt über die Client-Server-API mit httpx, bewusst nicht matrix-nio: kein libolm/E2EE nötig; eigener Homeserver, unverschlüsselter Raum, Bot-User mit Access-Token). Parallel, einzeln abschaltbar, Ziel pro Routing-Regel.
  • Alarm-Flow: Rohalarm sofort, KI-Analyse per Edit nachgereicht (Telegram editMessage, Matrix m.replace). Max 8 Zeilen DE. Timeout 60 s, 2 Retries, sonst "KI nicht verfügbar". Bündelung pro Host 60 s, max 10 Prompts/min, Recovery ohne KI. Downtime: kein Push, Verlauf "unterdrückt". UI-Stummschaltung mit Ablauf.
  • Befehle: gemeinsamer Handler, / in Telegram, ! in Matrix, Allowlist pro Backend.
  • Agent-Loop nur für /ask, /explain, Tiefenanalyse. 5 feste Lese-Tools (get_service_status, get_host_services, get_state_history, get_downtimes, get_problems), max 6 Schritte, 90 s, Tool-Output untrusted, alle Aufrufe im Audit-Log.
  • Bot liest Checkmk standardmäßig nur (Automation-User mit Lese-Rolle). Einzige Schreibaktion: Downtime setzen, siehe nächster Punkt.
  • Ruhigstellen per Chat (/mute und /downtime in Telegram, !mute und !downtime in Matrix):
    • A, mute: Bot-lokale Stummschaltung mit Dauer, Checkmk bleibt unberührt. Standard. Alarme bieten Buttons "2 h stumm" (Telegram Inline-Buttons, Matrix: !mute 2h als Antwort auf die Alarmnachricht).
    • B, downtime: echte Checkmk-Downtime per REST (POST /domain-types/downtime/collections/service, Endpunkt noch gegen echte Instanz prüfen). Eigener Checkmk-User nur mit Downtime-Recht, Secret getrennt vom Lese-User. In der UI abschaltbar, standardmäßig aus, maximale Dauer einstellbar (z.B. 24 h).
    • B nur durch Allowlist-User nach Bestätigung (Host, Service, Dauer, Kommentar anzeigen, dann Button bzw. ja). Agent und Modell haben keine Schreib-Tools und lösen B nie aus.
    • Jede Aktion im Audit-Log: User, Backend, Host, Service, Dauer.
  • UI: FastAPI, Jinja2, HTMX, deutsch, hell/dunkel. Lokale Nutzer (Argon2, optional TOTP), Rollen admin/viewer, checkbot create-admin, Setup-Assistent.
  • Secrets in SQLite mit AES-GCM. Nur master.key, Session-Secret, Bind-Adresse in /etc/checkbot/ (chmod 600). UI zeigt Secrets nie an.
  • Audit-Log ohne Secret-Werte. Prompts versioniert mit Rollback, Testbereich.
  • Retention: Verlauf/KI 90 Tage, Audit 1 Jahr. /health plus Checkmk-Agent im LXC.
  • Plugin-Output ist untrusted Input (Prompt Injection), KI löst keine Aktionen aus.

Phasen

  1. Gerüst: Schema, crypto.py, Checkmk- und Ollama-Client, /health
  2. UI-Basis: Login, Rollen, Setup-Assistent, Verbindungstests, Audit
  3. Chat-Interface, Telegram, Poller, Alarm-Flow
  4. Matrix-Adapter, Routing, Stummschaltung (UI)
  5. Command-Handler (inkl. mute, downtime mit Bestätigung), Agent-Loop
  6. Prompt-Versionierung, Testbereich, Verlauf, Retention
  7. Deployment (setup-lxc.sh, Caddy, systemd, Checkmk-Agent)
  8. Tests

Geplante Struktur

app/ main.py fileconfig.py db.py models.py crypto.py checkmk.py poller.py
     ollama.py pipeline.py agent.py tools.py commands.py audit.py
     retention.py health.py chat/{base,telegram,matrix}.py web/
deploy/ setup-lxc.sh systemd/checkbot.service Caddyfile
tests/

Fortschritt Phase 5b (ungetestet)

  • Neu: app/listeners/ (Telegram-getUpdates, Matrix-/sync, Backoff, Offset/Since in Tabelle listener_state), app/downtime/ (Client, Bestätigungs-Store, Service), app/agent_runs/ (Recorder, Tabelle agent_runs, AgentService), app/commands/{mutecmd,downtimecmd,callbacks,...}, app/alerts/extras.py (Buttons/Hinweis), app/chatops.py (Verdrahtung), UI /agent und Section checkmk_dt.
  • Annahmen Telegram: getUpdates mit allowed_updates=[message, callback_query], Long-Poll 30 s; erster Start überspringt den Rückstand per offset=-1; editMessageText ohne reply_markup würde die Buttons entfernen, daher wird es beim Edit mitgegeben; callback_data max. 64 Byte (mute:<alert_id>:<min>, deep:<id>, dt:<id>:<min>, dty:<token>, dtn:<token>).
  • Annahmen Matrix: /sync mit Filter (nur Raum, nur m.room.message); next_batch wird vor der Verarbeitung gespeichert (höchstens einmal); Edits (m.replace) und m.notice werden ignoriert; Reply per m.relates_to.m.in_reply_to.
  • Annahmen Checkmk: POST /domain-types/downtime/collections/service mit downtime_type=service, host_name, service_descriptions, start_time/end_time (ISO 8601 UTC, Z), comment; Erfolg ist 204. Noch gegen eine echte Instanz prüfen.
  • Alarm-Buttons nur bei Einzelalarmen (nicht Recovery, nicht gebündelt); Reply-Auflösung bei mehreren Services in einer Nachricht lehnt ab und nennt die explizite Form.

Phase 7 Deployment (Dateien unter deploy/, ungetestet, Details in deploy/README.md)

  • Genau ein uvicorn-Worker: Rate-Limiter, TOTP-Einrichtung und Downtime-Bestätigungen liegen im Prozessspeicher, außerdem liefe der Poller doppelt. Bind-Adresse und Port kommen aus checkbot.env (Unit nutzt ${CHECKBOT_BIND_*}), Caddy-Upstream wird daraus gerendert.
  • Caddy-Modi: internal (Caddy-CA, Root-Zertifikat muss verteilt werden) oder files (Zertifikat der Unternehmens-CA nach /etc/caddy/certs). Zugriffslog ohne Query, Authorization, Cookie.
  • /health über Caddy nur von 127.0.0.1 und CHECKBOT_MONITOR_IP (Detailtexte intern), sonst 403. /health liefert 503, solange ein Teilcheck nicht ok ist, auch bei "nicht konfiguriert".
  • Local Check: "nicht konfiguriert" ergibt WARN, "deaktiviert" (Telegram/Matrix fehlen im JSON) OK, Fehler/Bot nicht erreichbar CRIT.
  • master.key wird nie mit der DB gesichert. Schlüssel erzeugt setup-lxc.sh als root und übergibt sie an checkbot (das Konfigurationsverzeichnis ist für checkbot nur lesbar).
  • Unprivilegierte LXCs: Drop-In checkbot-lxc-relaxed.conf (setup-lxc.sh --lxc-relaxed).

Weiterer Weg (entschieden)

Reihenfolge: Testbasis, erster Lauf im Test-LXC (pytest), Korrekturrunde, Phase 6, Phase 6b, Phase 6c, Phase 8, Abnahme, Parallelbetrieb, Tag v0.1.0. Verfeinerungen passieren am Live-System, nicht vorab.

  • Testbasis: pytest manuell im Test-LXC (Dev-venv mit requirements-dev.txt), dazu .gitea/workflows/test.yml für einen späteren Gitea-Actions-Runner. Logging als Zeilenlog nach journald, Level über CHECKBOT_LOG_LEVEL (Default INFO), nie Secrets in Logs (Test für die Adapter). Zeitzone über CHECKBOT_TZ im Setup-Skript, Default Europe/Berlin.
  • Phase 6: Alarm- und Agenten-Prompt versioniert mit Rollback und Testbereich; der Schutzhinweis gegen Prompt Injection wird immer fest angehängt und ist nicht editierbar. Retention einstellbar: Alarmverlauf/Zustellungen 90 Tage, Agenten-Läufe 90 Tage, state_log 30 Tage, Audit 1 Jahr, abgelaufene Mutes 7 Tage, tägliches Aufräumen mit Log der gelöschten Zeilen. Erinnerungen für offene CRIT-Probleme, Standard aus, nicht bei Downtime/Mute.
  • Phase 6b (Trigger-Regeln, Routing-Seite wird "Regeln"): Zusatzfelder pro Regel: KI-Hinweistext (nur Zusatzkontext hinter dem festen Schutzhinweis), KI an/aus, Erinnerungsintervall (nur CRIT), laut/leise (Telegram disable_notification). Zusatzbedingungen: Plugin-Output enthält Text (Teilstring, keine Regex wegen ReDoS) und Mindestdauer in Minuten. Keine Checkmk-Labels/Tags. Beispiel: Service *zpool*, ab WARN, eigener Raum, eigener KI-Hinweis.
  • Phase 6c (Betriebsrobustheit, nach 6b, vor 8):
    • Baseline beim Erstlauf: Zustand still merken, eine Zusammenfassung ohne KI (Anzahl, 10 kritischste); Button in der UI setzt die Baseline neu.
    • Bestätigte Probleme (Acknowledged in Checkmk) werden mit Grund "bestätigt" unterdrückt, bei Verschlechterung wieder gemeldet. Regel für alle Unterdrückungen: Recovery nur, wenn das Problem vorher gemeldet wurde.
    • Host-Alarme: Hosts mitabfragen, "Host DOWN" als eigener Alarm, Service-Alarme des Hosts mit Grund "Host down" unterdrücken, Recovery bei Rückkehr.
    • Checkmk nicht erreichbar: nach 3 Fehlzyklen eine Meldung "Checkmk nicht erreichbar seit HH:MM" an die Standardziele, bei Rückkehr eine zweite; währenddessen keine Recoveries.
    • Sendelimit 15 Nachrichten pro Minute und Ziel, Überschuss als Sammelmeldung pro Minute, alles bleibt im Verlauf.
    • Datenschutz pro Ziel: Inhalt voll oder kurz (nur Host, Service, Status, ohne Plugin-Output und KI-Text), Standard voll, Entscheidung am Live-System.
    • Optionale ui.base_url: Alarme enthalten Link "Details" auf den Verlauf (Telegram-Button, Matrix-Text), nur wenn gesetzt.
  • Aktionen: Der Bot führt nie Shell-Befehle aus (weder lokal noch per SSH). Webhook pro Regel (POST JSON an Allowlist-URLs, Audit) kommt erst nach der Abnahme.
  • Phase 8: Integrationstests mit Marker integration (pytest -m integration), Zugangsdaten per Umgebung, nur lesend; Downtime nur mit ausdrücklichem Flag und gegen einen Testhost. Testhost checkbot-test in Checkmk mit schaltbarem lokalem Check plus halbautomatisches tests/e2e/run.py.
  • Abnahme (docs/ACCEPTANCE.md): CRIT in Telegram und Element, KI-Analyse binnen 90 s, Recovery ohne KI, Downtime und mute unterdrücken, Ollama aus ergibt Rohalarm mit "KI nicht verfügbar", Neustart ohne Doppelalarme, Backup und Restore real getestet, /health im Checkmk grün, Baseline-Zusammenfassung beim Erstlauf, Host-down unterdrückt Service-Alarme, Meldung bei Checkmk-Ausfall, 24 h Dauerlauf ohne Fehler im Journal.
  • Einführung: erste Woche nur Testziele (separate Gruppe/Raum) per Routing-Regel, danach auf Produktivziele umschalten. Release: Tag v0.1.0 und kurze CHANGELOG.md.
  • Bewusst nicht enthalten: Ack, mehrere Checkmk-Sites, weitere Kanäle (Mail/Slack), E2EE in Matrix.