feat(auditlog): add AuditLog:InboundMaxBytes option (default 1 MiB, [8 KiB, 16 MiB])

This commit is contained in:
Joseph Doherty
2026-05-23 05:39:50 -04:00
parent 441ec087a7
commit c5b27361c0
4 changed files with 82 additions and 1 deletions

View File

@@ -45,7 +45,8 @@ public class AuditLogOptionsBindingTests
"RedactSqlParamsMatching": "@token|@secret"
}
},
"RetentionDays": 180
"RetentionDays": 180,
"InboundMaxBytes": 524288
}
}
""";
@@ -64,6 +65,7 @@ public class AuditLogOptionsBindingTests
Assert.Equal(4096, opts.DefaultCapBytes);
Assert.Equal(32768, opts.ErrorCapBytes);
Assert.Equal(180, opts.RetentionDays);
Assert.Equal(524_288, opts.InboundMaxBytes);
// HeaderRedactList: the Microsoft.Extensions.Configuration list binder
// APPENDS to the default list, so we assert containment rather than

View File

@@ -0,0 +1,53 @@
using ScadaLink.AuditLog.Configuration;
namespace ScadaLink.AuditLog.Tests.Configuration;
/// <summary>
/// Task 1 of <c>docs/plans/2026-05-23-inbound-api-full-response-audit.md</c>:
/// pins the <see cref="AuditLogOptions.InboundMaxBytes"/> default to 1 MiB and
/// the validator bounds to <c>[8 KiB, 16 MiB]</c>. The inbound channel needs a
/// much larger ceiling than the 8 KiB / 64 KiB default/error caps that other
/// channels use, but unbounded would let any caller flood the central
/// <c>AuditLog</c> table with arbitrarily large bodies — hence the upper bound.
/// Companion to <see cref="AuditLogOptionsTests"/> which covers the existing
/// cap-bytes + retention invariants.
/// </summary>
public class AuditLogOptionsValidatorTests
{
[Fact]
public void Validate_InboundMaxBytes_DefaultOptions_IsOneMebibyte()
{
// The doc'd default per docs/plans/2026-05-23-inbound-api-full-response-audit-design.md
// is 1 048 576 bytes (1 MiB). Pin it so a config drift is a test failure,
// not a silent operational surprise.
var opts = new AuditLogOptions();
Assert.Equal(1_048_576, opts.InboundMaxBytes);
}
[Theory]
[InlineData(8_192)] // documented min
[InlineData(1_048_576)] // default
[InlineData(16_777_216)] // documented max
public void Validate_InboundMaxBytes_InRange_Passes(int value)
{
var validator = new AuditLogOptionsValidator();
var opts = new AuditLogOptions { InboundMaxBytes = value };
Assert.True(validator.Validate(null, opts).Succeeded);
}
[Theory]
[InlineData(0)]
[InlineData(8_191)]
[InlineData(16_777_217)]
[InlineData(int.MaxValue)]
public void Validate_InboundMaxBytes_OutOfRange_Fails(int value)
{
var validator = new AuditLogOptionsValidator();
var opts = new AuditLogOptions { InboundMaxBytes = value };
var result = validator.Validate(null, opts);
Assert.False(result.Succeeded);
Assert.Contains(
result.Failures!,
f => f.Contains(nameof(AuditLogOptions.InboundMaxBytes), StringComparison.Ordinal));
}
}