- Added new documentation references for access layer governance in CLAUDE.md, including multi-tenancy and endpoint audit guidelines. - Updated ACCESS_LAYER_AND_GOVERNANCE_PLAN.md to include cursor and heuristic checks for access layer compliance. - Enhanced ACCESS_LAYER_ENDPOINT_AUDIT.md to clarify endpoint visibility and governance requirements, including exemptions for certain routers. - Introduced library_content_visible_to_profile function in club_tenancy.py to streamline visibility checks for library content. - Updated exercise progression graphs router to utilize the new visibility function, improving access control. - Bumped application version to 0.8.27 and updated changelog to reflect these changes.
77 lines
2.3 KiB
Python
77 lines
2.3 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",
|
|
"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())
|