feat(dashboard): gate the side rail's Secrets link on secrets:manage
Family-wide nav sweep: the Secrets management page should be linked from each app's UI, visible to Administrator-role users only. The link already existed in MainLayout's Admin section. The gate did not: the rail rendered every item for every visitor, including a Viewer and the anonymous-localhost read-only identity. Not an access hole — the mounted page carries [Authorize(Policy = "secrets:manage")], so a Viewer clicking through was denied — but a dead link presented as a live one. There was also no existing role-gated nav pattern to follow; the rail's only AuthorizeView was the footer's signed-in/signed-out split. Gated on the POLICY rather than a role literal, so nav visibility cannot drift from what the page enforces. In this host the two are equivalent: GatewayOptionsValidator constrains Dashboard:GroupToRole values to Administrator or Viewer, so the shared library's other manage-granting roles (secrets-manager, secrets-reveal) are unreachable. The policy form stays correct if that ever relaxes, where a role literal would then hide the link from users who can use the page. API Keys is deliberately left ungated. It looks like the same case and is not: ApiKeysPage renders for a Viewer with write affordances hidden, so hiding its link would remove legitimate read access. The secrets page has no read-only mode. The rule is "gate the link when the page denies the role outright", not "gate everything under Admin". Coverage: three tests pin the policy's verdict per principal (Administrator admitted, Viewer refused, unauthenticated refused), and /admin/secrets joins the canonical route list — it is the one nav destination mounted from an RCL rather than declared here, so a routing regression could remove it without touching this repo's pages. The principal helper sets an authentication type deliberately: without one the role assertions would pass vacuously for the wrong reason. Not a rendering test — the suite has no component-testing harness, and adding one to assert a single AuthorizeView would be a large dependency for a small claim. Build 0 warnings / 0 errors; suite 895/895.
This commit is contained in:
@@ -205,6 +205,12 @@ public sealed class GatewayApplicationTests
|
||||
"/galaxy",
|
||||
"/apikeys",
|
||||
"/sessions/{SessionId}",
|
||||
|
||||
// Mounted from the ZB.MOM.WW.Secrets.Ui RCL rather than declared here, so it is the
|
||||
// one nav destination that a routing regression could remove without touching this
|
||||
// repo's own pages. The side rail links to it (role-gated), which makes an unmapped
|
||||
// route a visible dead link rather than a silent absence.
|
||||
"/admin/secrets",
|
||||
];
|
||||
foreach (string canonical in canonicalRoutes)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user