Files
Aegis/backend/app/routers/reports.py

90 lines
3.0 KiB
Python

"""Reports endpoints — export coverage summaries and test results.
Thin HTTP adapter: delegates all data logic to coverage_report_service.
Endpoints
---------
GET /reports/coverage-summary — full coverage JSON report
GET /reports/coverage-csv — CSV export of coverage
GET /reports/test-results — test results report (JSON)
GET /reports/remediation-status — remediation status report (JSON)
"""
import csv
import io
from datetime import datetime
from typing import Optional
from fastapi import APIRouter, Depends, Query
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from app.database import get_db
from app.dependencies.auth import get_current_user
from app.models.user import User
from app.services.coverage_report_service import (
build_coverage_csv_rows,
build_coverage_summary,
build_remediation_status_report,
build_test_results_report,
)
router = APIRouter(prefix="/reports", tags=["reports"])
@router.get("/coverage-summary")
def coverage_summary(
tactic: Optional[str] = Query(None, description="Filter by tactic"),
platform: Optional[str] = Query(None, description="Filter by platform (in techniques)"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Full coverage report as JSON — technique-by-technique with test counts."""
return build_coverage_summary(db, tactic=tactic, platform=platform)
@router.get("/coverage-csv")
def coverage_csv(
tactic: Optional[str] = Query(None),
platform: Optional[str] = Query(None),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Export coverage as a downloadable CSV."""
rows = build_coverage_csv_rows(db, tactic=tactic, platform=platform)
output = io.StringIO()
writer = csv.writer(output)
for row in rows:
writer.writerow(row)
output.seek(0)
filename = f"aegis_coverage_{datetime.utcnow().strftime('%Y%m%d')}.csv"
return StreamingResponse(
iter([output.getvalue()]),
media_type="text/csv",
headers={"Content-Disposition": f"attachment; filename={filename}"},
)
@router.get("/test-results")
def test_results(
state: Optional[str] = Query(None),
date_from: Optional[str] = Query(None, description="ISO date string YYYY-MM-DD"),
date_to: Optional[str] = Query(None, description="ISO date string YYYY-MM-DD"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Report of test results with optional filters."""
return build_test_results_report(db, state=state, date_from=date_from, date_to=date_to)
@router.get("/remediation-status")
def remediation_status(
status: Optional[str] = Query(None, description="Filter by remediation status"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Report of remediation status across all tests."""
return build_remediation_status_report(db, status=status)