From 90206f867304a63b5c91dddebf450f3596ca5840 Mon Sep 17 00:00:00 2001 From: briquet Date: Mon, 19 Oct 2026 13:18:56 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(backend)=20split=20audit=20r?= =?UTF-8?q?egistrations=20from=20the=20action=20catalogue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit core/auditing.py both declared the actions that emitters import and registered the models and authentication classes: it made it impossible for authentication class to emit an audit event without an import cycle. Keep the actions and transit_code_target in core/auditing.py and move the model and authentication method registrations to core/audit_registry.py, the module the audit app now autodiscovers. --- docs/features/audit-logging.md | 7 ++- src/backend/core/audit/apps.py | 6 +-- src/backend/core/audit/registry.py | 2 +- src/backend/core/audit_registry.py | 82 +++++++++++++++++++++++++++++ src/backend/core/auditing.py | 83 ++---------------------------- 5 files changed, 96 insertions(+), 84 deletions(-) create mode 100644 src/backend/core/audit_registry.py diff --git a/docs/features/audit-logging.md b/docs/features/audit-logging.md index b07ee5fae..79342feb6 100644 --- a/docs/features/audit-logging.md +++ b/docs/features/audit-logging.md @@ -383,6 +383,9 @@ APPLICATION_TOKEN_ISSUE = audit.Action( ROOM_CREATE = audit.Action("room.create") ``` +`core/auditing.py` imports nothing but the audit facility, so that any module can import it, authentication classes +included. Models and authentication classes are registered apart, in `core/audit_registry.py`. + ### Auditing a DRF view A DRF view only declares the actions it audits: everything else is derived from the response. CRUD actions are mapped @@ -466,8 +469,8 @@ on. A registered field that cannot be read is left out of the target, and the ev ### Registering models and authentication methods -The project describes itself to the audit facility in code, in `core/auditing.py`. Once the audit app is ready, it -imports the `auditing` module of every installed app. +The project describes itself to the audit facility in code, in `core/audit_registry.py`. Once the audit app is ready, +it imports the `audit_registry` module of every installed app. **`audit.register(Model, ...)`** tells the audit log how to handle a model: diff --git a/src/backend/core/audit/apps.py b/src/backend/core/audit/apps.py index 4bebe6da8..ddb7c7d3c 100644 --- a/src/backend/core/audit/apps.py +++ b/src/backend/core/audit/apps.py @@ -16,11 +16,11 @@ class AuditConfig(AppConfig): def ready(self): """Connect the login, failed login and logout receivers. - Then import the ``auditing`` module of every installed app, where the - project registers its models and authentication classes. + Then import the ``audit_registry`` module of every installed app, where + the project registers its models and authentication classes. """ connect_auth_signals() - autodiscover_modules("auditing") + autodiscover_modules("audit_registry") class AuditedAdminConfig(AdminConfig): diff --git a/src/backend/core/audit/registry.py b/src/backend/core/audit/registry.py index d1e24e554..861355278 100644 --- a/src/backend/core/audit/registry.py +++ b/src/backend/core/audit/registry.py @@ -1,6 +1,6 @@ """Declare what audit events may say about models and authentication classes. -The project registers them from an ``auditing`` module in one of its apps, +The project registers them from an ``audit_registry`` module in one of its apps, imported once the audit app is ready:: audit.register( diff --git a/src/backend/core/audit_registry.py b/src/backend/core/audit_registry.py new file mode 100644 index 000000000..95a7003a1 --- /dev/null +++ b/src/backend/core/audit_registry.py @@ -0,0 +1,82 @@ +"""How Meet describes itself to the audit facility: its models and authentication classes. + +Imported by the audit app once it is ready, see ``core.audit.apps``. The actions +Meet audits are declared in ``core.auditing``. +""" + +from django.contrib.auth.models import Group + +from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication + +from core import audit, models +from core.audit import EventCategory +from core.authentication.backends import OIDCAuthenticationBackend +from core.authentication.livekit import LiveKitTokenAuthentication +from core.authentication.user_token import UserAccessJWTAuthentication +from core.external_api.authentication import ( + AddonsJWTAuthentication, + ApplicationJWTAuthentication, +) +from core.recording.event.authentication import HeaderBasedAuthentication +from core.roomkit.authentication import ServerToServerAuthentication + +# Models + +audit.register( + models.User, + category=EventCategory.IAM, + admin_values=( + "is_active", + "is_staff", + "is_superuser", + "is_device", + "groups", + "user_permissions", + ), +) +audit.register(Group, category=EventCategory.IAM, admin_values=("name", "permissions")) +audit.register( + models.Application, + category=EventCategory.IAM, + entity_type="application", + fields=("client_id", "name", "is_active", "scopes"), + admin_values=("name", "is_active", "scopes"), +) +audit.register( + models.ApplicationDomain, category=EventCategory.IAM, admin_values=("domain",) +) +audit.register( + models.ResourceAccess, + category=EventCategory.IAM, + fields=("resource_id", "user_id", "role"), + admin_values=("role",), + user_target="user", +) +audit.register( + models.RecordingAccess, + category=EventCategory.IAM, + admin_values=("role",), + user_target="user", +) +audit.register( + models.Room, + fields=("slug", "name", "access_level"), + admin_values=("name", "slug", "access_level", "configuration"), +) +audit.register( + models.Recording, + fields=("room_id", "status", "mode", "requested_mode", "is_transcribed"), + admin_values=("status", "mode"), +) +audit.register(models.File, admin_values=("title", "upload_state")) + +# Authentication classes and login backends -> ``lasuite.auth.method`` + +audit.register_auth_method(OIDCAuthenticationBackend, "oidc") +audit.register_auth_method(ApplicationJWTAuthentication, "application_jwt") +audit.register_auth_method(AddonsJWTAuthentication, "addons_jwt") +audit.register_auth_method(ResourceServerAuthentication, "resource_server") +audit.register_auth_method(LiveKitTokenAuthentication, "livekit_token") +audit.register_auth_method(UserAccessJWTAuthentication, "user_access_jwt") +audit.register_auth_method(HeaderBasedAuthentication, "shared_secret") +audit.register_auth_method(ServerToServerAuthentication, "shared_secret") diff --git a/src/backend/core/auditing.py b/src/backend/core/auditing.py index eacdd6ef1..b9f8745b3 100644 --- a/src/backend/core/auditing.py +++ b/src/backend/core/auditing.py @@ -1,23 +1,12 @@ -"""What Meet audits, and what its audit events may say. +"""The catalogue of what Meet audits: its actions and the targets that are not models. -Imported by the audit app once it is ready, see ``core.audit.apps``. +It imports nothing but the audit facility and leaf helpers, so that any module can +import it, authentication classes included. Models and authentication classes +are registered in ``core.audit_registry``. """ -from django.contrib.auth.models import Group - -from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication - -from core import audit, models +from core import audit from core.audit import EventCategory, EventType -from core.authentication.backends import OIDCAuthenticationBackend -from core.authentication.livekit import LiveKitTokenAuthentication -from core.authentication.user_token import UserAccessJWTAuthentication -from core.external_api.authentication import ( - AddonsJWTAuthentication, - ApplicationJWTAuthentication, -) -from core.recording.event.authentication import HeaderBasedAuthentication -from core.roomkit.authentication import ServerToServerAuthentication from core.services.transit_code import TransitCodeService # Actions @@ -57,68 +46,6 @@ RECORDING_SUMMARY_REPORT = audit.Action( "recording.summary.report", types=(EventType.END,) ) -# Models - -audit.register( - models.User, - category=EventCategory.IAM, - admin_values=( - "is_active", - "is_staff", - "is_superuser", - "is_device", - "groups", - "user_permissions", - ), -) -audit.register(Group, category=EventCategory.IAM, admin_values=("name", "permissions")) -audit.register( - models.Application, - category=EventCategory.IAM, - entity_type="application", - fields=("client_id", "name", "is_active", "scopes"), - admin_values=("name", "is_active", "scopes"), -) -audit.register( - models.ApplicationDomain, category=EventCategory.IAM, admin_values=("domain",) -) -audit.register( - models.ResourceAccess, - category=EventCategory.IAM, - fields=("resource_id", "user_id", "role"), - admin_values=("role",), - user_target="user", -) -audit.register( - models.RecordingAccess, - category=EventCategory.IAM, - admin_values=("role",), - user_target="user", -) -audit.register( - models.Room, - fields=("slug", "name", "access_level"), - admin_values=("name", "slug", "access_level", "configuration"), -) -audit.register( - models.Recording, - fields=("room_id", "status", "mode", "requested_mode", "is_transcribed"), - admin_values=("status", "mode"), -) -audit.register(models.File, admin_values=("title", "upload_state")) - -# Authentication classes and login backends -> ``lasuite.auth.method`` - -audit.register_auth_method(OIDCAuthenticationBackend, "oidc") -audit.register_auth_method(ApplicationJWTAuthentication, "application_jwt") -audit.register_auth_method(AddonsJWTAuthentication, "addons_jwt") -audit.register_auth_method(ResourceServerAuthentication, "resource_server") -audit.register_auth_method(LiveKitTokenAuthentication, "livekit_token") -audit.register_auth_method(UserAccessJWTAuthentication, "user_access_jwt") -audit.register_auth_method(HeaderBasedAuthentication, "shared_secret") -audit.register_auth_method(ServerToServerAuthentication, "shared_secret") - - # Targets that are not models