docs: backfill XML documentation across 756 files
v2-ci / build (push) Failing after 1m43s
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
v2-ci / build (push) Failing after 1m43s
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
Adds <summary>, <param>, <typeparam>, and <inheritdoc/> tags to public members surfaced by commentchecker — resolves 5,847 of 5,869 issues (99.6%) across three /fixdocs passes.
This commit is contained in:
@@ -15,12 +15,15 @@ public sealed record AuthorizationDecision(
|
||||
AuthorizationVerdict Verdict,
|
||||
IReadOnlyList<MatchedGrant> Provenance)
|
||||
{
|
||||
/// <summary>Gets a value indicating whether the authorization decision allows the operation.</summary>
|
||||
public bool IsAllowed => Verdict == AuthorizationVerdict.Allow;
|
||||
|
||||
/// <summary>Convenience constructor for the common "no grants matched" outcome.</summary>
|
||||
public static AuthorizationDecision NotGranted() => new(AuthorizationVerdict.NotGranted, []);
|
||||
|
||||
/// <summary>Allow with the list of grants that matched.</summary>
|
||||
/// <param name="provenance">The list of grants that matched to allow the operation.</param>
|
||||
/// <returns>An authorization decision with Allow verdict.</returns>
|
||||
public static AuthorizationDecision Allowed(IReadOnlyList<MatchedGrant> provenance)
|
||||
=> new(AuthorizationVerdict.Allow, provenance);
|
||||
}
|
||||
|
||||
@@ -19,5 +19,8 @@ public interface IPermissionEvaluator
|
||||
/// failure to <c>BadUserAccessDenied</c> per OPC UA Part 4 when the result is not
|
||||
/// <see cref="AuthorizationVerdict.Allow"/>.
|
||||
/// </summary>
|
||||
/// <param name="session">The user session containing resolved LDAP groups and roles.</param>
|
||||
/// <param name="operation">The OPC UA operation being requested.</param>
|
||||
/// <param name="scope">The node address scope being accessed.</param>
|
||||
AuthorizationDecision Authorize(UserAuthorizationState session, OpcUaOperation operation, NodeScope scope);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ public sealed class PermissionTrie
|
||||
/// session's <paramref name="ldapGroups"/>. Returns the matched-grant list; the caller
|
||||
/// OR-s the flag bits to decide whether the requested permission is carried.
|
||||
/// </summary>
|
||||
/// <param name="scope">The node scope to match permissions for.</param>
|
||||
/// <param name="ldapGroups">The user's LDAP group memberships.</param>
|
||||
public IReadOnlyList<MatchedGrant> CollectMatches(NodeScope scope, IEnumerable<string> ldapGroups)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(scope);
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class PermissionTrieCache
|
||||
new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>Install a trie for a cluster + make it the current generation.</summary>
|
||||
/// <param name="trie">The permission trie to install.</param>
|
||||
public void Install(PermissionTrie trie)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(trie);
|
||||
@@ -32,6 +33,7 @@ public sealed class PermissionTrieCache
|
||||
}
|
||||
|
||||
/// <summary>Get the current-generation trie for a cluster; null when nothing installed.</summary>
|
||||
/// <param name="clusterId">The cluster identifier.</param>
|
||||
public PermissionTrie? GetTrie(string clusterId)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(clusterId);
|
||||
@@ -39,6 +41,8 @@ public sealed class PermissionTrieCache
|
||||
}
|
||||
|
||||
/// <summary>Get a specific (cluster, generation) trie; null if that pair isn't cached.</summary>
|
||||
/// <param name="clusterId">The cluster identifier.</param>
|
||||
/// <param name="generationId">The generation identifier.</param>
|
||||
public PermissionTrie? GetTrie(string clusterId, long generationId)
|
||||
{
|
||||
if (!_byCluster.TryGetValue(clusterId, out var entry)) return null;
|
||||
@@ -46,10 +50,12 @@ public sealed class PermissionTrieCache
|
||||
}
|
||||
|
||||
/// <summary>The generation id the <see cref="GetTrie(string)"/> shortcut currently serves for a cluster.</summary>
|
||||
/// <param name="clusterId">The cluster identifier.</param>
|
||||
public long? CurrentGenerationId(string clusterId)
|
||||
=> _byCluster.TryGetValue(clusterId, out var entry) ? entry.Current.GenerationId : null;
|
||||
|
||||
/// <summary>Drop every cached trie for one cluster.</summary>
|
||||
/// <param name="clusterId">The cluster identifier.</param>
|
||||
public void Invalidate(string clusterId) => _byCluster.TryRemove(clusterId, out _);
|
||||
|
||||
/// <summary>
|
||||
@@ -59,6 +65,8 @@ public sealed class PermissionTrieCache
|
||||
/// class-typed entry) so a concurrent <see cref="Install"/> on the same cluster is never
|
||||
/// silently overwritten.
|
||||
/// </summary>
|
||||
/// <param name="clusterId">The cluster identifier.</param>
|
||||
/// <param name="keepLatest">The number of most recent generations to retain.</param>
|
||||
public void Prune(string clusterId, int keepLatest = 3)
|
||||
{
|
||||
if (keepLatest < 1) throw new ArgumentOutOfRangeException(nameof(keepLatest), keepLatest, "keepLatest must be >= 1");
|
||||
@@ -96,12 +104,18 @@ public sealed class PermissionTrieCache
|
||||
// Class (not record) so TryUpdate in Prune uses reference equality for the CAS comparison.
|
||||
private sealed class ClusterEntry(PermissionTrie current, IReadOnlyDictionary<long, PermissionTrie> tries)
|
||||
{
|
||||
/// <summary>Gets the current (latest) permission trie for the cluster.</summary>
|
||||
public PermissionTrie Current { get; } = current;
|
||||
/// <summary>Gets all cached tries for the cluster keyed by generation ID.</summary>
|
||||
public IReadOnlyDictionary<long, PermissionTrie> Tries { get; } = tries;
|
||||
|
||||
/// <summary>Creates a cluster entry from a single trie.</summary>
|
||||
/// <param name="trie">The permission trie to create the entry from.</param>
|
||||
public static ClusterEntry FromSingle(PermissionTrie trie) =>
|
||||
new(trie, new Dictionary<long, PermissionTrie> { [trie.GenerationId] = trie });
|
||||
|
||||
/// <summary>Creates a new entry with an additional trie, updating current if it's newer.</summary>
|
||||
/// <param name="trie">The new permission trie to add.</param>
|
||||
public ClusterEntry WithAdditional(PermissionTrie trie)
|
||||
{
|
||||
var next = new Dictionary<long, PermissionTrie>(Tries) { [trie.GenerationId] = trie };
|
||||
|
||||
@@ -14,6 +14,9 @@ public sealed class TriePermissionEvaluator : IPermissionEvaluator
|
||||
private readonly PermissionTrieCache _cache;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
/// <summary>Initializes a new instance of the TriePermissionEvaluator class.</summary>
|
||||
/// <param name="cache">The permission trie cache.</param>
|
||||
/// <param name="timeProvider">The time provider for checking authorization state staleness; if null, uses system time.</param>
|
||||
public TriePermissionEvaluator(PermissionTrieCache cache, TimeProvider? timeProvider = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(cache);
|
||||
@@ -21,6 +24,11 @@ public sealed class TriePermissionEvaluator : IPermissionEvaluator
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <summary>Authorizes an operation against the user's session and node scope.</summary>
|
||||
/// <param name="session">The user's authorization session.</param>
|
||||
/// <param name="operation">The OPC UA operation to authorize.</param>
|
||||
/// <param name="scope">The target node scope.</param>
|
||||
/// <returns>An authorization decision indicating whether the operation is allowed.</returns>
|
||||
public AuthorizationDecision Authorize(UserAuthorizationState session, OpcUaOperation operation, NodeScope scope)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(session);
|
||||
@@ -65,6 +73,8 @@ public sealed class TriePermissionEvaluator : IPermissionEvaluator
|
||||
}
|
||||
|
||||
/// <summary>Maps each <see cref="OpcUaOperation"/> to the <see cref="NodePermissions"/> bit required to grant it.</summary>
|
||||
/// <param name="op">The OPC UA operation.</param>
|
||||
/// <returns>The required node permission for the operation.</returns>
|
||||
public static NodePermissions MapOperationToPermission(OpcUaOperation op) => op switch
|
||||
{
|
||||
OpcUaOperation.Browse => NodePermissions.Browse,
|
||||
|
||||
@@ -63,6 +63,7 @@ public sealed record UserAuthorizationState
|
||||
/// <see cref="AuthCacheMaxStaleness"/>. The evaluator short-circuits to NotGranted
|
||||
/// whenever this is true.
|
||||
/// </summary>
|
||||
/// <param name="utcNow">The current UTC time.</param>
|
||||
public bool IsStale(DateTime utcNow) => utcNow - MembershipResolvedUtc > AuthCacheMaxStaleness;
|
||||
|
||||
/// <summary>
|
||||
@@ -70,6 +71,7 @@ public sealed record UserAuthorizationState
|
||||
/// ceiling — a signal to the caller to kick off an async refresh, while the current
|
||||
/// call still evaluates against the cached memberships.
|
||||
/// </summary>
|
||||
/// <param name="utcNow">The current UTC time.</param>
|
||||
public bool NeedsRefresh(DateTime utcNow) =>
|
||||
!IsStale(utcNow) && utcNow - MembershipResolvedUtc > MembershipFreshnessInterval;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user