fix(central-ui): Flow Debugger Replay opens to OperationalAudit roles; Live run and Retry/Discard stay Deployer-only (arch-review F3)
Design D6 / §9 says a Live run is a Deployer act while Replay needs only
OperationalAudit, but the page and all three FlowDebug* commands were gated on
Deployer. The Audit Log and Execution Chain pages -- themselves OperationalAudit
-- show an "Open in Flow Debugger" drill-in that an auditor could not follow.
Implements the split:
- New `RequireFlowDebugger` policy over `FlowDebuggerAccessRoles`
{Deployer, Administrator, Viewer}; the page now carries it instead of
`RequireDeployment`.
- `FlowDebugReplayCommand` takes the same role set in the ManagementActor
matrix; `FlowDebugRunMethodCommand` / `FlowDebugRunValueChangeCommand` stay
DeployerOnly.
- The page resolves `_canLive` (Deployer) in OnInitializedAsync and, without it,
pins the mode to Replay, hides the entry-point and mode toggles, the Run
button and the Live pickers, honours only the `?executionId=` drill-in, and
leaves the parked-node Retry/Discard callbacks unset so those buttons never
render. `CanRun`, `SetMode(Live)` and `ActOnStepAsync` repeat the check so the
split does not rest on markup alone.
The NavMenu entry stays inside the Deployer-gated Deployment section -- auditors
arrive through the audit drill-ins, which is the point of the finding.
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
This commit is contained in:
@@ -149,6 +149,33 @@ public static class AuthorizationPolicies
|
||||
/// </remarks>
|
||||
public static readonly string[] AuditExportRoles = { Roles.Administrator };
|
||||
|
||||
/// <summary>
|
||||
/// Permission to OPEN the Flow Debugger page (arch-review F3 / design D6).
|
||||
/// Replay only reads the audit chain, and the Audit Log / Execution Chain
|
||||
/// pages — themselves gated on <see cref="OperationalAudit"/> — carry an
|
||||
/// "Open in Flow Debugger" drill-in that is the feature's main entry for a
|
||||
/// past incident, so an auditor must be able to follow it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is page ACCESS only, and is deliberately NOT sufficient for a Live
|
||||
/// run: the Run controls, the Live entry-point pickers and the parked-node
|
||||
/// Retry/Discard actions are gated on <see cref="RequireDeployment"/> in the
|
||||
/// page, and <c>FlowDebugRunMethodCommand</c> /
|
||||
/// <c>FlowDebugRunValueChangeCommand</c> stay Deployer-only in the
|
||||
/// ManagementActor role matrix. Only <c>FlowDebugReplayCommand</c> accepts
|
||||
/// <see cref="FlowDebuggerAccessRoles"/>.
|
||||
/// </remarks>
|
||||
public const string RequireFlowDebugger = "RequireFlowDebugger";
|
||||
|
||||
/// <summary>
|
||||
/// Roles that satisfy <see cref="RequireFlowDebugger"/> — the
|
||||
/// <see cref="OperationalAuditRoles"/> plus <c>Deployer</c>. Held in one
|
||||
/// place so the policy, the page and the ManagementActor's
|
||||
/// <c>FlowDebugReplayCommand</c> gate stay in lockstep.
|
||||
/// </summary>
|
||||
public static readonly string[] FlowDebuggerAccessRoles =
|
||||
{ Roles.Deployer, Roles.Administrator, Roles.Viewer };
|
||||
|
||||
/// <summary>
|
||||
/// Registers the ScadaBridge authorization policies (Admin, Design, Deployment, OperationalAudit, AuditExport).
|
||||
/// </summary>
|
||||
@@ -191,6 +218,12 @@ public static class AuthorizationPolicies
|
||||
|
||||
options.AddPolicy(AuditExport, policy =>
|
||||
policy.RequireClaim(JwtTokenService.RoleClaimType, AuditExportRoles));
|
||||
|
||||
// Flow Debugger page access (arch-review F3): opening the page is a
|
||||
// Replay-capable read; the Live run controls are separately gated on
|
||||
// RequireDeployment inside the page.
|
||||
options.AddPolicy(RequireFlowDebugger, policy =>
|
||||
policy.RequireClaim(JwtTokenService.RoleClaimType, FlowDebuggerAccessRoles));
|
||||
});
|
||||
|
||||
return services;
|
||||
|
||||
Reference in New Issue
Block a user