Реестр MODULE_MOUNTS: API, ui_router, фрагменты главной, EventBus. Главная и страницы модулей с правой навигацией из реестра; wrap_module_html_page. Ingress: публикация alert.received после сохранения в БД. Документация MODULES.md; pytest покрывает API, UI и навигацию. Made-with: Cursor
59 lines
1.9 KiB
Python
59 lines
1.9 KiB
Python
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)
|