075c0e69da
v2-ci / build (push) Failing after 40s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Introduces the IAuditActorAccessor seam and HttpAuditActorAccessor impl so the ZB.MOM.WW.Audit.AuditEvent Actor field can be sourced from the authenticated Blazor cookie principal (ZbClaimTypes.Username) when structured emitters are added. Adds the AuditActor.Resolve static helper (accessor value → SystemFallback/"system") as the canonical pattern for future emit sites. Wires DI in AddOtOpcUaAuth (TryAddScoped) with AddHttpContextAccessor(). The structured AuditEvent path remains DORMANT — no live emit sites exist; seam is forward-looking. SP-based audit path left untouched. 9 new unit tests all green; Security (54) and ControlPlane (45) test suites fully pass.
82 lines
2.9 KiB
C#
82 lines
2.9 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Security.Audit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Security.Tests.Audit;
|
|
|
|
/// <summary>
|
|
/// Unit tests for <see cref="AuditActor"/> — the static resolution helper that sources the
|
|
/// <c>Actor</c> field of a canonical <c>ZB.MOM.WW.Audit.AuditEvent</c> from the current
|
|
/// HTTP principal and falls back to a configurable value when no principal is available.
|
|
/// </summary>
|
|
public sealed class AuditActorTests
|
|
{
|
|
/// <summary>
|
|
/// <see cref="AuditActor.Resolve(IAuditActorAccessor?)"/> returns the accessor's value
|
|
/// when the accessor returns a non-null string.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Resolve_returns_accessor_value_when_present()
|
|
{
|
|
var accessor = new StubAccessor("alice");
|
|
|
|
AuditActor.Resolve(accessor).ShouldBe("alice");
|
|
}
|
|
|
|
/// <summary>
|
|
/// <see cref="AuditActor.Resolve(IAuditActorAccessor?)"/> returns
|
|
/// <see cref="AuditActor.SystemFallback"/> when the accessor returns null
|
|
/// (unauthenticated / no HTTP context).
|
|
/// </summary>
|
|
[Fact]
|
|
public void Resolve_returns_system_fallback_when_accessor_returns_null()
|
|
{
|
|
var accessor = new StubAccessor(null);
|
|
|
|
AuditActor.Resolve(accessor).ShouldBe(AuditActor.SystemFallback);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <see cref="AuditActor.Resolve(IAuditActorAccessor?)"/> returns
|
|
/// <see cref="AuditActor.SystemFallback"/> when the accessor reference itself is null
|
|
/// (e.g. in a background/non-HTTP context where DI did not inject the accessor).
|
|
/// </summary>
|
|
[Fact]
|
|
public void Resolve_returns_system_fallback_when_accessor_is_null()
|
|
{
|
|
AuditActor.Resolve(null).ShouldBe(AuditActor.SystemFallback);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <see cref="AuditActor.Resolve(IAuditActorAccessor?,string)"/> uses the explicit
|
|
/// fallback string rather than <see cref="AuditActor.SystemFallback"/> when the accessor
|
|
/// returns null.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Resolve_uses_explicit_fallback_when_accessor_returns_null()
|
|
{
|
|
var accessor = new StubAccessor(null);
|
|
|
|
AuditActor.Resolve(accessor, "scheduler").ShouldBe("scheduler");
|
|
}
|
|
|
|
/// <summary>
|
|
/// <see cref="AuditActor.Resolve(IAuditActorAccessor?,string)"/> prefers the accessor's
|
|
/// value over the explicit fallback when the accessor returns a non-null string.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Resolve_prefers_accessor_value_over_explicit_fallback()
|
|
{
|
|
var accessor = new StubAccessor("bob");
|
|
|
|
AuditActor.Resolve(accessor, "scheduler").ShouldBe("bob");
|
|
}
|
|
|
|
// ── stub ──────────────────────────────────────────────────────────────────────
|
|
|
|
private sealed class StubAccessor(string? value) : IAuditActorAccessor
|
|
{
|
|
public string? CurrentActor { get; } = value;
|
|
}
|
|
}
|