using ZB.MOM.WW.OtOpcUa.Core.Authorization; namespace ZB.MOM.WW.OtOpcUa.Server.Security; /// /// Maps a driver-side full reference (e.g. "TestMachine_001/Oven/SetPoint") to the /// the Phase 6.2 evaluator walks. Today a simplified resolver that /// returns a cluster-scoped + tag-only scope — the deeper UnsArea / UnsLine / Equipment /// path lookup from the live Configuration DB is a Stream C.12 follow-up. /// /// /// The flat cluster-level scope is sufficient for v2 GA because Phase 6.2 ACL grants /// at the Cluster scope cascade to every tag below (decision #129 — additive grants). The /// finer hierarchy only matters when operators want per-area or per-equipment grants; /// those still work for Cluster-level grants, and landing the finer resolution in a /// follow-up doesn't regress the base security model. /// /// Thread-safety: the resolver is stateless once constructed. Callers may cache a /// single instance per DriverNodeManager without locks. /// public sealed class NodeScopeResolver { private readonly string _clusterId; public NodeScopeResolver(string clusterId) { ArgumentException.ThrowIfNullOrWhiteSpace(clusterId); _clusterId = clusterId; } /// /// Resolve a node scope for the given driver-side . /// Phase 1 shape: returns ClusterId + TagId = fullReference only; /// NamespaceId / UnsArea / UnsLine / Equipment stay null. A future resolver will /// join against the Configuration DB to populate the full path. /// public NodeScope Resolve(string fullReference) { ArgumentException.ThrowIfNullOrWhiteSpace(fullReference); return new NodeScope { ClusterId = _clusterId, TagId = fullReference, Kind = NodeHierarchyKind.Equipment, }; } }