perf(audit): bounded async audit writer with batched inserts, one-time bootstrap, retention sweep

This commit is contained in:
Joseph Doherty
2026-08-15 12:17:22 -04:00
parent 6c5218913b
commit e2ac5d117a
9 changed files with 845 additions and 38 deletions
@@ -100,6 +100,13 @@ public sealed class GatewayOptionsValidator : OptionsValidatorBase<GatewayOption
"MxGateway:Security:ApiKeyFailureTrackedPeers must be greater than zero.",
builder);
// Retention must be at least one day: 0 would sweep the audit table on every pass, which
// is a way to silently disable auditing rather than an expression of intent.
AddIfNotPositive(
options.AuditRetentionDays,
"MxGateway:Security:AuditRetentionDays must be greater than zero (at least one day of audit history is retained).",
builder);
// The two-layer limiter knobs (SEC-31) accept 0 as "disable this layer": a zero aggregate
// limit turns off cross-peer counting, and a zero probe interval restores absolute blocking.
// Negatives express no intent.
@@ -88,4 +88,13 @@ public sealed class SecurityOptions
/// ceiling of twice this value. Default is 4096.
/// </summary>
public int ApiKeyFailureTrackedPeers { get; init; } = 4096;
/// <summary>
/// Gets how many days of canonical audit history the gateway keeps. The audit drain sweeps
/// <c>audit_event</c> once at startup and hourly thereafter, deleting rows older than this
/// window; without it the table grows without bound in the same SQLite file the
/// authentication hot path reads. Must be greater than zero — audit retention cannot be
/// disabled by configuration, only widened. Default is 90 days.
/// </summary>
public int AuditRetentionDays { get; init; } = 90;
}