import json import logging from datetime import datetime, timezone from fastapi import APIRouter, Depends, Header, HTTPException, Request from starlette.responses import Response from onguard24.domain.entities import Alert, Severity logger = logging.getLogger(__name__) router = APIRouter(tags=["ingress"]) async def get_pool(request: Request): return getattr(request.app.state, "pool", None) @router.post("/ingress/grafana", status_code=202) async def grafana_webhook( request: Request, pool=Depends(get_pool), x_onguard_secret: str | None = Header(default=None, alias="X-OnGuard-Secret"), ): settings = request.app.state.settings if settings.grafana_webhook_secret and x_onguard_secret != settings.grafana_webhook_secret: raise HTTPException(status_code=401, detail="unauthorized") raw = await request.body() if len(raw) > 1_000_000: raise HTTPException(status_code=400, detail="body too large") try: body = json.loads(raw.decode() or "{}") except json.JSONDecodeError: body = {} if pool is None: logger.warning("ingress: database not configured, event not persisted") return Response(status_code=202) async with pool.acquire() as conn: row = await conn.fetchrow( "INSERT INTO ingress_events (source, body) VALUES ($1, $2::jsonb) RETURNING id", "grafana", json.dumps(body), ) raw_id = row["id"] if row else None bus = getattr(request.app.state, "event_bus", None) if bus and raw_id is not None: title = str(body.get("title") or body.get("ruleName") or "")[:500] alert = Alert( source="grafana", title=title, severity=Severity.WARNING, payload=body, received_at=datetime.now(timezone.utc), ) await bus.publish_alert_received(alert, raw_payload_ref=raw_id) return Response(status_code=202)