review(OpcUaServer): record findings + fix stale node-manager/host docs

First review of the v2 OPC UA core at HEAD 7286d320. 6 findings (2 Medium, 4 Low).
OpcUaServer-006 fixed (stale NodeManager/ApplicationHost XML docs). 001-004 deferred
(cross-module: Runtime publish-actor / Core.Abstractions history contract / Wonderware
boundary semantics, or latent-only). 005 re-triaged Won't-Fix (coverage already exists).
High-scrutiny paths (Lock discipline, OnWriteValue fire-and-forget, WriteOperate/AlarmAck
gates, HistoryRead AccessLevel bits) verified correct.
This commit is contained in:
Joseph Doherty
2026-06-19 10:37:00 -04:00
parent e4abe186a1
commit bac6613dd2
3 changed files with 231 additions and 13 deletions
@@ -83,13 +83,12 @@ public sealed class OpcUaApplicationHostOptions
/// <summary>
/// Thin facade over the OPC Foundation .NET Standard SDK's application bootstrap.
/// Owns the <see cref="ApplicationInstance"/> + <see cref="ApplicationConfiguration"/> lifetime
/// and starts a <see cref="StandardServer"/> with the supplied node-manager factory.
///
/// Full extraction from legacy <c>OtOpcUa.Server</c> (security wiring, ScriptedAlarmDescriptor
/// pipeline, ResilienceController, history backend, observability hooks) is tracked as
/// follow-up F13. This facade compiles + boots the SDK so Task 53 can wire the fused Host's
/// driver-role startup against it.
/// Owns the <see cref="ApplicationInstance"/> + <see cref="ApplicationConfiguration"/> lifetime,
/// builds the <see cref="ApplicationConfiguration"/> programmatically (security profiles + user
/// token policies + PKI stores), starts a <see cref="StandardServer"/>, attaches the
/// <c>ImpersonateUser</c> hook for UserName-token authentication via
/// <see cref="IOpcUaUserAuthenticator"/>, and publishes the redundancy peer URIs through
/// <c>Server.ServerArray</c>. See <c>docs/OpcUaServer.md</c> and <c>docs/security.md</c>.
/// </summary>
public sealed class OpcUaApplicationHost : IAsyncDisposable
{
@@ -419,8 +418,11 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
/// <summary>
/// Anonymous + UserName token policies. UserName tokens are always SDK-encrypted with
/// the server certificate (see docs/security.md "UserName token encryption") so the
/// policy works on None endpoints too. F13c will plug a real LDAP-bound validator into
/// <c>StandardServer.SessionManager.ImpersonateUser</c>.
/// policy works on None endpoints too. The real LDAP-bound validator is wired through
/// <see cref="IOpcUaUserAuthenticator"/> on <c>StandardServer.SessionManager.ImpersonateUser</c>
/// (see <see cref="AttachUserAuthenticator"/> / <see cref="HandleImpersonation"/>); the Host
/// project supplies the LDAP adapter, and <see cref="NullOpcUaUserAuthenticator"/> denies all
/// UserName logins when none is registered.
/// </summary>
internal static IEnumerable<UserTokenPolicy> BuildUserTokenPolicies()
{
@@ -24,10 +24,15 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer;
/// materialise as real OPC UA Variable updates that clients can browse + subscribe to.
///
/// Node-id encoding uses the manager's default namespace + the caller-supplied string id
/// as the identifier portion (e.g. <c>"ns=2;s=eq-1/temp"</c>). Equipment-folder hierarchy
/// and OPC UA type metadata still come from the AddressSpaceApplier / EquipmentNodeWalker
/// integration (F14b, tracked under #85) — this manager treats every id as a flat
/// <see cref="BaseDataVariableState"/> under the namespace root.
/// as the identifier portion (e.g. <c>"ns=2;s=eq-1/temp"</c>). Beyond lazily-created flat
/// variables, the manager also materialises the full UNS Area/Line/Equipment folder hierarchy
/// (<see cref="EnsureFolder"/>), typed equipment-tag variables with the correct built-in
/// <c>DataType</c> / array shape / access levels (<see cref="EnsureVariable"/>), historized
/// nodes (the <c>HistoryRead</c> access bit + HistoryRead overrides), and real Part 9
/// <see cref="AlarmConditionState"/> nodes (<see cref="MaterialiseAlarmCondition"/>). The
/// <c>AddressSpaceApplier</c> drives these passes from the composed deployment artifact;
/// the legacy <c>EquipmentNodeWalker</c> server-side integration was retired in favour of the
/// (composer → applier → sink → node-manager) chain.
/// </summary>
public sealed class OtOpcUaNodeManager : CustomNodeManager2
{