Add read-only web dashboard and phone push notifications
Both zero-dependency (stdlib http.server + urllib), consistent with the project's no-dependency-tree stance for a security daemon. Web dashboard (enodia_sentinel/web.py + static/dashboard.html): - read-only JSON API over the log dir: /api/status, /api/alerts, /api/alerts/<id>, /api/events - bearer-token auth (constant-time; header or ?token=), required on non- loopback binds, auto-generated + persisted (0600) when unset - binds the host's Tailscale IP by default (auto-detected), reachable from the tailnet but not the LAN/internet - self-contained dark SPA: severity cards, live alert list, full snapshot viewer; 10s auto-refresh - path-traversal-safe alert lookup; `enodia-sentinel web` subcommand; daemon now writes a pidfile so the dashboard can show live status - hardened enodia-sentinel-web.service (read-only, no caps) Phone push (enodia_sentinel/notify/): - pluggable backends — ntfy, Pushover, generic webhook — each separating a pure build() (unit-tested, no network) from send() - a backend turns on when its config keys are set; pushes gated by notify_min_severity; severity → per-service priority/tags - fired from snapshot.capture on worker threads, errors swallowed - desktop notify-send retained Tests: +16 (9 web incl. a real-server 401/200 auth test, 7 notify request-build cases). 55/55 pass. Live end-to-end verified: daemon → alert → API → page. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0eb5077551
commit
c00fff224c
17 changed files with 960 additions and 5 deletions
|
|
@ -63,6 +63,34 @@ capture_execve_bpftrace = false
|
|||
max_snapshots = 300 # auto-delete oldest beyond this count (0 = no cap)
|
||||
max_snapshot_age_days = 60 # auto-delete older than this (0 = no age cap)
|
||||
|
||||
# --- notifications -------------------------------------------------------
|
||||
# --- notifications: desktop ---------------------------------------------
|
||||
notify_users = [] # e.g. ["luna"] — desktop notify-send on alert
|
||||
notify_urgency = "critical" # low / normal / critical
|
||||
|
||||
# --- notifications: phone push ------------------------------------------
|
||||
# A backend turns on when its required keys are set. Only alerts at or above
|
||||
# notify_min_severity are pushed.
|
||||
notify_min_severity = "HIGH" # MEDIUM / HIGH / CRITICAL
|
||||
|
||||
# ntfy (open-source, self-hostable). Install the ntfy app and subscribe to the
|
||||
# topic; keep the topic name secret — it is the only access control on ntfy.sh.
|
||||
notify_ntfy_url = "" # e.g. "https://ntfy.sh" or your own server
|
||||
notify_ntfy_topic = "" # e.g. "enodia-<random>"
|
||||
notify_ntfy_token = "" # optional Bearer token (protected topics)
|
||||
|
||||
# Pushover
|
||||
notify_pushover_token = "" # application token
|
||||
notify_pushover_user = "" # user/group key
|
||||
|
||||
# Generic webhook — receives the alert JSON via POST (Discord/Slack/your own).
|
||||
notify_webhook_url = ""
|
||||
|
||||
# Optional dashboard base URL embedded in pushes (e.g. your Tailscale URL).
|
||||
dashboard_url = ""
|
||||
|
||||
# --- web dashboard (read-only) ------------------------------------------
|
||||
web_bind = "" # "" = auto-detect Tailscale IP; or an explicit address
|
||||
web_port = 8787
|
||||
web_token = "" # bearer token; auto-generated + saved if empty on a
|
||||
# non-loopback bind. Set explicitly to keep the unit
|
||||
# fully read-only.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue