shinkan-jinkendo/backend/scripts/check_access_layer_hints.py
Lars 90e8f51566
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Test Suite / pytest-backend (push) Successful in 44s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m13s
Update Catalog Prompt Slots Router and Access Layer Exemptions
- Added documentation to the `catalog_prompt_slots.py` file to clarify its role as a global admin catalog requiring authentication and admin role, without tenant context.
- Updated the `check_access_layer_hints.py` script to include `catalog_prompt_slots.py` in the list of exempt routers, ensuring proper access control for admin functionalities.
2026-06-15 15:27:03 +02:00

86 lines
3.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()
"ai_skill_retrieval_admin.py", # Superadmin-Plattform-Konfiguration Skill-KI-Retrieval; require_auth + is_superadmin — kein Vereinsmandant
"ai_prompts_admin.py", # Superadmin ai_prompts; require_auth + is_superadmin — kein Vereinsmandant
"exercise_enrichment_admin.py", # Superadmin Batch-Übungs-Anreicherung KI; require_auth + is_superadmin — kein Vereinsmandant
"admin_user_content.py", # Superadmin Moderation nutzerangelegter Inhalte; require_auth + is_superadmin — kein Vereinsmandant
"admin_rights.py", # Superadmin Rollen/Rechte (Capabilities, Kontingent-Bypass, Pläne); require_auth + is_superadmin — kein Vereinsmandant
"catalogs.py",
"catalog_prompt_slots.py", # Admin Stammdaten KI-Prompt-Slots; require_auth + admin/superadmin — globaler Katalog, kein Vereinsmandant
"skills.py",
"maturity_models.py",
"matrix_stack_bundle.py",
"matrix_editor.py", # Superadmin Editor-Export/Import Fähigkeitsmatrix; require_auth + is_superadmin — kein Vereinsmandant
"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())