diff --git a/docker/main/requirements-wheels.txt b/docker/main/requirements-wheels.txt index bbfe91f824..5bb3b4c511 100644 --- a/docker/main/requirements-wheels.txt +++ b/docker/main/requirements-wheels.txt @@ -2,9 +2,8 @@ aiofiles == 25.1.* click == 8.5.* # FastAPI aiohttp == 3.12.* -starlette == 0.47.* starlette-context == 0.5.* -fastapi[standard-no-fastapi-cloud-cli] == 0.116.* +fastapi[standard-no-fastapi-cloud-cli] == 0.142.* uvicorn == 0.52.* slowapi == 0.1.* joserfc == 1.6.* diff --git a/docs/static/frigate-api.yaml b/docs/static/frigate-api.yaml index 97acaf942c..b0f72808e8 100644 --- a/docs/static/frigate-api.yaml +++ b/docs/static/frigate-api.yaml @@ -8017,7 +8017,7 @@ components: properties: file: type: string - format: binary + contentMediaType: application/octet-stream title: File type: object required: @@ -8027,7 +8027,7 @@ components: properties: file: type: string - format: binary + contentMediaType: application/octet-stream title: File type: object required: @@ -9601,6 +9601,11 @@ components: type: type: string title: Error Type + input: + title: Input + ctx: + type: object + title: Context type: object required: - loc diff --git a/generate_api_auth_spec.py b/generate_api_auth_spec.py index 3193836927..6b5b8b0eaf 100644 --- a/generate_api_auth_spec.py +++ b/generate_api_auth_spec.py @@ -136,33 +136,36 @@ ACCESS_NOTES = { } +# Mirrors the router set wired up in frigate.api.fastapi_app. +ROUTERS = [ + auth.router, + camera.router, + chat.router, + classification.router, + review.router, + main_app.router, + preview.router, + notification.router, + export.router, + hardware.router, + notices.router, + event.router, + media.router, + motion_search.router, + record.router, + debug_replay.router, +] + + def build_app() -> FastAPI: """Build a bare app with every router mounted. - This mirrors the router set wired up in frigate.api.fastapi_app. It omits - the global admin dependency and all runtime state; the OpenAPI route table - and the per-route dependencies are all we need to export and classify. + It omits the global admin dependency and all runtime state; the OpenAPI + route table and the per-route dependencies are all we need to export and + classify. """ app = FastAPI() - routers = [ - auth.router, - camera.router, - chat.router, - classification.router, - review.router, - main_app.router, - preview.router, - notification.router, - export.router, - hardware.router, - notices.router, - event.router, - media.router, - motion_search.router, - record.router, - debug_replay.router, - ] - for router in routers: + for router in ROUTERS: app.include_router(router) return app @@ -318,13 +321,17 @@ def _classify_base( def build_access_map( - app: FastAPI, exempt_paths: set[str], exempt_prefixes: tuple[str, ...], ) -> dict[tuple[str, str], dict]: """Map (path, lowercase method) -> classification details.""" access_map: dict[tuple[str, str], dict] = {} - for route in app.routes: + + # app.routes holds opaque wrappers for included routers on newer FastAPI. + # The routers mount without a prefix, so their own routes carry final paths. + routes = [route for router in ROUTERS for route in router.routes] + + for route in routes: if not isinstance(route, APIRoute): continue level, roles, flag = classify_route(route, exempt_paths, exempt_prefixes) @@ -515,7 +522,7 @@ def render(spec: dict) -> str: def build_spec() -> tuple[dict, dict, list, list, list]: app = build_app() exempt_paths, exempt_prefixes = read_exempt_rules() - access_map = build_access_map(app, exempt_paths, exempt_prefixes) + access_map = build_access_map(exempt_paths, exempt_prefixes) spec = base_document(app.openapi()) normalized = strip_volatile_defaults(spec)