fix(management): reconcile area role gate to Designer|Deployer across actor and all three docs (arch-review C6)
Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
@@ -103,7 +103,8 @@ Central cluster only. Sites have no user interface.
|
|||||||
- `Export Bundle` (`/design/transport/export`) — multi-step wizard for exporting a `.scadabundle` artifact containing templates, shared scripts, external systems, and central-only configuration. Visible to users with `RequireDesign`.
|
- `Export Bundle` (`/design/transport/export`) — multi-step wizard for exporting a `.scadabundle` artifact containing templates, shared scripts, external systems, and central-only configuration. Visible to users with `RequireDesign`.
|
||||||
- `Import Bundle` (`/design/transport/import`) — multi-step wizard for uploading and applying a `.scadabundle` into the current environment, with per-artifact diff review and conflict resolution. Visible to users with `RequireAdmin`.
|
- `Import Bundle` (`/design/transport/import`) — multi-step wizard for uploading and applying a `.scadabundle` into the current environment, with per-artifact diff review and conflict resolution. Visible to users with `RequireAdmin`.
|
||||||
|
|
||||||
### Area Management (Admin Role)
|
### Area Management (Designer or Deployer Role)
|
||||||
|
- Areas are authored inside the Deployment Topology workflow (`Topology.razor`, `RequireDeployment`); managing them is gated **any-of [Designer, Deployer]**, not Administrator (arch-review C6).
|
||||||
- Define hierarchical area structures per site.
|
- Define hierarchical area structures per site.
|
||||||
- Parent-child area relationships.
|
- Parent-child area relationships.
|
||||||
- Assign areas when managing instances.
|
- Assign areas when managing instances.
|
||||||
|
|||||||
@@ -216,9 +216,10 @@ The two-person authorization workflow for writes through the MxAccess Gateway. B
|
|||||||
|
|
||||||
Every incoming message carries the authenticated user's identity and roles. The ManagementActor enforces the same role-based authorization rules as the Central UI:
|
Every incoming message carries the authenticated user's identity and roles. The ManagementActor enforces the same role-based authorization rules as the Central UI:
|
||||||
|
|
||||||
- **Admin** role required for: site management, area management, API key management, role mapping management, scope rule management, system configuration.
|
- **Admin** role required for: site management, API key management, role mapping management, scope rule management, system configuration.
|
||||||
- **Design** role required for: template authoring (including template member management: attributes, alarms, native alarm sources, scripts, compositions), shared scripts, external system definitions, database connection definitions, notification lists, inbound API method definitions.
|
- **Design** role required for: template authoring (including template member management: attributes, alarms, native alarm sources, scripts, compositions), shared scripts, external system definitions, database connection definitions, notification lists, inbound API method definitions.
|
||||||
- **Deployment** role required for: instance management (including instance alarm overrides and native alarm source overrides), deployments, debug view, debug snapshot, parked message queries, site event log queries. Site scoping is enforced for site-scoped Deployment users.
|
- **Deployment** role required for: instance management (including instance alarm overrides and native alarm source overrides), deployments, debug view, debug snapshot, parked message queries, site event log queries. Site scoping is enforced for site-scoped Deployment users.
|
||||||
|
- **Any of Design / Deployment** required for: area management (`CreateAreaCommand` / `UpdateAreaCommand` / `DeleteAreaCommand`). Areas are authored both in the Designer tooling and inside the Central UI Deployment Topology workflow (`Topology.razor` is `RequireDeployment`), so either role qualifies — enforced as an any-of gate (arch-review C6). Administrator is not implicitly included.
|
||||||
- **Operator** role required for: submitting a secured write (`SubmitSecuredWriteCommand`).
|
- **Operator** role required for: submitting a secured write (`SubmitSecuredWriteCommand`).
|
||||||
- **Verifier** role required for: approving / rejecting a secured write (`ApproveSecuredWriteCommand` / `RejectSecuredWriteCommand`). The no-self-approval rule (`Operator ≠ Verifier`) is enforced in the handler, independent of the role check.
|
- **Verifier** role required for: approving / rejecting a secured write (`ApproveSecuredWriteCommand` / `RejectSecuredWriteCommand`). The no-self-approval rule (`Operator ≠ Verifier`) is enforced in the handler, independent of the role check.
|
||||||
- **Any of Operator / Verifier / Administrator** required for: listing / querying secured writes (`ListSecuredWritesCommand`). Read-only, but the history exposes process-sensitive tag values, so it is gated any-of rather than open to every authenticated user (arch-review UA1). Enforced as an any-of gate (`GetRequiredRoles` returns the permitted set; the caller must hold at least one).
|
- **Any of Operator / Verifier / Administrator** required for: listing / querying secured writes (`ListSecuredWritesCommand`). Read-only, but the history exposes process-sensitive tag values, so it is gated any-of rather than open to every authenticated user (arch-review UA1). Enforced as an any-of gate (`GetRequiredRoles` returns the permitted set; the caller must hold at least one).
|
||||||
|
|||||||
@@ -85,7 +85,6 @@ Set in a local or docker-dev environment via the environment variable `ScadaBrid
|
|||||||
- **Permissions**:
|
- **Permissions**:
|
||||||
- Manage site definitions.
|
- Manage site definitions.
|
||||||
- Manage site-level data connections (define and assign to sites).
|
- Manage site-level data connections (define and assign to sites).
|
||||||
- Manage area definitions per site.
|
|
||||||
- Manage LDAP group-to-role mappings.
|
- Manage LDAP group-to-role mappings.
|
||||||
- Manage API keys (create, enable/disable, delete).
|
- Manage API keys (create, enable/disable, delete).
|
||||||
- System-level configuration.
|
- System-level configuration.
|
||||||
@@ -100,12 +99,14 @@ Set in a local or docker-dev environment via the environment variable `ScadaBrid
|
|||||||
- Manage database connection definitions.
|
- Manage database connection definitions.
|
||||||
- Manage notification lists and SMTP configuration.
|
- Manage notification lists and SMTP configuration.
|
||||||
- Manage inbound API method definitions.
|
- Manage inbound API method definitions.
|
||||||
|
- Manage area definitions per site (any-of with Deployer — see note below).
|
||||||
- Run on-demand validation (template flattening, script compilation).
|
- Run on-demand validation (template flattening, script compilation).
|
||||||
|
|
||||||
### Deployer
|
### Deployer
|
||||||
- **Scope**: System-wide or site-scoped.
|
- **Scope**: System-wide or site-scoped.
|
||||||
- **Permissions**:
|
- **Permissions**:
|
||||||
- Create and manage instances (overrides, connection bindings, area assignment).
|
- Create and manage instances (overrides, connection bindings, area assignment).
|
||||||
|
- Manage area definitions per site (any-of with Designer — see note below).
|
||||||
- Disable, enable, and delete instances.
|
- Disable, enable, and delete instances.
|
||||||
- Deploy configurations to instances.
|
- Deploy configurations to instances.
|
||||||
- Deploy system-wide artifacts (shared scripts, external system definitions, DB connections, data connections) to all sites.
|
- Deploy system-wide artifacts (shared scripts, external system definitions, DB connections, data connections) to all sites.
|
||||||
@@ -116,6 +117,8 @@ Set in a local or docker-dev environment via the environment variable `ScadaBrid
|
|||||||
- View site event logs.
|
- View site event logs.
|
||||||
- **Site scoping**: A user with site-scoped Deployer role can only perform these actions for instances at their permitted sites.
|
- **Site scoping**: A user with site-scoped Deployer role can only perform these actions for instances at their permitted sites.
|
||||||
|
|
||||||
|
> **Area management (arch-review C6)**: Managing area definitions per site is gated **any-of [Designer, Deployer]**, not Administrator. Areas are authored both in the Designer tooling and inside the Central UI Deployment Topology workflow (`Topology.razor` is `RequireDeployment`), so either role qualifies; Administrator is not implicitly included in the actor gate.
|
||||||
|
|
||||||
### Viewer
|
### Viewer
|
||||||
- **Scope**: System-wide (always).
|
- **Scope**: System-wide (always).
|
||||||
- **Permissions**:
|
- **Permissions**:
|
||||||
|
|||||||
@@ -167,6 +167,15 @@ public class ManagementActor : ReceiveActor
|
|||||||
private static readonly string[] OperatorOnly = [Roles.Operator];
|
private static readonly string[] OperatorOnly = [Roles.Operator];
|
||||||
private static readonly string[] VerifierOnly = [Roles.Verifier];
|
private static readonly string[] VerifierOnly = [Roles.Verifier];
|
||||||
|
|
||||||
|
// arch-review C6: area management is reconciled to any-of [Designer, Deployer].
|
||||||
|
// Areas are authored on both real surfaces — the Designer template/topology
|
||||||
|
// tooling AND the Central UI Deployment Topology workflow (Topology.razor is
|
||||||
|
// RequireDeployment) — so a pure Deployer must be able to create/update/delete
|
||||||
|
// them. The three requirements docs' historical "Administrator" assignment was
|
||||||
|
// stale; Administrator is not implicitly included here, matching the actor's
|
||||||
|
// any-of treatment of every other Designer/Deployer command.
|
||||||
|
private static readonly string[] AreaManagers = [Roles.Designer, Roles.Deployer];
|
||||||
|
|
||||||
// arch-review UA1: the Secured Writes history table exposes
|
// arch-review UA1: the Secured Writes history table exposes
|
||||||
// process-sensitive tag values, so reading it is restricted to the
|
// process-sensitive tag values, so reading it is restricted to the
|
||||||
// two-person Secured Write roles plus Administrator (any-of) — NOT any
|
// two-person Secured Write roles plus Administrator (any-of) — NOT any
|
||||||
@@ -205,9 +214,13 @@ public class ManagementActor : ReceiveActor
|
|||||||
or UpdateSmtpConfigCommand
|
or UpdateSmtpConfigCommand
|
||||||
or UpdateSmsConfigCommand => AdminOnly,
|
or UpdateSmsConfigCommand => AdminOnly,
|
||||||
|
|
||||||
|
// Area management — any-of [Designer, Deployer] (arch-review C6).
|
||||||
|
// Exposed both in the Designer tooling and inside the Central UI
|
||||||
|
// Deployment Topology workflow (RequireDeployment), so both roles qualify.
|
||||||
|
CreateAreaCommand or UpdateAreaCommand or DeleteAreaCommand => AreaManagers,
|
||||||
|
|
||||||
// Designer operations
|
// Designer operations
|
||||||
CreateAreaCommand or DeleteAreaCommand
|
CreateTemplateCommand or UpdateTemplateCommand or DeleteTemplateCommand
|
||||||
or CreateTemplateCommand or UpdateTemplateCommand or DeleteTemplateCommand
|
|
||||||
or ValidateTemplateCommand
|
or ValidateTemplateCommand
|
||||||
or CreateExternalSystemCommand or UpdateExternalSystemCommand
|
or CreateExternalSystemCommand or UpdateExternalSystemCommand
|
||||||
or DeleteExternalSystemCommand
|
or DeleteExternalSystemCommand
|
||||||
@@ -227,7 +240,6 @@ public class ManagementActor : ReceiveActor
|
|||||||
or CreateSharedSchemaCommand or UpdateSharedSchemaCommand or DeleteSharedSchemaCommand
|
or CreateSharedSchemaCommand or UpdateSharedSchemaCommand or DeleteSharedSchemaCommand
|
||||||
or CreateDatabaseConnectionDefCommand or UpdateDatabaseConnectionDefCommand or DeleteDatabaseConnectionDefCommand
|
or CreateDatabaseConnectionDefCommand or UpdateDatabaseConnectionDefCommand or DeleteDatabaseConnectionDefCommand
|
||||||
or CreateApiMethodCommand or UpdateApiMethodCommand or DeleteApiMethodCommand
|
or CreateApiMethodCommand or UpdateApiMethodCommand or DeleteApiMethodCommand
|
||||||
or UpdateAreaCommand
|
|
||||||
or CreateTemplateFolderCommand or RenameTemplateFolderCommand
|
or CreateTemplateFolderCommand or RenameTemplateFolderCommand
|
||||||
or MoveTemplateFolderCommand or ReorderTemplateFolderCommand or DeleteTemplateFolderCommand
|
or MoveTemplateFolderCommand or ReorderTemplateFolderCommand or DeleteTemplateFolderCommand
|
||||||
or MoveTemplateToFolderCommand
|
or MoveTemplateToFolderCommand
|
||||||
|
|||||||
@@ -3125,4 +3125,31 @@ public class ManagementActorTests : TestKit, IDisposable
|
|||||||
Arg.Is<Commons.Entities.ExternalSystems.ExternalSystemDefinition>(d => d.TimeoutSeconds == 42),
|
Arg.Is<Commons.Entities.ExternalSystems.ExternalSystemDefinition>(d => d.TimeoutSeconds == 42),
|
||||||
Arg.Any<CancellationToken>());
|
Arg.Any<CancellationToken>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Area management role gate (arch-review C6): reconciled to any-of
|
||||||
|
// [Designer, Deployer]. The Central UI creates areas inside the Deployment
|
||||||
|
// Topology workflow (RequireDeployment), so a pure-Deployer must be allowed.
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("Designer")]
|
||||||
|
[InlineData("Deployer")]
|
||||||
|
public void CreateArea_DesignerOrDeployer_Allowed(string role)
|
||||||
|
{
|
||||||
|
var actor = CreateActor();
|
||||||
|
actor.Tell(Envelope(new CreateAreaCommand(1, "Area1", null), role));
|
||||||
|
// The gate must let both roles through. Dispatch may still fail (no
|
||||||
|
// AreaService wired), but it must NOT be an authorization rejection.
|
||||||
|
var resp = ExpectMsg<object>(TimeSpan.FromSeconds(5));
|
||||||
|
Assert.IsNotType<ManagementUnauthorized>(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateArea_ViewerOnly_Unauthorized()
|
||||||
|
{
|
||||||
|
var actor = CreateActor();
|
||||||
|
actor.Tell(Envelope(new CreateAreaCommand(1, "Area1", null), "Viewer"));
|
||||||
|
ExpectMsg<ManagementUnauthorized>(TimeSpan.FromSeconds(5));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user