feat(auditlog): IAuditPayloadFilter contract (#23 M5)
This commit is contained in:
30
src/ScadaLink.AuditLog/Payload/IAuditPayloadFilter.cs
Normal file
30
src/ScadaLink.AuditLog/Payload/IAuditPayloadFilter.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using ScadaLink.Commons.Entities.Audit;
|
||||||
|
|
||||||
|
namespace ScadaLink.AuditLog.Payload;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters an <see cref="AuditEvent"/> between construction and persistence —
|
||||||
|
/// truncates oversized payload fields, applies header/body/SQL-parameter
|
||||||
|
/// redaction, sets <see cref="AuditEvent.PayloadTruncated"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// Pure function: returns a filtered COPY of the input via <c>with</c>
|
||||||
|
/// expressions; never throws (over-redacts on internal failure and increments
|
||||||
|
/// the <c>AuditRedactionFailure</c> health metric).
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Wired in M5 between event construction and the writer chain
|
||||||
|
/// (<c>FallbackAuditWriter.WriteAsync</c>, <c>CentralAuditWriter.WriteAsync</c>,
|
||||||
|
/// and the <c>AuditLogIngestActor</c> handlers).
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public interface IAuditPayloadFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Apply the configured truncation + redaction policy to <paramref name="rawEvent"/>
|
||||||
|
/// and return a filtered copy. MUST NOT throw — on internal failure, over-redact
|
||||||
|
/// and surface the failure via the audit-redaction-failure health metric.
|
||||||
|
/// </summary>
|
||||||
|
AuditEvent Apply(AuditEvent rawEvent);
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using ScadaLink.AuditLog.Payload;
|
||||||
|
using ScadaLink.Commons.Entities.Audit;
|
||||||
|
|
||||||
|
namespace ScadaLink.AuditLog.Tests.Payload;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bundle A (M5-T1) contract test for <see cref="IAuditPayloadFilter"/>. The
|
||||||
|
/// interface is the seam between event construction and writer persistence;
|
||||||
|
/// later bundles register the production implementation as a singleton and
|
||||||
|
/// invoke it from the site/central writer paths. We pin the surface area here
|
||||||
|
/// via reflection so accidental signature drift breaks the build before the
|
||||||
|
/// downstream wiring goes red.
|
||||||
|
/// </summary>
|
||||||
|
public class PayloadFilterContractTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Interface_Exists_InPayloadNamespace()
|
||||||
|
{
|
||||||
|
var type = typeof(IAuditPayloadFilter);
|
||||||
|
|
||||||
|
Assert.True(type.IsInterface, "IAuditPayloadFilter must be an interface");
|
||||||
|
Assert.Equal("ScadaLink.AuditLog.Payload", type.Namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Apply_Method_HasDocumentedSignature()
|
||||||
|
{
|
||||||
|
var type = typeof(IAuditPayloadFilter);
|
||||||
|
|
||||||
|
var method = type.GetMethod(
|
||||||
|
"Apply",
|
||||||
|
BindingFlags.Instance | BindingFlags.Public,
|
||||||
|
binder: null,
|
||||||
|
types: new[] { typeof(AuditEvent) },
|
||||||
|
modifiers: null);
|
||||||
|
|
||||||
|
Assert.NotNull(method);
|
||||||
|
Assert.Equal(typeof(AuditEvent), method!.ReturnType);
|
||||||
|
|
||||||
|
var parameters = method.GetParameters();
|
||||||
|
Assert.Single(parameters);
|
||||||
|
Assert.Equal("rawEvent", parameters[0].Name);
|
||||||
|
Assert.Equal(typeof(AuditEvent), parameters[0].ParameterType);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Interface_DeclaresExactlyOneMethod()
|
||||||
|
{
|
||||||
|
var type = typeof(IAuditPayloadFilter);
|
||||||
|
var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
|
||||||
|
.Where(m => !m.IsSpecialName)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
Assert.Single(methods);
|
||||||
|
Assert.Equal("Apply", methods[0].Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user