Episode 16: Kuma alerts sorted by rules, a local agent and a script

ops-readonly gets kuma_alerts (host export kuma-export.py, one more read-only
mount). kuma-triage.py sorts the same data without a model. Flow H runs the
agent with skill alert-triage.md. Flow B: one open incident per monitor, an
UP closes all of them, titles name start and end and stay under Outline's
limit. B and D accept Kuma only with a header token. Monitoring notes: ntfy
rejects Kuma messages for monitors without a URL, resend for long outages.
This commit is contained in:
Maximilian Grimm 2026-09-29 22:14:50 +02:00
parent 54ab43dac7
commit 1655d04d7d
10 changed files with 705 additions and 67 deletions

View file

@ -10,6 +10,9 @@ questions, each answered by a few lines of code over three read-only mounts.
/run/fail2ban fail2ban's control socket (status queries only)
/waf WAF alerts as JSON, written by waf-export.py on the
host (episode 14); cscli and its credentials stay there
/kuma Uptime Kuma state per monitor as JSON, written by
kuma-export.py on the host (episode 16); the Kuma
database stays there
No docker socket, no write access, no free-form arguments. An action name that
is not in ACTIONS is refused, an argument outside its range is refused, and
@ -280,6 +283,18 @@ def waf_rule_info(rule_id):
return dict(rule, id=rule_id, known=True)
# ---------------------------------------------------------------- Kuma --
# Episode 16. Monitor names and messages (which quote the monitored page) are
# written by whoever controls the monitor or the page. Served as exported.
KUMA_DIR = os.environ.get("KUMA_DIR", "/kuma")
def kuma_alerts():
with open(os.path.join(KUMA_DIR, "alerts.json"), "rb") as fh:
return json.load(fh)
# ---------------------------------------------------------------- the list --
def arg_n(q):
@ -313,6 +328,7 @@ ACTIONS = {
"caddy_top_ips": lambda q: caddy_top_ips(arg_n(q)),
"waf_blocked": lambda q: waf_blocked(arg_hours(q)),
"waf_rule_info": lambda q: waf_rule_info(q.get("id", [""])[0]),
"kuma_alerts": lambda q: kuma_alerts(),
}