[ADMINAPI-1479] [ADMINAPI-1327] Missing Audit Logging Across Critical Operations - #414
Conversation
Covers the resolved log4net-vs-EF-Core write path decision, unified AuditLogs table schema, capture points, async write pipeline with retry/fallback, and single-flag configuration. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ten-task plan covering the shared capture pipeline (channel, recorder, background writer with retry/fallback), the two capture points (auth events, action-event middleware), per-version DbUp scripts and EF mapping for V2 and V3, DI wiring, manual end-to-end verification, and documentation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tion audit events OnChallenge always recorded StatusCode=200 because context.Response.StatusCode never equals 0 at that point in the pipeline; the ternary's == 0 branch was dead code. An auth challenge always results in a 401, so record it unconditionally. AuditActionLoggingMiddleware used try/finally, so when next(context) threw, the finally block read context.Response.StatusCode before the outer exception handler had set it to 500, recording a misleading 200/whatever-default for requests that actually failed. Switched to try/catch(rethrow) so the exception path always records 500 explicitly, while the success path still records the real response status code. Updated AuditActionLoggingMiddlewareTests to assert the exception path records 500 instead of an unconstrained int value.
…nown gaps - Widen adminapi.AuditLogs.ClientId from 100 to 256 chars (MsSql/PgSql, V2/V3) to match Applications.ClientId, preventing silent audit fallback for longer client ids. - Extract OnChallenge's audit-recording body into SecurityExtensions.RecordChallengeAuditEvent and add unit tests covering DefaultTokenResponseHandler.HandleAsync (success/failure) and the OnChallenge 401 path. - Document the double audit row produced by /connect/token requests and the known gap that 403-denied mutations are not currently audited.
Adds eng/run-db-tests.ps1 and eng/db-tests-compose.yml, modeled on eng/run-bruno-e2e.ps1, to stand up bare SQL Server and/or PostgreSQL containers, apply the Admin API DbUp migrations, and run the *.DBTests suites locally — since no local database is available by default for these projects. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Test Results 15 files 15 suites 1m 12s ⏱️ Results for commit 4a72f49. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Pull request overview
Adds an audit trail logging subsystem to Admin API so authentication outcomes and mutating administrative actions can be recorded to a database-backed adminapi.AuditLogs table (with background processing and “fail-open” behavior), plus supporting docs and tests.
Changes:
- Introduces audit capture points (middleware + auth hooks) and an async write pipeline (bounded channel + hosted background service + per-version EF writer).
- Adds DbUp migrations + EF mappings for the new
AuditLogstable across SQL Server and PostgreSQL, plus DB/integration tests and local DB test runner scripts. - Updates developer documentation to describe the audit logging feature and configuration.
Reviewed changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| eng/run-db-tests.ps1 | Adds a local helper script to run DBTests against containerized DB engines and apply migrations. |
| eng/db-tests-compose.yml | Adds bare SQL Server/PostgreSQL containers for DBTests/migration verification. |
| docs/developer.md | Links audit logging docs from the main developer guide. |
| docs/design/plan-b-log4net-to-serilog-migration.md | Removes an obsolete design plan document. |
| docs/design/2026-07-28-audit-trail-logging.md | Adds the technical design write-up for audit trail logging. |
| docs/audit-logging.md | Adds operator/developer documentation for enabling audit logging and understanding captured events/table schema. |
| Application/EdFi.Ods.AdminApi/Program.cs | Registers the audit action logging middleware in the request pipeline. |
| Application/EdFi.Ods.AdminApi/Infrastructure/WebApplicationBuilderExtensions.cs | Wires up audit logging services (settings, channel, recorder, writer, hosted service). |
| Application/EdFi.Ods.AdminApi/Infrastructure/Security/SecurityExtensions.cs | Records authentication success/failure audit events (token response handler + 401 challenge). |
| Application/EdFi.Ods.AdminApi/Infrastructure/Audit/AdminApiAuditLogWriter.cs | Adds V2 audit log writer implementation using EF Core. |
| Application/EdFi.Ods.AdminApi/Infrastructure/AdminApiDbContext.cs | Adds DbSet<AuditLog> and mapping for the AuditLogs table (V2). |
| Application/EdFi.Ods.AdminApi/Artifacts/PgSql/Structure/Admin/00007-CreateAuditLogs.sql | Adds PostgreSQL DbUp migration to create AuditLogs (V2). |
| Application/EdFi.Ods.AdminApi/Artifacts/MsSql/Structure/Admin/00007-CreateAuditLogs.sql | Adds SQL Server DbUp migration to create AuditLogs (V2). |
| Application/EdFi.Ods.AdminApi/appsettings.json | Adds AuditLogging:Enabled configuration flag (V2 host appsettings). |
| Application/EdFi.Ods.AdminApi.V3/Infrastructure/Audit/AdminApiAuditLogWriter.cs | Adds V3 audit log writer implementation using EF Core. |
| Application/EdFi.Ods.AdminApi.V3/Infrastructure/AdminApiDbContext.cs | Adds DbSet<AuditLog> and mapping for the AuditLogs table (V3). |
| Application/EdFi.Ods.AdminApi.V3/Artifacts/PgSql/Structure/Admin/00007-CreateAuditLogs.sql | Adds PostgreSQL DbUp migration to create AuditLogs (V3). |
| Application/EdFi.Ods.AdminApi.V3/Artifacts/MsSql/Structure/Admin/00007-CreateAuditLogs.sql | Adds SQL Server DbUp migration to create AuditLogs (V3). |
| Application/EdFi.Ods.AdminApi.V3/appsettings.json | Adds AuditLogging:Enabled configuration flag (V3 appsettings file). |
| Application/EdFi.Ods.AdminApi.V3.DBTests/Services/Jobs/JobStatusServiceTests.cs | Adjusts namespace aliasing for clarity in V3 DB tests. |
| Application/EdFi.Ods.AdminApi.V3.DBTests/Infrastructure/Audit/AdminApiAuditLogWriterTests.cs | Adds DB test validating audit log persistence for V3 writer. |
| Application/EdFi.Ods.AdminApi.V3.DBTests/Database/QueryTests/GetResourceClaimsQueryTests.cs | Adjusts namespace aliasing in V3 DB tests. |
| Application/EdFi.Ods.AdminApi.V3.DBTests/Database/QueryTests/GetResourceClaimsAsFlatListQueryTests.cs | Adjusts namespace aliasing in V3 DB tests. |
| Application/EdFi.Ods.AdminApi.UnitTests/Infrastructure/Security/SecurityExtensionsAuditTests.cs | Adds unit tests for auth audit event recording behavior. |
| Application/EdFi.Ods.AdminApi.DBTests/Services/Jobs/JobStatusServiceTests.cs | Adjusts DbContext aliasing for clarity in V2 DB tests. |
| Application/EdFi.Ods.AdminApi.DBTests/Infrastructure/Audit/AdminApiAuditLogWriterTests.cs | Adds DB test validating audit log persistence for V2 writer. |
| Application/EdFi.Ods.AdminApi.DBTests/Database/QueryTests/GetResourceClaimsQueryTests.cs | Adjusts namespace qualification in V2 DB tests. |
| Application/EdFi.Ods.AdminApi.DBTests/Database/QueryTests/GetResourceClaimsAsFlatListQueryTests.cs | Adjusts namespace qualification in V2 DB tests. |
| Application/EdFi.Ods.AdminApi.Common/Infrastructure/Audit/IAuditLogWriter.cs | Adds interface contract for audit log persistence. |
| Application/EdFi.Ods.AdminApi.Common/Infrastructure/Audit/IAuditEventRecorder.cs | Adds interface contract for recording audit events. |
| Application/EdFi.Ods.AdminApi.Common/Infrastructure/Audit/AuditLoggingSettings.cs | Adds configuration binding object for AuditLogging. |
| Application/EdFi.Ods.AdminApi.Common/Infrastructure/Audit/AuditLogChannel.cs | Adds bounded channel wrapper for audit event buffering. |
| Application/EdFi.Ods.AdminApi.Common/Infrastructure/Audit/AuditLogBackgroundService.cs | Adds background service to drain channel and write events with retry/fallback. |
| Application/EdFi.Ods.AdminApi.Common/Infrastructure/Audit/AuditLog.cs | Adds EF entity for persisted audit logs. |
| Application/EdFi.Ods.AdminApi.Common/Infrastructure/Audit/AuditEventType.cs | Adds enum defining audit event types. |
| Application/EdFi.Ods.AdminApi.Common/Infrastructure/Audit/AuditEventRecorder.cs | Adds recorder that builds/enqueues events and resolves tenant connection string. |
| Application/EdFi.Ods.AdminApi.Common/Infrastructure/Audit/AuditEvent.cs | Adds in-memory audit event DTO used by the channel/writer. |
| Application/EdFi.Ods.AdminApi.Common/Infrastructure/Audit/AuditActionLoggingMiddleware.cs | Adds middleware capturing mutating HTTP action audit events. |
| Application/EdFi.Ods.AdminApi.Common/AssemblyInfo.cs | Grants internal visibility to common unit tests. |
| Application/EdFi.Ods.AdminApi.Common.UnitTests/Infrastructure/Audit/AuditLogBackgroundServiceTests.cs | Adds unit tests for background service retry/fallback behavior. |
| Application/EdFi.Ods.AdminApi.Common.UnitTests/Infrastructure/Audit/AuditEventRecorderTests.cs | Adds unit tests for recorder enable/disable and connection string resolution. |
| Application/EdFi.Ods.AdminApi.Common.UnitTests/Infrastructure/Audit/AuditActionLoggingMiddlewareTests.cs | Adds unit tests for middleware verb filtering and exception handling. |
Review finding:
|
Follow-up / partial retraction: my "ClientId will always be null" claim was wrongThanks for pushing back with the Docker screenshot — that's real evidence and it contradicts what I asserted earlier. Correcting the record: What I got wrong: I traced the claim only through I grepped the whole repo for anything that could be injecting a Ask, so we can close this out with confidence: could you decode the actual JWT from one of the requests where
What still stands from the original finding: the two On "users-global, teams-global, ownerships-global, user-team-memberships" — good catch, and you're right to question it. I checked this repo's actual feature/route names ( Sorry for the noise on the first point — appreciate you checking against real runtime behavior instead of taking the static claim at face value. |
This pull request introduces a comprehensive audit logging infrastructure to the codebase, including middleware for capturing mutating API actions, event recording, background processing with retry/fallback logic, and configuration for enabling/disabling audit logging. It also adds unit tests to ensure the reliability of each component. The most important changes are grouped below.
Audit Logging Core Implementation
AuditActionLoggingMiddlewareto capture and record mutating HTTP actions (POST, PUT, PATCH, DELETE) as audit events, including client ID, IP address, HTTP verb, URL, and status code. Handles both successful and failed requests.AuditEventRecorderandIAuditEventRecorderfor recording audit events, supporting tenant-aware and fallback connection string resolution, and fail-open error handling. [1] [2]AuditEventandAuditEventTypeto standardize audit event data and event types (authentication success/failure and actions). [1] [2]AuditLogBackgroundServiceto process audit events from a bounded channel, with retry logic and fallback logging on repeated failures.AuditLogChannelfor thread-safe, bounded, single-reader/multi-writer event queuing.AuditLoggingSettingsto enable/disable audit logging.AuditLogentity for persistence mapping of audit events.Test Coverage
AuditActionLoggingMiddleware,AuditEventRecorder, andAuditLogBackgroundServiceto verify correct event recording, connection string resolution, error handling, and retry/fallback behavior. [1] [2] [3]Assembly Configuration
AssemblyInfo.csto allow internal visibility for unit tests.