feat(dashboard): GroupToTag / UntaggedSessionVisibility config (SEC-25)

Groundwork for the per-session dashboard event ACL (docs/plans/2026-07-10-dashboard-session-acl-tst15.md 3.2): a dashboard group can now grant visibility tags, and untagged sessions default to AdminOnly. Enforcement lands with the EventsHub ACL; nothing consumes the grant yet.

GroupToTag is deliberately uncoupled from GroupToRole - a group may appear in either map, both, or neither - and is validated for shape only. Tags gate dashboard event visibility, never data access.
This commit is contained in:
Joseph Doherty
2026-08-17 03:46:56 -04:00
parent fa9eb0c0b4
commit c79aaaf9eb
7 changed files with 389 additions and 1 deletions
@@ -410,6 +410,36 @@ public sealed class GatewayOptionsValidator : OptionsValidatorBase<GatewayOption
}
}
// GroupToTag is validated for shape only, and independently of GroupToRole:
// a group may grant a role, a tag, both, or neither. An empty map is legal —
// it yields Viewers with no tag grant, which (under the default AdminOnly)
// means they observe no session's events. That is the fail-closed posture.
foreach (KeyValuePair<string, string[]> entry in options.GroupToTag)
{
if (string.IsNullOrWhiteSpace(entry.Key))
{
builder.Add("MxGateway:Dashboard:GroupToTag keys (LDAP group names) must be non-blank.");
}
if (entry.Value is null)
{
builder.Add($"MxGateway:Dashboard:GroupToTag['{entry.Key}'] must be a list of tags, not null.");
continue;
}
if (Array.Exists(entry.Value, string.IsNullOrWhiteSpace))
{
builder.Add($"MxGateway:Dashboard:GroupToTag['{entry.Key}'] tags must be non-blank.");
}
}
if (!Enum.IsDefined(options.UntaggedSessionVisibility))
{
builder.Add(
$"MxGateway:Dashboard:UntaggedSessionVisibility must be '{nameof(UntaggedSessionVisibility.AdminOnly)}' "
+ $"or '{nameof(UntaggedSessionVisibility.AllViewers)}'.");
}
AddIfNotPositive(
options.SnapshotIntervalMilliseconds,
"MxGateway:Dashboard:SnapshotIntervalMilliseconds must be greater than zero.",