using Microsoft.Extensions.Options; namespace ScadaLink.AuditLog.Configuration; /// /// Validates on startup. The caps drive payload /// truncation in the M2+ writers, so an unset/zero cap would let arbitrarily /// large blobs into the central AuditLog table. /// must be at least as large as /// because the error cap is meant to capture more detail than the /// happy-path summary, not less. is /// bounded to [30, 3650] to keep purge windows sane: too short would /// drop in-flight investigations, too long would defeat the partition-switch /// purge's purpose. /// public sealed class AuditLogOptionsValidator : IValidateOptions { /// Inclusive lower bound for . public const int MinRetentionDays = 30; /// Inclusive upper bound for . public const int MaxRetentionDays = 3650; /// public ValidateOptionsResult Validate(string? name, AuditLogOptions options) { ArgumentNullException.ThrowIfNull(options); var failures = new List(); if (options.DefaultCapBytes <= 0) { failures.Add( $"AuditLog:{nameof(AuditLogOptions.DefaultCapBytes)} ({options.DefaultCapBytes}) " + "must be > 0; it drives payload-summary truncation in audit writers."); } if (options.ErrorCapBytes < options.DefaultCapBytes) { failures.Add( $"AuditLog:{nameof(AuditLogOptions.ErrorCapBytes)} ({options.ErrorCapBytes}) " + $"must be >= {nameof(AuditLogOptions.DefaultCapBytes)} ({options.DefaultCapBytes}); " + "the error-row cap is intended to capture more detail than the happy-path summary."); } if (options.RetentionDays < MinRetentionDays || options.RetentionDays > MaxRetentionDays) { failures.Add( $"AuditLog:{nameof(AuditLogOptions.RetentionDays)} ({options.RetentionDays}) " + $"must be in [{MinRetentionDays}, {MaxRetentionDays}] days."); } return failures.Count == 0 ? ValidateOptionsResult.Success : ValidateOptionsResult.Fail(failures); } }