#!/usr/bin/env python3 """Pull recent Falco alerts from netdata and write them as a Dashy custom-list JSON file, so the homelab dashboard shows a live feed of security events without needing Falcosidekick/Redis/a new UI. Run periodically via cron (see repo README/crontab entry). Reads from netdata's existing alert-transitions API - the same data already driving the Telegram pipeline - so this adds zero new attack surface or dependencies. """ import json import time import urllib.request NETDATA_URL = "http://192.168.1.67:19999" OUTPUT_PATH = "/srv/dashy/json-data/falco-alerts.json" LOOKBACK_SECONDS = 7 * 86400 # 7 days MAX_ENTRIES = 20 def fetch_transitions(): now = int(time.time()) after = now - LOOKBACK_SECONDS url = ( f"{NETDATA_URL}/api/v2/alert_transitions" f"?after={after}&before={now}&last=500" ) with urllib.request.urlopen(url, timeout=10) as resp: return json.load(resp).get("transitions", []) def to_dashy_entry(t): rule_name = t["summary"].removeprefix("Falco rule fired - ") status = t["new"]["status"] return { "link": { "text": "View", "url": f"{NETDATA_URL}/", "title": f"{status}: {rule_name}", }, "value": { "text": f"{status} - {rule_name}", "title": "Falco", }, "date": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(t["when"])), } def main(): transitions = fetch_transitions() raised = [ t for t in transitions if t.get("alert") == "falco_rule_match" and t.get("new", {}).get("status") in ("WARNING", "CRITICAL") ] raised.sort(key=lambda t: t["when"], reverse=True) entries = [to_dashy_entry(t) for t in raised[:MAX_ENTRIES]] with open(OUTPUT_PATH, "w") as f: json.dump(entries, f, indent=2) if __name__ == "__main__": main()