-
Notifications
You must be signed in to change notification settings - Fork 73
feat: add audit events plugin infrastructure (addresses #343) #360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add audit events plugin infrastructure (addresses #343) #360
Conversation
Add pluggy-based plugin system for streaming audit events to external systems (SIEM, logging platforms, analytics). - Add AuditEventsPluginSpec with audit_event_logged hook - Add AuditEventEnvelope dataclass with WHO/WHAT/WHEN/WHY context - Emit audit events from all 18 state-changing operations after DB commit - Add error isolation to prevent plugin failures from breaking operations - Add comprehensive test coverage for plugin infrastructure - Update README to document audit events plugin capability Signed-off-by: Jean-Philippe Lachance <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces the foundational plugin infrastructure for streaming Access audit events to external systems (SIEM, logging platforms, analytics tools). It establishes a pluggy-based plugin system with a comprehensive event envelope containing WHO/WHAT/WHEN/WHY context, and emits audit events after all state-changing operations complete.
Key changes:
- New
AuditEventsPluginSpecandAuditEventEnvelopeclasses for the plugin system - Audit event emission integrated into 18 state-changing operations across access requests, role requests, apps, groups, tags, and role assignments
- Comprehensive error isolation with try-catch blocks to prevent plugin failures from affecting core operations
- Import organization improvements and circular import fixes discovered during integration
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| api/plugins/audit_events.py | Core plugin specification defining AuditEventsPluginSpec, AuditEventEnvelope dataclass, and hook initialization |
| api/plugins/init.py | Exports audit events plugin hooks and markers for external plugin implementations |
| tests/test_audit_events.py | Comprehensive tests for envelope structure, hook functionality, and plugin infrastructure |
| api/operations/approve_access_request.py | Emits access_approve audit event after access request approval |
| api/operations/reject_access_request.py | Emits access_reject audit event after access request rejection |
| api/operations/create_access_request.py | Emits access_create audit event after access request creation |
| api/operations/approve_role_request.py | Emits role_request_approve audit event after role request approval |
| api/operations/reject_role_request.py | Emits role_request_reject audit event after role request rejection |
| api/operations/create_role_request.py | Emits role_request_create audit event after role request creation |
| api/operations/modify_group_users.py | Emits 4 event types for member/owner additions and removals |
| api/operations/modify_role_groups.py | Emits 2 event types for role group assignments and unassignments |
| api/operations/create_group.py | Emits group_create audit event after group creation |
| api/operations/delete_group.py | Emits group_delete audit event after group deletion |
| api/operations/modify_group_tags.py | Emits tag_update audit event when group tags are modified |
| api/operations/create_app.py | Emits app_create audit event after app creation |
| api/operations/delete_app.py | Emits app_delete audit event after app deletion |
| api/operations/modify_app_tags.py | Emits tag_update audit event when app tags are modified |
| api/operations/create_tag.py | Emits tag_create audit event after tag creation |
| api/operations/delete_tag.py | Emits tag_delete audit event after tag deletion |
| api/operations/modify_group_type.py | Import reorganization only (isort) |
| api/operations/unmanage_group.py | Import reorganization and log message formatting improvement |
| api/operations/delete_user.py | Fixed circular import by using explicit import path |
| api/operations/constraints/check_for_self_add.py | Import reorganization (isort) |
| api/operations/constraints/check_for_reason.py | Import reorganization (isort) |
| api/operations/init.py | Alphabetized imports for consistency |
| api/views/schemas/core_schemas.py | Fixed missing comma in tuple definition (bug fix) |
| README.md | Fixed incorrect plugin filename reference from requests.py to conditional_access.py |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -1,9 +1,7 @@ | |||
| import asyncio | |||
| from datetime import UTC, datetime | |||
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Inconsistent import style: This file imports UTC from datetime and uses datetime.now(UTC) for timestamps (lines 587, 620, 652, 685), while most other files in this PR import timezone and use datetime.now(timezone.utc). While both are functionally equivalent, consider using timezone.utc consistently across all files for better maintainability and code uniformity.
| @@ -1,9 +1,7 @@ | |||
| import asyncio | |||
| from datetime import UTC, datetime | |||
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Inconsistent import style: This file imports UTC from datetime and uses datetime.now(UTC) for timestamps (lines 520, 553, 587, 619), while most other files in this PR import timezone and use datetime.now(timezone.utc). While both are functionally equivalent, consider using timezone.utc consistently across all files for better maintainability and code uniformity.
| from datetime import UTC, datetime | |
| from datetime import datetime, timezone |
| await asyncio.wait(async_tasks) | ||
|
|
||
| # Emit audit events to plugins (after DB commit) - 2 event types | ||
| try: |
Copilot
AI
Dec 6, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] For consistency and robustness, consider redefining context = has_request_context() inside this try block (similar to line 574 in modify_group_users.py). While context is currently available from line 168, re-declaring it here makes the code more self-contained and resilient to future refactoring.
| try: | |
| try: | |
| context = has_request_context() |
|
And yes, I tested it end to end:
This made it much easier to visualize what’s changing, when, why, and by whom. |
Summary
This PR adds the foundational plugin infrastructure to enable streaming Access audit events to external systems (SIEM, logging platforms, analytics tools). This addresses the core need from #343 for exporting audit logs to destinations like S3, Splunk, Datadog, etc.
What's included
This PR provides the infrastructure layer that enables plugin developers to capture audit events. It does not include any specific destination plugins (S3, Kinesis, etc.) — those will come in follow-up PRs.
Core changes:
AuditEventsPluginSpecusing Python pluggy frameworkAuditEventEnvelopedataclass with complete WHO/WHAT/WHEN/WHY contextHow it works
After any state-changing operation (approve access, add user to group, delete app, etc.):
AuditEventEnvelopeis created with full contextPlugins are discovered via setuptools entrypoints, following the same pattern as existing notification and conditional access plugins.
Event coverage
Events emitted for: access requests, role requests, apps, groups, tags, group memberships, role assignments (20 distinct event types covering all state changes)
Additional changes
isortto alphabetize imports across all modified files for consistencyapi/operations/delete_user.pyand constraint files thatisortuncoveredapi/views/schemas/core_schemas.pytuple (line 323)requests.py→conditional_access.py)Next steps
Follow-up PR will add an example S3 plugin implementation demonstrating how to use this infrastructure.
Testing
Closes #343