shinkan-jinkendo/backend/scripts/check_access_layer_hints.py
Lars b9adf6da84
All checks were successful
Deploy Development / deploy (push) Successful in 37s
Test Suite / pytest-backend (push) Successful in 37s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 7s
Test Suite / playwright-tests (push) Successful in 43s
fix(access-layer): legal_documents in EXEMPT_ROUTERS eintragen
Router hat keinen Vereinsbezug (Plattform-Rechtstexte).
Öffentlicher Endpoint ohne Auth; Admin-Endpoints require_auth + is_superadmin().
ACCESS_LAYER_STRICT schlägt jetzt nicht mehr an.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 12:07:52 +02:00

79 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""
Heuristik-Check: Router mit FastAPI-Routen und Auth sollten bei mandantenrelevanten APIs
get_tenant_context nutzen — siehe ACCESS_LAYER_AND_GOVERNANCE_PLAN.md.
Lauf aus Repo-Root:
python backend/scripts/check_access_layer_hints.py
Mit Fehler-Exit bei Verstößen (z. B. CI):
set ACCESS_LAYER_STRICT=1 # Windows: set ACCESS_LAYER_STRICT=1
"""
from __future__ import annotations
import os
import sys
from pathlib import Path
# Router, die bewusst keinen TenantContext verwenden (global / Auth-only / Admin-Tools).
# Neuen Eintrag nur mit kurzer Begründung im Commit/Audit ergänzen.
EXEMPT_ROUTERS: frozenset[str] = frozenset(
{
"auth.py",
"admin_users.py",
"platform_media_storage.py",
"legal_documents.py", # ACCESS_LAYER exempt: Plattform-Rechtstexte ohne Vereinsbezug; öffentlicher Endpoint ohne Auth, Admin-Endpoints require_auth + is_superadmin()
"catalogs.py",
"skills.py",
"maturity_models.py",
"matrix_stack_bundle.py",
"import_wiki.py",
"import_wiki_admin.py",
}
)
def main() -> int:
strict = os.environ.get("ACCESS_LAYER_STRICT", "").strip().lower() in ("1", "true", "yes")
root = Path(__file__).resolve().parents[1]
routers = root / "routers"
if not routers.is_dir():
print("check_access_layer_hints: routers/ nicht gefunden", file=sys.stderr)
return 1
issues: list[str] = []
for path in sorted(routers.glob("*.py")):
name = path.name
text = path.read_text(encoding="utf-8")
if "@router." not in text:
continue
if name in EXEMPT_ROUTERS:
continue
if "get_tenant_context" in text:
continue
if "require_auth" not in text:
continue
issues.append(
f" {path.relative_to(root.parent)}: Routen + require_auth, "
f"aber kein get_tenant_context — TenantContext ergänzen oder in EXEMPT_ROUTERS eintragen "
f"(mit Begründung / Audit)."
)
if not issues:
print("check_access_layer_hints: OK (keine auffälligen Router außerhalb EXEMPT).")
return 0
print("check_access_layer_hints: mögliche ACCESS_LAYER-Abweichungen:\n", file=sys.stderr)
for line in issues:
print(line, file=sys.stderr)
print(
"\nHinweis: Heuristik — false positives möglich. "
"Bei echter Ausnahme Datei zu EXEMPT_ROUTERS hinzufügen.",
file=sys.stderr,
)
return 1 if strict else 0
if __name__ == "__main__":
raise SystemExit(main())