standardize packaging, tooling, docs, CI, and licensing
This commit is contained in:
@@ -8,10 +8,11 @@ FastAPI dependencies for token validation (e.g., Bearer JWT introspection).
|
||||
|
||||
import os
|
||||
import re
|
||||
from typing import Any, Callable
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
from fastapi import Depends, Request, HTTPException
|
||||
from fastapi import Depends, HTTPException, Request
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
|
||||
_env_pattern = re.compile(r"\{(\w+)\}")
|
||||
@@ -19,14 +20,16 @@ _env_pattern = re.compile(r"\{(\w+)\}")
|
||||
|
||||
def _resolve_env(value: str) -> str:
|
||||
"""Replace {ENV_VAR} placeholders with values from os.environ."""
|
||||
def _replace(m: re.Match) -> str:
|
||||
|
||||
def _replace(m: re.Match[str]) -> str:
|
||||
return os.environ.get(m.group(1), "")
|
||||
|
||||
return _env_pattern.sub(_replace, value)
|
||||
|
||||
|
||||
def _resolve_scheme(scheme: dict) -> dict:
|
||||
def _resolve_scheme(scheme: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Recursively resolve env vars in all string-valued fields of a scheme."""
|
||||
resolved = {}
|
||||
resolved: dict[str, Any] = {}
|
||||
for key, value in scheme.items():
|
||||
if isinstance(value, str):
|
||||
resolved[key] = _resolve_env(value)
|
||||
@@ -37,13 +40,13 @@ def _resolve_scheme(scheme: dict) -> dict:
|
||||
return resolved
|
||||
|
||||
|
||||
def parse_security_schemes(spec: dict) -> dict[str, dict]:
|
||||
def parse_security_schemes(spec: dict[str, Any]) -> dict[str, dict[str, Any]]:
|
||||
"""Extract and resolve environment variables in security schemes."""
|
||||
raw = spec.get("components", {}).get("securitySchemes", {})
|
||||
return {name: _resolve_scheme(scheme) for name, scheme in raw.items()}
|
||||
|
||||
|
||||
def _make_bearer_dependency(introspect_url: str | None) -> Callable:
|
||||
def _make_bearer_dependency(introspect_url: str | None) -> Callable[..., Any]:
|
||||
"""
|
||||
Create a FastAPI dependency that validates a Bearer JWT.
|
||||
|
||||
@@ -76,7 +79,7 @@ def _make_bearer_dependency(introspect_url: str | None) -> Callable:
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="Authentication service unavailable",
|
||||
)
|
||||
) from None
|
||||
|
||||
if resp.status_code != 200:
|
||||
raise HTTPException(status_code=401, detail="Invalid or expired token")
|
||||
@@ -92,7 +95,9 @@ def _make_bearer_dependency(introspect_url: str | None) -> Callable:
|
||||
return _bearer_dep
|
||||
|
||||
|
||||
def _build_dependency(scheme_name: str, scheme: dict) -> Callable | None:
|
||||
def _build_dependency(
|
||||
scheme_name: str, scheme: dict[str, Any]
|
||||
) -> Callable[..., Any] | None:
|
||||
"""Return a FastAPI dependency callable for *scheme*, or ``None``."""
|
||||
scheme_type = scheme.get("type")
|
||||
|
||||
@@ -106,8 +111,8 @@ def _build_dependency(scheme_name: str, scheme: dict) -> Callable | None:
|
||||
|
||||
|
||||
def make_security_dependencies(
|
||||
spec: dict,
|
||||
security_schemes: dict[str, dict],
|
||||
spec: dict[str, Any],
|
||||
security_schemes: dict[str, dict[str, Any]],
|
||||
) -> dict[str, list[Any]]:
|
||||
"""
|
||||
Build a mapping of ``METHOD:/path`` → list of ``Depends(...)``.
|
||||
|
||||
Reference in New Issue
Block a user