docs: strip task-tracking IDs from code comments and fill missing XML docs
ci / nightly-windev (push) Has been skipped
ci / windows-x86 (push) Successful in 1m16s
ci / java (push) Successful in 2m5s
ci / portable (push) Failing after 5m9s

Tracking IDs are review bookkeeping that rots in shipped source; the rationale they tagged is kept. Comment-only change (CommentChecker 458 -> 16 false positives).
This commit is contained in:
Joseph Doherty
2026-10-07 15:34:32 -04:00
parent f2e0861709
commit f40409a688
115 changed files with 549 additions and 411 deletions
@@ -5,7 +5,7 @@ namespace ZB.MOM.WW.MxGateway.Server.Dashboard;
/// <summary>
/// Handler for <see cref="AuthenticatedDashboardRoleRequirement"/>: succeeds only when the caller
/// is authenticated AND holds one of the requirement's roles. It reads no options at all, which
/// is the point — there is no configuration value that can turn this into a bypass (SEC-40).
/// is the point — there is no configuration value that can turn this into a bypass.
/// </summary>
public sealed class AuthenticatedDashboardRoleHandler
: AuthorizationHandler<AuthenticatedDashboardRoleRequirement>
@@ -13,9 +13,9 @@ namespace ZB.MOM.WW.MxGateway.Server.Dashboard;
/// into this one by accident.
/// </summary>
/// <remarks>
/// Introduced for SEC-40 to gate the alarm feed (<c>AlarmsHub</c> and the <c>/alarms</c> page),
/// Introduced to gate the alarm feed (<c>AlarmsHub</c> and the <c>/alarms</c> page),
/// which is gateway-central and session-less and therefore carries no per-session provenance the
/// SEC-25 tag ACL could scope it by. Requiring a real dashboard role claim is the narrowing that
/// tag ACL could scope it by. Requiring a real dashboard role claim is the narrowing that
/// is actually available: it keeps galaxy-wide alarm metadata — alarm reference (a full tag path),
/// state, severity, category, area, acknowledging operator — away from the read-only environment
/// bypasses, which exist for local development and unauthenticated deployments rather than as a
@@ -32,7 +32,7 @@ public sealed record DashboardAlarmProviderStatus(
/// <summary>
/// Badge label shown when the alarm manager is serving normally but the subtag standby
/// behind it covers nothing — an empty or undiscoverable watch-list (GWC-37). The feed is
/// behind it covers nothing — an empty or undiscoverable watch-list. The feed is
/// healthy today; what is degraded is the fallback that would take over tomorrow, so the
/// badge names the standby rather than claiming the feed has failed over.
/// </summary>
@@ -77,7 +77,7 @@ public sealed record DashboardAlarmProviderStatus(
&& status.Mode == AlarmProviderMode.Subtag
&& string.Equals(reason, AlarmProviderReasons.ForcedSubtag, StringComparison.Ordinal);
// GWC-37: degraded WITHOUT subtag mode means the alarm manager is still serving and the
// Degraded WITHOUT subtag mode means the alarm manager is still serving and the
// standby is the unsound half. "Subtag monitoring (degraded)" would misreport which
// provider is live, so this state gets its own label; the amber badge is shared because
// the operator action — fix discovery — is equally overdue in both.
@@ -35,7 +35,7 @@ public static class DashboardAuthenticationDefaults
/// <summary>
/// Policy guarding the alarm feed — the <c>AlarmsHub</c> SignalR surface and the
/// <c>/alarms</c> page that reads the same central monitor in process (SEC-40). Accepts the
/// <c>/alarms</c> page that reads the same central monitor in process. Accepts the
/// same two schemes as <see cref="HubClientsPolicy"/> but carries
/// <see cref="AuthenticatedDashboardRoleRequirement"/>, a requirement type
/// <see cref="DashboardAuthorizationHandler"/> does not handle, so the environment bypasses
@@ -49,10 +49,10 @@ public static class DashboardAuthenticationDefaults
public const string KeyPrefixClaimType = "mxgateway:key_prefix";
/// <summary>
/// Claim carrying one dashboard event-visibility tag the caller is granted (SEC-25). Stamped
/// Claim carrying one dashboard event-visibility tag the caller is granted. Stamped
/// at cookie login by <see cref="DashboardAuthenticator"/> and at hub-token mint by
/// <see cref="HubTokenService"/>, both resolving the caller's LDAP groups through
/// <c>MxGateway:Dashboard:GroupToTag</c>. Since SEC-41 <see cref="IDashboardSessionAcl"/> reads
/// <c>MxGateway:Dashboard:GroupToTag</c>. <see cref="IDashboardSessionAcl"/> reads
/// this claim only as a FALLBACK, for a principal that carries no
/// <see cref="LdapGroupClaimType"/> claims to re-resolve from (the hub-token principal, whose
/// payload carries tags but not groups); a cookie principal is re-resolved against current
@@ -21,7 +21,7 @@ namespace ZB.MOM.WW.MxGateway.Server.Dashboard;
/// <param name="roleMapper">Maps LDAP groups to dashboard roles.</param>
/// <param name="options">
/// Gateway options supplying <c>MxGateway:Dashboard:GroupToTag</c>, the map that turns the user's
/// LDAP groups into the dashboard visibility tags stamped on the cookie principal (SEC-25).
/// LDAP groups into the dashboard visibility tags stamped on the cookie principal.
/// </param>
/// <param name="logger">Logger for diagnostic, credential-free login outcomes.</param>
public sealed class DashboardAuthenticator(
@@ -142,7 +142,7 @@ public sealed class DashboardAuthenticator(
claims.AddRange(groupNames.Select(group => new Claim(
DashboardAuthenticationDefaults.LdapGroupClaimType,
group)));
// Dashboard event-visibility tags (SEC-25). Visibility only — never a data-access grant —
// Dashboard event-visibility tags. Visibility only — never a data-access grant —
// and never logged: only the decision, never the tag values, reaches diagnostics.
claims.AddRange(DashboardGroupTagMapping
.MapGroupsToTags(groupNames, groupToTag)
@@ -107,7 +107,7 @@ public static class DashboardEndpointRouteBuilderExtensions
// SignalR hubs. Authorization is enforced on the hub class via [Authorize], so both
// policies below accept either the dashboard cookie or a HubToken bearer. Snapshot and
// events use HubClientsPolicy; AlarmsHub uses AlarmsPolicy, which additionally requires a
// real authenticated dashboard role (SEC-40) — see AlarmsHub for why the alarm feed is
// real authenticated dashboard role — see AlarmsHub for why the alarm feed is
// gated harder than the session-scoped ones.
endpoints.MapHub<DashboardSnapshotHub>("/hubs/snapshot");
endpoints.MapHub<AlarmsHub>("/hubs/alarms");
@@ -177,7 +177,7 @@ public static class DashboardServiceCollectionExtensions
DashboardAuthenticationDefaults.AuthenticationScheme,
DashboardAuthenticationDefaults.HubAuthenticationScheme)
.AddRequirements(DashboardAuthorizationRequirement.AnyDashboardRole));
// SEC-40. Same two schemes as HubClientsPolicy (the alarm feed has an in-page reader
// Same two schemes as HubClientsPolicy (the alarm feed has an in-page reader
// and an external hub reader), but a requirement type DashboardAuthorizationHandler
// does not handle, so neither Authentication:Mode=Disabled nor anonymous localhost
// can satisfy it. Galaxy-wide alarm metadata therefore needs a real dashboard role.
@@ -26,7 +26,7 @@ namespace ZB.MOM.WW.MxGateway.Server.Dashboard;
/// (ordinal-ignore-case).</description></item>
/// </list>
/// <para>
/// <strong>Where the grant comes from (SEC-41).</strong> The grant is re-resolved on every call
/// <strong>Where the grant comes from.</strong> The grant is re-resolved on every call
/// from the caller's <see cref="DashboardAuthenticationDefaults.LdapGroupClaimType"/> claims
/// through <c>MxGateway:Dashboard:GroupToTag</c> as it stands in the currently bound options —
/// the same single <see cref="DashboardGroupTagMapping.MapGroupsToTags"/> call
@@ -120,7 +120,7 @@ public sealed class DashboardSessionAcl(
if (groups is not null)
{
// SEC-41: current options, not the login-time snapshot. MapGroupsToTags returns an
// Current options, not the login-time snapshot. MapGroupsToTags returns an
// OrdinalIgnoreCase set, so probing it with the session's tags carries the
// case-insensitive comparison in the same direction the claim scan below does.
IReadOnlySet<string> granted = DashboardGroupTagMapping.MapGroupsToTags(
@@ -39,7 +39,7 @@ public sealed class HubTokenService
// revocable. A short lifetime bounds the exposure window of a token captured from a proxy
// or log after logout (the cookie is cleared on logout, but outstanding tokens are not), and
// bounds how long a stale role set survives a role change. It now bounds a stale *tag* grant
// the same way (SEC-25): the token carries the tags resolved from the caller's LDAP groups at
// the same way: the token carries the tags resolved from the caller's LDAP groups at
// mint time, so revoking a GroupToTag entry takes effect for token-authenticated hub
// connections within one lifetime — the natural place the deferred "tokens gain session
// binding" note landed. Five minutes is transparent to clients that re-fetch from /hubs/token
@@ -11,9 +11,9 @@ namespace ZB.MOM.WW.MxGateway.Server.Dashboard.Hubs;
/// </summary>
/// <remarks>
/// The feed is galaxy-wide: the alarm monitor is gateway-central and its messages carry no
/// session provenance, so the SEC-25 per-session tag ACL that scopes <c>EventsHub</c> has nothing
/// session provenance, so the per-session tag ACL that scopes <c>EventsHub</c> has nothing
/// to intersect here and is deliberately not applied — every authenticated Viewer sees the whole
/// subscription expression's alarm metadata. What SEC-40 tightened instead is the entry gate:
/// subscription expression's alarm metadata. What is tightened instead is the entry gate:
/// <see cref="DashboardAuthenticationDefaults.AlarmsPolicy"/> rather than the
/// <see cref="DashboardAuthenticationDefaults.HubClientsPolicy"/> the other hubs use, so the
/// read-only environment bypasses (<c>Authentication:Mode=Disabled</c>, anonymous localhost) no
@@ -23,7 +23,7 @@ namespace ZB.MOM.WW.MxGateway.Server.Dashboard.Hubs;
/// <c>StreamAlarms</c> subscribers and the alarms page as well, and none of
/// those audiences is subject to this dashboard-display flag.
/// <para>
/// The broadcast stays deliberately unfiltered (SEC-40). Audience is decided once, at hub
/// The broadcast stays deliberately unfiltered. Audience is decided once, at hub
/// admission — <see cref="AlarmsHub"/> carries
/// <see cref="DashboardAuthenticationDefaults.AlarmsPolicy"/>, so only an authenticated caller
/// with a real dashboard role is ever in <see cref="AlarmsHub.AllAlarmsGroup"/> — and the alarm
@@ -39,8 +39,8 @@ public sealed class EventsHub(
/// The hub-level <see cref="AuthorizeAttribute"/> (<c>HubClientsPolicy</c>)
/// only checks that the caller carries one of the dashboard roles, which by
/// itself would let any Viewer subscribe to any session id they name. The
/// per-session decision is <see cref="IDashboardSessionAcl"/>'s
/// (SEC-25 / TST-15). The admin bypass is evaluated first, so an
/// per-session decision is <see cref="IDashboardSessionAcl"/>'s.
/// The admin bypass is evaluated first, so an
/// Administrator joins any session id they name; every check below it
/// applies to non-Admin callers only. For those: a Viewer sees a session
/// only when its tags intersect their granted tags, an untagged session
@@ -95,16 +95,12 @@ public sealed class EventsHub(
viewerRegistry.RemoveViewer(Context.ConnectionId, sessionId);
}
/// <summary>
/// Releases every session subscription the dropped connection held. A browser
/// tab that closes never calls <see cref="UnsubscribeSession"/>, so without
/// this the session would look watched forever and the mirror would keep
/// cloning and sending events to an empty group.
/// </summary>
/// <param name="exception">The exception that terminated the connection, if any.</param>
/// <returns>A task representing the disconnect handling.</returns>
/// <inheritdoc />
public override Task OnDisconnectedAsync(Exception? exception)
{
// Release every session subscription the dropped connection held. A browser tab that
// closes never calls UnsubscribeSession, so without this the session would look watched
// forever and the mirror would keep cloning and sending events to an empty group.
viewerRegistry.ReleaseConnection(Context.ConnectionId);
return base.OnDisconnectedAsync(exception);
@@ -4,7 +4,7 @@ namespace ZB.MOM.WW.MxGateway.Server.Dashboard;
/// <summary>
/// Decides whether a dashboard principal may observe one session's mirrored
/// event stream (SEC-25 / TST-15). Consulted at every subscribe seam: the
/// event stream. Consulted at every subscribe seam: the
/// SignalR <c>EventsHub.SubscribeSession</c> join and the in-process
/// <c>IDashboardSessionEventSubscriber.Subscribe</c> used by the
/// session-details page.