The Phase 6.2 evaluator was wired but received no input in production: RoleBasedIdentity (the IUserIdentity our LDAP path produces) implemented IRoleBearer but not ILdapGroupsBearer, so AuthorizationGate.BuildSessionState always returned null and the gate lax-mode-allowed every request. UserAuthResult also never carried the resolved LDAP groups, only the role-mapped strings. Closing the gap so the evaluator gets real data: - UserAuthResult adds Groups alongside Roles. LdapUserAuthenticator now surfaces the raw RDN values (ReadOnly / WriteOperate / ...) it already collected during the directory query. Roles stay separate per decision #150 (control-plane Admin role mapping vs data-plane NodeAcl key). - RoleBasedIdentity implements ILdapGroupsBearer so AuthorizationGate sees the groups via the same seam unit tests already use. ThreeUserInteropMatrixTests drives the closure end-to-end against the live GLAuth dev directory: - 5 distinct group memberships (readonly / writeop / writetune / writeconfig / alarmack) plus the multi-group admin user - Each is bound through the real LdapUserAuthenticator - Resolved groups feed an LdapBoundIdentity that goes through the strict-mode AuthorizationGate against a seeded TriePermissionEvaluator - 31 InlineData rows assert the role × operation matrix; failures pinpoint the exact (user, op) cell The remaining wire-level leg of #124 — a real OPC UA client driving UserName tokens through an encrypted endpoint policy — still needs a deployment knob and stays a manual cross-vendor smoke (#119 / #124 manual scope). The doc audit note in admin-ui-phase-6-status.md is updated to reflect what's now auto'd vs what stays manual. 33/33 new tests pass against live GLAuth; existing 270 non-LiveLdap tests in Server.Tests still pass; Core.Tests 205/205, Admin.Tests 109/109. The 7 integration-test failures observed during this run pre-exist this commit (NodeId-scheme regression from #134) and are tracked separately as #135.
39 lines
3.2 KiB
Markdown
39 lines
3.2 KiB
Markdown
# Admin UI Phase 6 status audit (2026-04-24)
|
||
|
||
Audit pass that closes the Phase 6 Admin-UI tasks that were tracked as still-open (#128–#131) but already had their Blazor pages shipped. Every page listed below compiles against the current `OtOpcUaConfigDbContext` schema + the current Admin service surface, has substantive (non-stub) content, and is covered by `ZB.MOM.WW.OtOpcUa.Admin.Tests` (112/112 green).
|
||
|
||
## Task #128 — /hosts column refresh (Phase 6.1 Stream E.2/E.3)
|
||
|
||
`Components/Pages/Hosts.razor` — 233 LOC. Route `/hosts`. Ships:
|
||
|
||
- Per-driver circuit-breaker columns (`ConsecutiveFailures`, `LastCircuitBreakerOpenUtc`).
|
||
- Stale-row detection via `HostStatusService.IsStale` (publisher heartbeat ≥ 30 s stale threshold).
|
||
- Summary cards: Running / Stale / Faulted / total.
|
||
- Auto-refresh every `RefreshIntervalSeconds` driven by the `FleetStatusHub` SignalR feed.
|
||
- Health band via `DriverHostState` enum colour coding.
|
||
|
||
## Task #129 — RoleGrantsTab + AclsTab + Probe (Phase 6.2 Stream D)
|
||
|
||
- `Components/Pages/RoleGrants.razor` — 192 LOC. Route `/role-grants`. Edits LDAP-group → OPC-UA-role mappings with live reload over `AclChangeNotifier` SignalR.
|
||
- `Components/Pages/Clusters/AclsTab.razor` — 279 LOC. NodeAcl CRUD + the **"Probe this permission"** form (task #196 slice 1, embedded at line 38 onward). Binds `_probeGroup` / `_probeNamespaceId` / `_probeUnsAreaId` / `_probeUnsLineId` / `_probeEquipmentId` / `_probeTagId` / `_probePermission` through `PermissionProbeService`.
|
||
|
||
## Task #130 — RedundancyTab (Phase 6.3 Stream E)
|
||
|
||
`Components/Pages/Clusters/RedundancyTab.razor` — 175 LOC. Topology table, per-peer reachability (via `FleetStatusHub`), ServiceLevel band + `ApplyLeaseRegistry` / `RecoveryStateManager` state surfaces, failover action button. Live updates over the same SignalR hub `RedundancyPublisherHostedService` ticks.
|
||
|
||
## Task #131 — Draft / publish / diff / identification (Phase 6.4 Streams A–D)
|
||
|
||
- `Components/Pages/Clusters/DraftEditor.razor` — 105 LOC. Route `/clusters/{ClusterId}/draft/{GenerationId:long}`. Calls `DraftValidationService` + `GenerationService`.
|
||
- `Components/Pages/Clusters/Generations.razor` — 73 LOC. Publish flow (generation state transitions through `sp_PublishGeneration`).
|
||
- `Components/Pages/Clusters/DiffViewer.razor` — 87 LOC. Route `/clusters/{ClusterId}/draft/{GenerationId:long}/diff`. Renders `sp_ComputeGenerationDiff` output.
|
||
- `Components/Pages/Clusters/IdentificationFields.razor` — 49 LOC. OPC 40010 Identification folder editor bound to the `Equipment` entity.
|
||
|
||
## What's NOT in this audit
|
||
|
||
- `#124` — Phase 6.2 3-user interop matrix. Authz layer is now covered by `ThreeUserInteropMatrixTests` in `ZB.MOM.WW.OtOpcUa.Server.Tests` (drives the 5 GLAuth users + admin through `LdapUserAuthenticator` → `AuthorizationGate.IsAllowed` for the role × operation matrix). The wire-level OPC UA-client cross-vendor leg still needs a UserName-token endpoint policy + manual client drill — that part stays a manual deliverable.
|
||
- `#119` — Phase 6.3 client interop matrix. Manual Ignition/Kepware/Aveva drills.
|
||
- `#113` — OPC UA CTT conformance pass. Manual CTT run.
|
||
- `#114` / `#115` — Redundancy cutover + deployment checklist. Manual.
|
||
|
||
Those remain GA-gating but require a human at a console, not a code change.
|