feat(audit): persist OPC UA certificate-trust decisions to the central audit log (ScadaBridge#43)
New AuditChannel.Security with AuditKind.CertTrust / CertTrustRemove (appended, ordinals stable). Both central entry points - the management actor handlers and the Central UI CertManagementService - write a best-effort ICentralAuditWriter row after the site outcome is known (Delivered when all reachable site nodes acked, Failed otherwise, incl. relay timeouts), naming actor, site, thumbprint and connection. Shared builder: CertTrustAuditEvents. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -5621,6 +5621,46 @@ public class ManagementActorTests : TestKit, IDisposable
|
||||
Assert.Equal("SITE1", stub.LastTrustSite);
|
||||
}
|
||||
|
||||
/// <summary>Gitea #43: an admin trust decision is persisted to the central audit log with the real actor and outcome.</summary>
|
||||
[Fact]
|
||||
public void TrustServerCert_Admin_WritesCentralAuditRow()
|
||||
{
|
||||
var writer = Substitute.For<ICentralAuditWriter>();
|
||||
_services.AddSingleton(writer);
|
||||
_services.AddSingleton<CommunicationService>(new StubCommunicationService());
|
||||
var actor = CreateActor();
|
||||
|
||||
actor.Tell(Envelope(new TrustServerCertCommand("conn", "ZGVy", "AB12", "SITE1"), "Administrator"));
|
||||
|
||||
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||
var evt = Assert.Single(writer.ReceivedCalls()
|
||||
.Where(c => c.GetMethodInfo().Name == nameof(ICentralAuditWriter.WriteAsync))
|
||||
.Select(c => (ZB.MOM.WW.Audit.AuditEvent)c.GetArguments()[0]!));
|
||||
Assert.Equal("Security", evt.Category);
|
||||
Assert.Contains("\"kind\":\"CertTrust\"", evt.DetailsJson);
|
||||
Assert.Contains("\"status\":\"Delivered\"", evt.DetailsJson);
|
||||
Assert.Equal("SITE1/AB12", evt.Target);
|
||||
Assert.False(string.IsNullOrEmpty(evt.Actor));
|
||||
}
|
||||
|
||||
/// <summary>Gitea #43: a removal is audited too.</summary>
|
||||
[Fact]
|
||||
public void RemoveServerCert_Admin_WritesCentralAuditRow()
|
||||
{
|
||||
var writer = Substitute.For<ICentralAuditWriter>();
|
||||
_services.AddSingleton(writer);
|
||||
_services.AddSingleton<CommunicationService>(new StubCommunicationService());
|
||||
var actor = CreateActor();
|
||||
|
||||
actor.Tell(Envelope(new RemoveServerCertCommand("AB12", "SITE1"), "Administrator"));
|
||||
|
||||
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||
var evt = Assert.Single(writer.ReceivedCalls()
|
||||
.Where(c => c.GetMethodInfo().Name == nameof(ICentralAuditWriter.WriteAsync))
|
||||
.Select(c => (ZB.MOM.WW.Audit.AuditEvent)c.GetArguments()[0]!));
|
||||
Assert.Contains("\"kind\":\"CertTrustRemove\"", evt.DetailsJson);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that remove server cert, when admin, relays to site.</summary>
|
||||
[Fact]
|
||||
public void RemoveServerCert_Admin_RelaysToSite()
|
||||
|
||||
Reference in New Issue
Block a user