Der Decorator require_school (utils/checks.py:191) soll sicherstellen, dass global-administrators bei school-scoped Endpunkten einen gültigen school-Parameter mitgeben. Er wird an folgenden Stellen aber über statt unter dem Routen-Decorator gesetzt:
routers_v1/groups.py:92 (delete_group)
routers_v1/groups.py:267 (add_members_to_group)
routers_v1/groups.py:305 (remove_members_from_group)
routers_v1/groups.py:343 (migrate_group)
routers_v1/devices.py:20 (get_all_devices)
routers_v1/devices.py:160 (post_management_list_content)
routers_v1/devices.py:203 (do_import_devices)
@require_school
@router.delete("/{group}", ...)
def delete_group(...):
FastAPIs Routen-Decorator (router.get/post/delete/patch) registriert die Endpunkt-Funktion beim Aufruf sofort im Router und gibt sie unverändert zurück. Da er als innerer (unterster) Decorator zuerst ausgeführt wird, landet die unwrapped Original-Funktion in der Routing-Tabelle. Der äußere require_school-Wrapper wird zwar noch auf den Rückgabewert angewendet, ersetzt aber nur den module-level Namen — die Route selbst zeigt weiterhin auf die ungewrappte Funktion.
Der Wrapper wird bei echten HTTP-Requests dadurch nie aufgerufen (per TestClient-Testaufbau reproduziert: der Wrapper-Code läuft nachweislich nicht). Die bestehenden Tests bemerken das nicht, weil test_checks.py::TestRequireSchool den Wrapper direkt aufruft statt über eine registrierte FastAPI-Route zu gehen.
Fix: Reihenfolge umkehren, @require_school muss unter dem @router.*-Decorator stehen.
Der Decorator
require_school(utils/checks.py:191) soll sicherstellen, dass global-administrators bei school-scoped Endpunkten einen gültigenschool-Parameter mitgeben. Er wird an folgenden Stellen aber über statt unter dem Routen-Decorator gesetzt:routers_v1/groups.py:92(delete_group)routers_v1/groups.py:267(add_members_to_group)routers_v1/groups.py:305(remove_members_from_group)routers_v1/groups.py:343(migrate_group)routers_v1/devices.py:20(get_all_devices)routers_v1/devices.py:160(post_management_list_content)routers_v1/devices.py:203(do_import_devices)FastAPIs Routen-Decorator (
router.get/post/delete/patch) registriert die Endpunkt-Funktion beim Aufruf sofort im Router und gibt sie unverändert zurück. Da er als innerer (unterster) Decorator zuerst ausgeführt wird, landet die unwrapped Original-Funktion in der Routing-Tabelle. Der äußererequire_school-Wrapper wird zwar noch auf den Rückgabewert angewendet, ersetzt aber nur den module-level Namen — die Route selbst zeigt weiterhin auf die ungewrappte Funktion.Der Wrapper wird bei echten HTTP-Requests dadurch nie aufgerufen (per
TestClient-Testaufbau reproduziert: der Wrapper-Code läuft nachweislich nicht). Die bestehenden Tests bemerken das nicht, weiltest_checks.py::TestRequireSchoolden Wrapper direkt aufruft statt über eine registrierte FastAPI-Route zu gehen.Fix: Reihenfolge umkehren,
@require_schoolmuss unter dem@router.*-Decorator stehen.