fix(admin): resolve Medium code-review finding (Admin-007)

NewCluster.razor and ClusterDetail.razor now resolve ClaimTypes.Name /
NameIdentifier from the cascaded AuthenticationState instead of hardcoding
"admin-ui" as the createdBy audit field. The operator principal is now
attributed correctly on every cluster-create and draft-create write path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-22 07:27:40 -04:00
parent a9cede8ed4
commit 08f000069c
3 changed files with 26 additions and 6 deletions

View File

@@ -123,13 +123,13 @@
| Severity | Medium |
| Category | Design-document adherence |
| Location | `Components/Pages/Clusters/NewCluster.razor:91,95-96` |
| Status | Open |
| Status | Resolved |
**Description:** `NewCluster.CreateAsync` hardcodes `CreatedBy = "admin-ui"` (both on the `ServerCluster` row and the draft generation) instead of the signed-in operator principal name. `admin-ui.md` section "Audit" requires "the operator principal" be recorded on every write. The audit trail therefore cannot attribute cluster creation to a person. The same literal would apply to any anonymous creation that Admin-001/002 currently permit.
**Recommendation:** Pass the authenticated user identity (`ClaimTypes.Name` / `NameIdentifier` from the cascaded `AuthenticationState`) as `createdBy`. Apply the same pattern to every other Admin write path that records a `CreatedBy`/`PublishedBy`/`ReleasedBy` field.
**Resolution:** _(open)_
**Resolution:** Resolved 2026-05-22 — `NewCluster.razor` and `ClusterDetail.razor` (the two pages that call `ClusterService.CreateAsync` / `GenerationService.CreateDraftAsync` with a hardcoded literal) now resolve `ClaimTypes.Name` / `ClaimTypes.NameIdentifier` from the cascaded `AuthenticationState` and pass the operator principal name as `createdBy`; the fallback is `"unknown"` (defensive, should never occur on an `[Authorize]`-gated page).
### Admin-008