Files
geointel/backend/tests/test_rc7_api_response_contracts.py
T
Codex 0fae53a7de
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s
Harden RC7 API response contracts
2026-07-18 05:07:35 +02:00

54 lines
1.6 KiB
Python

from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
BACKEND = ROOT / "backend"
def test_no_untyped_fastapi_response_models_remain() -> None:
route_root = BACKEND / "app" / "api" / "routes"
route_sources = "\n".join(
path.read_text(encoding="utf-8")
for path in sorted(route_root.glob("*.py"))
)
assert "response_model=dict" not in route_sources
def test_every_json_success_response_has_a_concrete_canonical_schema() -> None:
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(BACKEND))
from app.main import create_app
from scripts.audit_api_contracts import (
ALLOWED_NON_ENVELOPE_ENDPOINTS,
_validate_response_contracts,
)
openapi = create_app().openapi()
assert _validate_response_contracts(openapi) == []
untyped_successes: set[tuple[str, str]] = set()
for path, path_item in openapi["paths"].items():
for method, operation in path_item.items():
if method.upper() not in {"GET", "POST", "PATCH", "DELETE"}:
continue
has_json_schema = any(
response.get("content", {})
.get("application/json", {})
.get("schema")
for code, response in operation.get("responses", {}).items()
if str(code).startswith("2")
)
if not has_json_schema:
untyped_successes.add((method.upper(), path))
assert untyped_successes == ALLOWED_NON_ENVELOPE_ENDPOINTS - {
("GET", "/health"),
("GET", "/health/live"),
("GET", "/health/ready"),
}