docs(xmldoc): fill missing XML docs + strip tracking-ID comments across src
v2-ci / build (push) Failing after 41s
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>/<returns>/<inheritdoc> where missing and removes
project bookkeeping IDs (task/tracking refs) from shipped code comments,
so the docs read cleanly and CommentChecker is quiet except for known
false positives (PLC/protocol terms, event/IEqualityComparer inheritdoc).
Doc/comment-only; no logic changed; solution builds clean.
This commit is contained in:
Joseph Doherty
2026-07-07 12:38:39 -04:00
parent 384dbd7d36
commit 9cad9ed0fc
375 changed files with 1899 additions and 2493 deletions
@@ -33,9 +33,14 @@ public sealed class AutoLoginAuthenticationHandler
=> _opts = disableLoginOptions.Value;
/// <summary>No-op: auto-login writes no cookie, so an explicit sign-in has nothing to persist.</summary>
/// <param name="user">The principal that would be signed in.</param>
/// <param name="properties">Authentication properties that would be persisted.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties? properties) => Task.CompletedTask;
/// <summary>No-op: there is no auth cookie to clear; the next request re-authenticates via this handler.</summary>
/// <param name="properties">Authentication properties that would be cleared.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public Task SignOutAsync(AuthenticationProperties? properties) => Task.CompletedTask;
/// <inheritdoc />
@@ -65,7 +65,8 @@ public sealed class CookieAuthenticationStateProvider : AuthenticationStateProvi
}
}
/// <inheritdoc />
/// <summary>Cancels the background ping loop, awaits its completion, and disposes the cancellation token source.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
public async ValueTask DisposeAsync()
{
_cts.Cancel();
@@ -132,7 +132,7 @@ public static class AuthEndpoints
await http.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
if (!isForm) return Results.NoContent();
// Security-001: validate returnUrl is a relative (local) URL before redirecting.
// Validate returnUrl is a relative (local) URL before redirecting.
// An attacker can supply an absolute URL (e.g. https://evil.com) via a crafted link;
// LoginCard echoes the value verbatim into the hidden form field. Fall back to the
// app root rather than following the external URL (open-redirect prevention).
@@ -135,6 +135,7 @@ public sealed class JwtTokenService
/// required pairing whenever a JwtBearer scheme is wired.
/// </para>
/// </summary>
/// <returns>The <see cref="TokenValidationParameters"/> used to validate tokens minted by <see cref="Issue"/>.</returns>
public TokenValidationParameters BuildValidationParameters() => new()
{
ValidateIssuer = true,
@@ -34,7 +34,7 @@ public sealed class LdapOptions
/// Transport security for the LDAP connection — <see cref="LdapTransport.Ldaps"/> (implicit
/// TLS), <see cref="LdapTransport.StartTls"/> (upgrade), or <see cref="LdapTransport.None"/>
/// (plaintext, dev/test only — requires <see cref="AllowInsecure"/>). Replaces the former
/// <c>UseTls</c> bool (Task 1.4): <c>true</c>→<see cref="LdapTransport.Ldaps"/>,
/// <c>UseTls</c> bool: <c>true</c>→<see cref="LdapTransport.Ldaps"/>,
/// <c>false</c>→<see cref="LdapTransport.None"/>.
/// </summary>
public LdapTransport Transport { get; set; } = LdapTransport.None;
@@ -78,7 +78,7 @@ public sealed class LdapOptions
/// <summary>
/// Maps LDAP group name → Admin role. Group match is case-insensitive. A user gets every
/// role whose source group is in their membership list. Values are the canonical control-plane
/// roles (Task 1.7). Example dev mapping:
/// roles. Example dev mapping:
/// <code>"ReadOnly":"Viewer","ReadWrite":"Designer","AlarmAck":"Administrator"</code>
/// </summary>
public Dictionary<string, string> GroupToRole { get; set; } = new(StringComparer.OrdinalIgnoreCase);
@@ -90,6 +90,7 @@ public sealed class LdapOptions
/// handled by the app wrapper around the library service; <see cref="Enabled"/> is carried
/// through so the library's own feature gate stays consistent with the app master switch.
/// </summary>
/// <returns>The projected <see cref="LibLdapOptions"/> for the shared LDAP client library.</returns>
public LibLdapOptions ToLibraryOptions() => new()
{
Enabled = Enabled,
@@ -20,7 +20,13 @@ public sealed class OtOpcUaGroupRoleMapper(
IOptions<LdapOptions> ldapOptions,
ILdapGroupRoleMappingService dbMappings) : IGroupRoleMapper<string>
{
/// <inheritdoc />
/// <summary>Maps a user's LDAP group memberships to their OtOpcUa roles.</summary>
/// <param name="groups">The LDAP group names the user is a member of.</param>
/// <param name="ct">Cancellation token for the DB lookup.</param>
/// <returns>
/// The merged role mapping — the appsettings <c>GroupToRole</c> baseline unioned with
/// any matching system-wide DB grants, with a <c>null</c> <see cref="GroupRoleMapping{TRole}.Scope"/>.
/// </returns>
public async Task<GroupRoleMapping<string>> MapAsync(IReadOnlyList<string> groups, CancellationToken ct)
{
ArgumentNullException.ThrowIfNull(groups);
@@ -29,7 +29,7 @@ namespace ZB.MOM.WW.OtOpcUa.Security.Ldap;
/// <remarks>
/// Fail-closed: the library never throws, and this wrapper adds no new throwing paths. The
/// DevStub result grants the canonical <c>"Administrator"</c> control-plane role (group
/// <c>"dev"</c>) so the dev session can navigate the full Admin UI (Task 1.7 renamed the prior
/// <c>"dev"</c>) so the dev session can navigate the full Admin UI (renamed from the prior
/// <c>"FleetAdmin"</c> to the canonical <c>"Administrator"</c>).
/// </remarks>
public sealed class OtOpcUaLdapAuthService : ILdapAuthService
@@ -80,7 +80,7 @@ public sealed class OtOpcUaLdapAuthService : ILdapAuthService
{
// Dev bypass: accept any non-empty credentials and grant Administrator WITHOUT a real bind.
// Pre-populated Roles are unioned with the mapper output by both consumers, so the grant
// survives the move to IGroupRoleMapper. (Task 1.7 canonicalized the role string from the
// survives the move to IGroupRoleMapper. (The role string was canonicalized from the
// prior "FleetAdmin" to "Administrator".)
_logger.LogWarning(
"OtOpcUaLdapAuthService: DevStubMode bypass — accepting {User} without a real LDAP bind", username);
@@ -90,7 +90,7 @@ public sealed class OtOpcUaLdapAuthService : ILdapAuthService
// Fail closed on a plaintext transport unless explicitly opted in. The bespoke service
// enforced this at login (not startup), so the host still boots with an insecure-by-default
// config and only refuses the bind here — preserved verbatim after the UseTls→Transport
// migration (Task 1.4). The shared library's directory client does not re-check this.
// migration. The shared library's directory client does not re-check this.
if (_options.Transport == LdapTransport.None && !_options.AllowInsecure)
return new(false, null, username, [], [],
"Insecure LDAP is disabled. Enable a TLS transport or set AllowInsecure for dev/test.");
@@ -33,6 +33,7 @@ public static class RoleMapper
/// </summary>
/// <param name="baselineRoles">Roles already resolved from appsettings (or the dev stub).</param>
/// <param name="dbRows">LdapGroupRoleMapping rows for the user's groups (from GetByGroupsAsync).</param>
/// <returns>The merged, de-duplicated list of roles.</returns>
public static IReadOnlyList<string> Merge(
IReadOnlyCollection<string> baselineRoles,
IReadOnlyCollection<LdapGroupRoleMapping> dbRows)
@@ -33,6 +33,7 @@ public static class ServiceCollectionExtensions
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="configuration">The application configuration root.</param>
/// <returns>The same service collection, for chaining.</returns>
public static IServiceCollection AddOtOpcUaAuth(this IServiceCollection services, IConfiguration configuration)
{
services.AddOptions<JwtOptions>().Bind(configuration.GetSection(JwtOptions.SectionName));
@@ -148,7 +149,7 @@ public static class ServiceCollectionExtensions
// DriverOperator (policy NAME kept stable): may issue Reconnect/Restart commands against
// live driver instances from the Admin UI DriverStatusPanel. The role STRINGS it requires
// are the canonical control-plane roles (Task 1.7): Operator (was DriverOperator) and
// are the canonical control-plane roles: Operator (was DriverOperator) and
// Administrator (was FleetAdmin). Map LDAP group → role via GroupToRole in appsettings
// (e.g. "ot-driver-operator": "Operator").
o.AddPolicy("DriverOperator", policy =>