From 3f4fde3e3502fb30b24124aa0e1834708257ff6f Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 8 Sep 2026 01:18:52 -0400 Subject: [PATCH] feat(management): dispatch FlowDebugRunScriptCommand (Deployer-only, long-running) on the ManagementActor Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29 --- .../ManagementActor.cs | 16 +++++++++------- .../ManagementEndpoints.cs | 3 +++ .../AuthorizationPolicies.cs | 5 +++-- .../FlowDebugRunnerTests.cs | 9 +++++++-- .../RequiredRoleMatrixTests.cs | 1 + 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs b/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs index fe8dc090..629b1ced 100644 --- a/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs +++ b/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs @@ -197,7 +197,7 @@ public class ManagementActor : ReceiveActor // arch-review F3: Flow Debugger Replay is an audit read, so it carries the same role // set as the RequireFlowDebugger page policy ({Deployer, Administrator, Viewer}). The - // two Live run commands stay DeployerOnly. + // three Live run commands stay DeployerOnly. private static readonly string[] FlowDebuggerReplayRoles = AuthorizationPolicies.FlowDebuggerAccessRoles; // arch-review C6: area management is reconciled to any-of [Designer, Deployer]. @@ -310,12 +310,13 @@ public class ManagementActor : ReceiveActor or RetryParkedMessageCommand or DiscardParkedMessageCommand or DebugSnapshotCommand => DeployerOnly, - // Flow Debugger (design 2026-09-05 §9 / D6, arch-review F3). A Live run executes - // scripts and writes attributes on operator input, so it stays Deployer-only, like - // the Debug View. Replay only reads the audit chain, so it additionally accepts the - // OperationalAudit roles — the Audit Log / Execution Chain drill-ins are the - // feature's main entry for a past incident and an auditor must be able to use them. - FlowDebugRunMethodCommand or FlowDebugRunValueChangeCommand => DeployerOnly, + // Flow Debugger (design 2026-09-05 §9 / D6, arch-review F3; script entry added by + // design 2026-09-08). All three Live run commands execute scripts and write + // attributes on operator input, so they stay Deployer-only, like the Debug View. + // Replay only reads the audit chain, so it additionally accepts the OperationalAudit + // roles — the Audit Log / Execution Chain drill-ins are the feature's main entry for + // a past incident and an auditor must be able to use them. + FlowDebugRunMethodCommand or FlowDebugRunValueChangeCommand or FlowDebugRunScriptCommand => DeployerOnly, FlowDebugReplayCommand => FlowDebuggerReplayRoles, // Two-person secured write. Submit is an Operator action; @@ -418,6 +419,7 @@ public class ManagementActor : ReceiveActor // Flow Debugger (design 2026-09-05 §7.1) — one execution path for the UI and the CLI. FlowDebugRunMethodCommand cmd => await sp.GetRequiredService().RunMethodAsync(sp, cmd, user, CancellationToken.None), FlowDebugRunValueChangeCommand cmd => await sp.GetRequiredService().RunValueChangeAsync(sp, cmd, user, CancellationToken.None), + FlowDebugRunScriptCommand cmd => await sp.GetRequiredService().RunScriptAsync(sp, cmd, user, CancellationToken.None), FlowDebugReplayCommand cmd => await sp.GetRequiredService().ReplayAsync(sp, cmd, CancellationToken.None), // External Systems diff --git a/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementEndpoints.cs b/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementEndpoints.cs index 3a04aadc..9d8b4f22 100644 --- a/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementEndpoints.cs +++ b/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementEndpoints.cs @@ -58,6 +58,9 @@ public static class ManagementEndpoints // Flow Debugger (design 2026-09-05 §7.1): a Live run lasts up to the method timeout // (+ grace) or the value-change wait window — never the ordinary Ask timeout. typeof(FlowDebugRunMethodCommand), typeof(FlowDebugRunValueChangeCommand), + // script entry (design 2026-09-08): a direct call lasts up to the script's timeout + // (+ grace), a write kind up to its wait window. + typeof(FlowDebugRunScriptCommand), ]; /// diff --git a/src/ZB.MOM.WW.ScadaBridge.Security/AuthorizationPolicies.cs b/src/ZB.MOM.WW.ScadaBridge.Security/AuthorizationPolicies.cs index c691fd24..caa3e5da 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Security/AuthorizationPolicies.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Security/AuthorizationPolicies.cs @@ -160,8 +160,9 @@ public static class AuthorizationPolicies /// 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 in the - /// page, and FlowDebugRunMethodCommand / - /// FlowDebugRunValueChangeCommand stay Deployer-only in the + /// page, and FlowDebugRunMethodCommand, + /// FlowDebugRunValueChangeCommand and + /// FlowDebugRunScriptCommand stay Deployer-only in the /// ManagementActor role matrix. Only FlowDebugReplayCommand accepts /// . /// diff --git a/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/FlowDebugRunnerTests.cs b/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/FlowDebugRunnerTests.cs index 586c0f18..1afa25de 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/FlowDebugRunnerTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/FlowDebugRunnerTests.cs @@ -343,10 +343,15 @@ public class FlowDebugRunnerTests } [Fact] - public void RoleGate_TheTwoRunCommands_AreDeployerOnly() + public void RoleGate_TheThreeRunCommands_AreDeployerOnly() { // arch-review F3: a Live run executes scripts and writes attributes, so it stays Deployer-only. - foreach (var cmd in new object[] { new FlowDebugRunMethodCommand(1, null), new FlowDebugRunValueChangeCommand(1, "a", "b") }) + foreach (var cmd in new object[] + { + new FlowDebugRunMethodCommand(1, null), + new FlowDebugRunValueChangeCommand(1, "a", "b"), + new FlowDebugRunScriptCommand(1, "Manual", null, null), + }) Assert.Equal(new[] { "Deployer" }, ManagementActor.GetRequiredRoles(cmd)); } diff --git a/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/RequiredRoleMatrixTests.cs b/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/RequiredRoleMatrixTests.cs index b060ad34..6f99b190 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/RequiredRoleMatrixTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.ManagementService.Tests/RequiredRoleMatrixTests.cs @@ -151,6 +151,7 @@ public class RequiredRoleMatrixTests // for a past incident and an auditor must be able to follow them. ["FlowDebugRunMethod"] = [Roles.Deployer], ["FlowDebugRunValueChange"] = [Roles.Deployer], + ["FlowDebugRunScript"] = [Roles.Deployer], ["FlowDebugReplay"] = FlowDebuggerReplayers, // ---- Two-person secured write ----------------------------------------------