feat(centralui): cert-management UI + Trust action + site relay (T17)

This commit is contained in:
Joseph Doherty
2026-06-18 03:53:32 -04:00
parent 2d139442ba
commit 384204b71a
12 changed files with 858 additions and 13 deletions
@@ -161,6 +161,18 @@ public class SiteCommunicationActor : ReceiveActor, IWithTimers
// children holding the live OPC UA sessions.
Receive<ReadTagValuesCommand>(msg => _deploymentManagerProxy.Forward(msg));
// OPC UA server-certificate trust management (T17 / D6) — forward to the
// Deployment Manager singleton, which owns the cross-node trust broadcast.
// The trusted-peer PKI store is node-wide per site node, so a trust/remove
// decision must reach BOTH nodes' CertStoreActor; the singleton broadcasts
// to every site node (list answers from the singleton's own node). The
// singleton always lands on the active node, the same routing rationale as
// BrowseNodeCommand above. Forward preserves the central Ask sender so the
// CertTrustResult routes straight back to the waiting Ask.
Receive<TrustServerCertCommand>(msg => _deploymentManagerProxy.Forward(msg));
Receive<ListServerCertsCommand>(msg => _deploymentManagerProxy.Forward(msg));
Receive<RemoveServerCertCommand>(msg => _deploymentManagerProxy.Forward(msg));
// Pattern 7: Remote Queries
Receive<EventLogQueryRequest>(msg =>
{
@@ -416,6 +416,73 @@ public class CommunicationService
envelope, _options.QueryTimeout, cancellationToken);
}
// ── OPC UA Server-Certificate Trust (T17 / D6 — node-wide site PKI store) ──
/// <summary>
/// Asks the owning site to trust an OPC UA server certificate at every site
/// node. Backs the CentralUI cert-management Trust action. The site Deployment
/// Manager singleton broadcasts the captured DER bytes to every site node's
/// <c>CertStoreActor</c>; the result reflects whether every reachable node
/// acked. The Ask is bounded by <see cref="CommunicationOptions.QueryTimeout"/>,
/// mirroring <see cref="BrowseNodeAsync"/> and the other interactive
/// design-time site queries.
/// </summary>
/// <param name="siteId">The target site identifier.</param>
/// <param name="command">The trust-server-cert command (connection name + DER + thumbprint).</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The cert-trust result (per-node aggregate success + first error).</returns>
public Task<CertTrustResult> TrustServerCertAsync(
string siteId,
TrustServerCertCommand command,
CancellationToken cancellationToken = default)
{
var envelope = new SiteEnvelope(siteId, command);
return GetActor().Ask<CertTrustResult>(
envelope, _options.QueryTimeout, cancellationToken);
}
/// <summary>
/// Asks the owning site to list the certificates in its trusted-peer and
/// rejected PKI stores. Backs the CentralUI cert-management list page. Answered
/// by the site Deployment Manager singleton from its own node (the store is
/// node-wide per site node). The Ask is bounded by
/// <see cref="CommunicationOptions.QueryTimeout"/>.
/// </summary>
/// <param name="siteId">The target site identifier.</param>
/// <param name="command">The list-server-certs command.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The cert-trust result carrying the listed certificates on success.</returns>
public Task<CertTrustResult> ListServerCertsAsync(
string siteId,
ListServerCertsCommand command,
CancellationToken cancellationToken = default)
{
var envelope = new SiteEnvelope(siteId, command);
return GetActor().Ask<CertTrustResult>(
envelope, _options.QueryTimeout, cancellationToken);
}
/// <summary>
/// Asks the owning site to remove a previously-trusted OPC UA server
/// certificate from every site node, identified by thumbprint. Backs the
/// CentralUI cert-management Remove action. The site Deployment Manager
/// singleton broadcasts the removal to every site node's <c>CertStoreActor</c>.
/// The Ask is bounded by <see cref="CommunicationOptions.QueryTimeout"/>.
/// </summary>
/// <param name="siteId">The target site identifier.</param>
/// <param name="command">The remove-server-cert command (thumbprint).</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The cert-trust result (per-node aggregate success + first error).</returns>
public Task<CertTrustResult> RemoveServerCertAsync(
string siteId,
RemoveServerCertCommand command,
CancellationToken cancellationToken = default)
{
var envelope = new SiteEnvelope(siteId, command);
return GetActor().Ask<CertTrustResult>(
envelope, _options.QueryTimeout, cancellationToken);
}
// ── Test Bindings (one-shot live read of bound tags) ──
/// <summary>