standardize packaging, tooling, docs, CI, and licensing

This commit is contained in:
2026-09-10 18:49:04 +05:30
parent c95de5a6e9
commit 0efe68b052
25 changed files with 667 additions and 74 deletions

View File

@@ -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(...)``.