refactor: ScadaBridge module options registration -> AddValidatedOptions; clarify De Morgan predicates

This commit is contained in:
Joseph Doherty
2026-06-01 22:49:41 -04:00
parent 6dbbc7ad04
commit 9668a4e84a
3 changed files with 17 additions and 5 deletions
@@ -39,11 +39,15 @@ public sealed class AuditLogOptionsValidator : OptionsValidatorBase<AuditLogOpti
$"must be >= {nameof(AuditLogOptions.DefaultCapBytes)} ({options.DefaultCapBytes}); " +
"the error-row cap is intended to capture more detail than the happy-path summary.");
// Valid when RetentionDays is within [Min, Max] inclusive. The De Morgan'd
// guard !(below Min OR above Max) is equivalent to (>= Min AND <= Max).
builder.RequireThat(
!(options.RetentionDays < MinRetentionDays || options.RetentionDays > MaxRetentionDays),
$"AuditLog:{nameof(AuditLogOptions.RetentionDays)} ({options.RetentionDays}) " +
$"must be in [{MinRetentionDays}, {MaxRetentionDays}] days.");
// Valid when InboundMaxBytes is within [Min, Max] inclusive. The De Morgan'd
// guard !(below Min OR above Max) is equivalent to (>= Min AND <= Max).
builder.RequireThat(
!(options.InboundMaxBytes < MinInboundMaxBytes || options.InboundMaxBytes > MaxInboundMaxBytes),
$"AuditLog:{nameof(AuditLogOptions.InboundMaxBytes)} ({options.InboundMaxBytes}) " +
@@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.Configuration;
using ZB.MOM.WW.ScadaBridge.AuditLog.Central;
using ZB.MOM.WW.ScadaBridge.AuditLog.Configuration;
using ZB.MOM.WW.ScadaBridge.AuditLog.Payload;
@@ -62,10 +62,12 @@ public static class ServiceCollectionExtensions
ArgumentNullException.ThrowIfNull(config);
// M1: top-level AuditLogOptions + validator (redaction policy, payload caps, etc.).
services.AddOptions<AuditLogOptions>()
.Bind(config.GetSection(ConfigSectionName))
.ValidateOnStart();
services.AddSingleton<IValidateOptions<AuditLogOptions>, AuditLogOptionsValidator>();
// Collapsed onto the shared ZB.MOM.WW.Configuration helper: it binds the
// "AuditLog" section, registers the validator, and enables ValidateOnStart in
// one call. Same section path as before; AddAuditLog is call-once per
// collection, and the helper's TryAddEnumerable is idempotent for the
// validator (a strict improvement over the previous AddSingleton).
services.AddValidatedOptions<AuditLogOptions, AuditLogOptionsValidator>(config, ConfigSectionName);
// M5 Bundle A: payload filter — truncates oversized RequestSummary /
// ResponseSummary / ErrorDetail / Extra fields between event
@@ -35,6 +35,12 @@ public sealed class HealthMonitoringOptionsValidator : OptionsValidatorBase<Heal
$"ScadaBridge:HealthMonitoring:CentralOfflineTimeout must be a positive duration " +
$"(was {options.CentralOfflineTimeout}).");
// Valid when CentralOfflineTimeout >= OfflineTimeout (both already
// required to be positive above). The De Morgan'd guard !(both positive
// AND Central < Offline) is true unless BOTH timeouts are positive and
// Central is strictly smaller — so it stays silent when either field is
// non-positive, leaving that failure to the dedicated positive-duration
// checks above rather than double-firing here.
builder.RequireThat(
!(options.OfflineTimeout > TimeSpan.Zero
&& options.CentralOfflineTimeout > TimeSpan.Zero