"""REST API for findings (across all scans).""" from fastapi import APIRouter, Depends, Query from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from ..constants import ( DEFAULT_OFFSET, DEFAULT_PAGE_SIZE, JSON_PATH_RULE, JSON_PATH_SEVERITY, MAX_PAGE_SIZE, ) from ..db.engine import get_session from ..db.models import Finding from ..schemas import FindingsListResponse, serialize_finding router = APIRouter(prefix="/api/v1/findings", tags=["findings"]) @router.get("", response_model=FindingsListResponse) async def list_findings( limit: int = Query(DEFAULT_PAGE_SIZE, le=MAX_PAGE_SIZE), offset: int = Query(DEFAULT_OFFSET, ge=0), rule: str | None = Query(None), severity: str | None = Query(None), scan_id: int | None = Query(None), session: AsyncSession = Depends(get_session), ) -> dict: q = select(Finding) if rule: q = q.where(func.json_extract(Finding.data, JSON_PATH_RULE) == rule) if severity: q = q.where(func.json_extract(Finding.data, JSON_PATH_SEVERITY) == severity) if scan_id: q = q.where(Finding.scan_id == scan_id) total = await session.scalar(select(func.count()).select_from(q.subquery())) findings = (await session.execute(q.offset(offset).limit(limit))).scalars().all() return { "total": total, "limit": limit, "offset": offset, "findings": [serialize_finding(f) for f in findings], }