chore: release v1.0.0 — каркас FastAPI, ingress Grafana, интеграции, документация

Made-with: Cursor
This commit is contained in:
Alexandr
2026-04-03 08:30:56 +03:00
commit 4da9b13a86
34 changed files with 1049 additions and 0 deletions

View File

@ -0,0 +1 @@
"""Входящие интеграции (Grafana и др.)."""

View File

@ -0,0 +1,43 @@
import json
import logging
from fastapi import APIRouter, Depends, Header, HTTPException, Request
from starlette.responses import Response
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:
await conn.execute(
"INSERT INTO ingress_events (source, body) VALUES ($1, $2::jsonb)",
"grafana",
json.dumps(body),
)
return Response(status_code=202)