feat(audit): ScadaBridge IAuditActorAccessor + wire audit Actor from Auth principal at authenticated emit sites (Phase 3)
This commit is contained in:
+64
@@ -0,0 +1,64 @@
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Types.Audit;
|
||||
|
||||
/// <summary>
|
||||
/// Phase 3 (wire audit Actor from the Auth principal): the
|
||||
/// <see cref="ScadaBridgeAuditEventFactory"/> is the single construction point and
|
||||
/// records the <c>actor</c> the CALLER passes in — it never injects a principal of
|
||||
/// its own. These tests pin that contract so the per-emit-site decision holds:
|
||||
/// authenticated emit sites pass the principal's actor (sourced via
|
||||
/// <c>IAuditActorAccessor</c> at the inbound middleware), while system-originated
|
||||
/// emitters (notification / script DB-outbound) keep passing their own system/script
|
||||
/// actor unchanged. The factory does not blur the two.
|
||||
/// </summary>
|
||||
public class ScadaBridgeAuditEventFactoryActorTests
|
||||
{
|
||||
[Theory]
|
||||
// Mirrors the literal system actors the outbound emitters pass:
|
||||
// NotificationOutboxActor → "system"; AuditingDbCommand → the source script.
|
||||
[InlineData("system")]
|
||||
[InlineData("order-sync.caspx")]
|
||||
public void SystemOriginatedEmit_PreservesCallerActor_Verbatim(string systemActor)
|
||||
{
|
||||
var evt = ScadaBridgeAuditEventFactory.Create(
|
||||
channel: AuditChannel.Notification,
|
||||
kind: AuditKind.NotifyDeliver,
|
||||
status: AuditStatus.Delivered,
|
||||
actor: systemActor);
|
||||
|
||||
// The system emit keeps its system/script actor — the factory does not
|
||||
// overwrite it with any authenticated principal.
|
||||
Assert.Equal(systemActor, evt.Actor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AuthenticatedEmit_PreservesCallerActor_Verbatim()
|
||||
{
|
||||
// An authenticated emit site (e.g. the inbound middleware) passes the
|
||||
// principal's actor; the factory records it as-is.
|
||||
var evt = ScadaBridgeAuditEventFactory.Create(
|
||||
channel: AuditChannel.ApiInbound,
|
||||
kind: AuditKind.InboundRequest,
|
||||
status: AuditStatus.Delivered,
|
||||
actor: "alice");
|
||||
|
||||
Assert.Equal("alice", evt.Actor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NullActor_MapsToEmptyString_OnCanonicalRecord()
|
||||
{
|
||||
// The canonical AuditEvent.Actor is a non-null string; a null actor (no
|
||||
// authenticated principal AND no system fallback supplied) maps to empty.
|
||||
// AuditRowProjection then surfaces empty as null at the row boundary.
|
||||
var evt = ScadaBridgeAuditEventFactory.Create(
|
||||
channel: AuditChannel.ApiInbound,
|
||||
kind: AuditKind.InboundAuthFailure,
|
||||
status: AuditStatus.Failed,
|
||||
actor: null);
|
||||
|
||||
Assert.Equal(string.Empty, evt.Actor);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user