Problem
The README says every /api/v1/* route requires a bearer API key, but GET /api/v1/experiments/report and POST /api/v1/experiments/report/export have no authentication dependency. The report scans all student profiles, and the export endpoint also writes derived data to disk. Any network caller can currently trigger both operations.
This is a security boundary regression and creates an avoidable denial-of-service/storage-abuse path even when the returned metrics are aggregated.
Proposed change
- Require authenticated, explicitly privileged access for both experiment routes (prefer an
admin or dedicated researcher role rather than any parent/teacher account).
- Centralize the dependency at a router/sub-router boundary so future experiment endpoints inherit the policy by default.
- Validate
retention_days with a bounded FastAPI Query (for example 1–365) on both routes.
- Make exports non-publicly triggerable and return only a safe artifact identifier, never a host filesystem path.
- Update the authentication documentation/OpenAPI descriptions to state the role requirement.
- Audit all
/api/v1 endpoints with a route-table test that fails when a route is accidentally added without the intended auth dependency. Public endpoints, if any, should be explicitly allowlisted.
Acceptance criteria
- Missing or invalid credentials receive
401 on both experiment endpoints.
- Authenticated accounts without the privileged role receive
403.
- A privileged account can retrieve and export the report.
- Invalid or extreme
retention_days values receive 422 without scanning profiles or writing a file.
- Automated tests enumerate the registered API routes and enforce the documented authentication policy.
- README examples and generated OpenAPI security metadata match the implementation.
Relevant code
api/routes.py (get_experiment_report, export_experiment_report)
agent/auth.py
dashboard/experiment_report.py
README.md
Problem
The README says every
/api/v1/*route requires a bearer API key, butGET /api/v1/experiments/reportandPOST /api/v1/experiments/report/exporthave no authentication dependency. The report scans all student profiles, and the export endpoint also writes derived data to disk. Any network caller can currently trigger both operations.This is a security boundary regression and creates an avoidable denial-of-service/storage-abuse path even when the returned metrics are aggregated.
Proposed change
adminor dedicatedresearcherrole rather than any parent/teacher account).retention_dayswith a bounded FastAPIQuery(for example 1–365) on both routes./api/v1endpoints with a route-table test that fails when a route is accidentally added without the intended auth dependency. Public endpoints, if any, should be explicitly allowlisted.Acceptance criteria
401on both experiment endpoints.403.retention_daysvalues receive422without scanning profiles or writing a file.Relevant code
api/routes.py(get_experiment_report,export_experiment_report)agent/auth.pydashboard/experiment_report.pyREADME.md