Add audit logs.
ci-cd-vm / ci-cd (push) Successful in 4m2s

This commit is contained in:
Chris Chen
2026-06-23 12:13:47 -07:00
parent 870eeec82a
commit 62592c29ae
106 changed files with 2522 additions and 311 deletions
+30 -1
View File
@@ -6,11 +6,15 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Extensions.Logging.Abstractions;
using ROLAC.API.Data;
using ROLAC.API.Data.Interceptors;
using ROLAC.API.Data.Logging;
using ROLAC.API.Entities;
using ROLAC.API.Json;
using ROLAC.API.Middleware;
using ROLAC.API.Services;
using ROLAC.API.Services.Logging;
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
@@ -19,10 +23,31 @@ var config = builder.Configuration;
// Database
// ---------------------------------------------------------------------------
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<CurrentUserAccessor>();
builder.Services.AddScoped<AuditSaveChangesInterceptor>();
builder.Services.AddScoped<AuditLogInterceptor>();
builder.Services.AddDbContext<AppDbContext>((sp, opt) =>
opt.UseNpgsql(config.GetConnectionString("DefaultConnection"))
.AddInterceptors(sp.GetRequiredService<AuditSaveChangesInterceptor>()));
.AddInterceptors(
sp.GetRequiredService<AuditSaveChangesInterceptor>(),
sp.GetRequiredService<AuditLogInterceptor>()));
// Dedicated context for log writes — NO interceptors and a silent logger factory, so persisting
// a log row produces no log events the DB sink would pick up (breaks recursion / log-storms).
builder.Services.AddDbContext<LogDbContext>(opt =>
opt.UseNpgsql(config.GetConnectionString("DefaultConnection"))
.UseLoggerFactory(NullLoggerFactory.Instance));
// ---------------------------------------------------------------------------
// System + audit logging (custom EF DB sink)
// ---------------------------------------------------------------------------
builder.Services.Configure<DatabaseLoggerOptions>(config.GetSection("Logging:Database"));
builder.Services.AddSingleton<SystemLogQueue>();
builder.Services.AddSingleton<ILoggerProvider, DbLoggerProvider>();
builder.Services.AddHostedService<LogWriterBackgroundService>();
builder.Services.AddScoped<IAuditLogger, AuditLogger>();
builder.Services.AddScoped<ISystemLogQueryService, SystemLogQueryService>();
builder.Services.AddScoped<IAuditLogQueryService, AuditLogQueryService>();
// ---------------------------------------------------------------------------
// Identity (API-only — no cookie auth; JWT is the default scheme)
@@ -200,6 +225,10 @@ app.UseForwardedHeaders(new ForwardedHeadersOptions
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
// First in the pipeline: catch every unhandled exception, log it to SystemLogs, and return
// a clean problem+json. Placed after UseForwardedHeaders so the logged client IP is correct.
app.UseMiddleware<ExceptionHandlingMiddleware>();
// Apply migrations + seed on startup
using (var scope = app.Services.CreateScope())
{