Complete management API and CLI command parity

This commit is contained in:
Joseph Doherty
2026-09-10 00:51:45 -04:00
parent 477e2abe97
commit 2750bd2809
38 changed files with 1637 additions and 199 deletions
+33 -5
View File
@@ -44,7 +44,7 @@ Every command accepts `--format json` (default) or `--format table`. For JSON ou
## Architecture
`Program.cs` builds the `RootCommand` tree, attaches the four global options (`--url`, `--username`, `--password`, `--format`), and registers each command group:
`Program.cs` invokes `CliApplication.BuildRoot()`, which builds the `RootCommand` tree, attaches the four global options (`--url`, `--username`, `--password`, `--format`), and registers each command group:
```csharp
rootCommand.Add(TemplateCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
@@ -59,10 +59,14 @@ rootCommand.Add(AuditLogCommands.Build(urlOption, formatOption, usernameOption,
rootCommand.Add(AuditCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
rootCommand.Add(HealthCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
rootCommand.Add(DebugCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
rootCommand.Add(SharedSchemaCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
rootCommand.Add(SharedScriptCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
rootCommand.Add(DbConnectionCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
rootCommand.Add(ApiMethodCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
rootCommand.Add(BundleCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
rootCommand.Add(CachedCallCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
rootCommand.Add(SecuredWriteCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
rootCommand.Add(FlowDebugCommands.Build(urlOption, formatOption, usernameOption, passwordOption));
```
Every command's action delegates to `CommandHelpers.ExecuteCommandAsync`, which owns the URL/credential resolution, `ManagementHttpClient` lifetime, and exit-code mapping. This consolidation means the authorization-failure exit code (`2`) is enforced uniformly — including for the `bundle` group, which uses `ExecuteCommandAsync` with a longer 5-minute timeout and a per-command `onSuccess` handler rather than a separate HTTP path.
@@ -105,14 +109,18 @@ scadabridge instance deploy --id 7
| Group | Subcommands | Role required |
|-------|-------------|---------------|
| `template` | `list`, `get`, `create`, `update`, `delete`, `validate`; `attribute add/update/delete`; `alarm add/update/delete`; `script add/update/delete`; `composition add/delete`; `native-alarm-source add/list/remove` | `Design` |
| `instance` | `list`, `get`, `create`, `set-bindings`, `set-overrides`, `alarm-override set/delete/list`, `native-alarm-source set/clear`, `set-area`, `diff`, `deploy`, `enable`, `disable`, `delete` | `Deployment` |
| `template` | `list`, `get`, `create`, `update`, `delete`, `validate`, `resolved-members`, `move`; `attribute add/update/delete`; `alarm add/update/delete`; `script add/update/delete`; `composition add/delete`; `native-alarm-source add/list/update/remove` | `Design` |
| `instance` | `list`, `get`, `create`, `set-bindings`, `set-overrides`, `alarm-override set/delete/list`, `native-alarm-source set/clear/list/import`, `attribute-override delete`, `set-area`, `diff`, `deploy`, `enable`, `disable`, `delete` | `Deployment` |
| `site` | `list`, `get`, `create`, `delete`, `deploy-artifacts`; `area list/create/update/delete` | `Admin` |
| `deploy` | `instance`, `artifacts`, `status` | `Deployment` |
| `data-connection` | `list`, `get`, `create`, `update`, `delete` | `Design` / `Deployment` |
| `data-connection` | `list`, `get`, `create`, `update`, `delete`, `move`; `browse`, `search`, `verify-endpoint`, `certs` | `Design` / `Deployment` |
| `external-system` | `list`, `get`, `create`, `update`, `delete` | `Design` |
| `notification` | `list`, `get`, `create`, `update`, `delete`; `smtp list/update` | `Design` / `Admin` |
| `notification` | `list`, `get`, `create`, `update`, `delete`, `rename`; `recipient add/delete`; `smtp list/create/update`; `sms list/create/update` | `Design` / `Admin` |
| `security` | `api-key list/create/update/delete/set-methods`; `role-mapping list/create/update/delete`; `scope-rule list/add/delete` | `Admin` |
| `shared-schema` | `list`, `get`, `create`, `update`, `delete` | Read: authenticated; mutations: Designer |
| `secured-write` | `list`, `submit`, `approve`, `reject` | Operator / Verifier / Administrator, enforced per operation |
| `cached-call` | `list`, `retry`, `discard` | Server-enforced operational roles and site scope |
| `flow-debug` | `run-method`, `run-script`, `run-value-change`, `replay` | Deployer; replay also accepts OperationalAudit roles |
| `shared-script` | `list`, `get`, `create`, `update`, `delete` | `Design` |
| `db-connection` | `list`, `get`, `create`, `update`, `delete` | `Design` |
| `api-method` | `list`, `get`, `create`, `update`, `delete` | `Design` |
@@ -248,3 +256,23 @@ The `audit-log` command group was renamed to `audit-config` in M8 of Audit Log (
- [Audit Log](./AuditLog.md)
- [Security](./Security.md)
- [Commons](./Commons.md)
## Management parity and deadlines
All 149 HTTP-eligible management contracts are exposed across 20 production CLI
groups, including the `shared-schema` library and the secured-write lifecycle.
The [parity additions](../../src/ZB.MOM.WW.ScadaBridge.CLI/README.md#management-parity-additions-2026-09-10)
document the individual notification edits, provider creation, template and
instance operations, connection relocation, and SMS policy flags.
The production-root loopback test requires actual HTTP dispatch for every
eligible contract. A separate actor test verifies every registered contract has
a handler. `ReadTagValues` remains site-only and `ResolveRoles` remains retired;
both are excluded from HTTP name resolution.
Every instance/artifact/site deployment alias lets the server own the overall
deadline, while retaining a bounded connect timeout. This prevents the ordinary
30-second client timer from abandoning a deployment still applying at the server.
Secured-write approval interprets execution status as well as HTTP success:
only `Executed` exits zero; failed execution or an invalid response exits one.
+11
View File
@@ -241,3 +241,14 @@ Any exception that is not a `ManagementCommandException` or `SiteScopeViolationE
- [Security](./Security.md)
- [Audit Log](./AuditLog.md)
- [Host](./Host.md)
## HTTP command eligibility
`ManagementCommandRegistry` includes 149 executable HTTP contracts. The site-only
`ReadTagValuesCommand` and retired `ResolveRolesCommand` remain internal message
types but are excluded from the HTTP registry, so `/management` rejects those
names as unknown commands instead of accepting an undispatchable request. Site
gRPC tag-read serialization and server-side LDAP role resolution are unchanged.
The dispatch-coverage test now checks every HTTP-registered contract without
exemptions, including create records inherited from update records.
@@ -2,17 +2,17 @@
**Date:** 2026-09-10
**Reviewed revision:** `9ee402bb`
**Status:** Findings recorded; remediation not started.
**Status:** Remediation in progress on `codex/management-cli-parity`.
## Scope and method
## Original review scope and method
Source-level comparison of management command records, automatic HTTP command
registration, ManagementActor dispatch (including inherited record types), CLI
command construction and registration, and management audit REST endpoints.
No live mutations were performed and no tests were rerun for this review.
The CLI's 19 registered command groups and previously passing 475-test suite do
not establish complete actor/API parity. The inventory found:
At the reviewed revision, 19 registered command groups and the passing 475-test
suite did not establish complete actor/API parity. The baseline inventory found:
| Inventory | Count |
|---|---:|
@@ -31,24 +31,24 @@ is not counted as a missing operator command.
## Missing CLI operations
All 19 commands below are handled by the actor and reachable through the generic
`POST /management` API, subject to server-side authorization. Each remains open;
the secured-write limitation is already documented and may be retained as an
explicit product decision rather than implemented.
`POST /management` API, subject to server-side authorization. Remediation adds
all 19, including the full secured-write lifecycle. The descriptions below retain
the original findings; status cells and completion evidence track the fixes.
| ID | Capability | Missing command contracts | Status |
|---|---|---|---|
| GAP-01 | Shared-schema library (5) | `ListSharedSchemasCommand`, `GetSharedSchemaCommand`, `CreateSharedSchemaCommand`, `UpdateSharedSchemaCommand`, `DeleteSharedSchemaCommand` | Open |
| GAP-02 | Secured-write lifecycle (3) | `SubmitSecuredWriteCommand`, `ApproveSecuredWriteCommand`, `RejectSecuredWriteCommand` | Open; documented listing-only CLI scope |
| GAP-03 | Individual notification editing (3) | `RenameNotificationListCommand`, `AddNotificationRecipientCommand`, `DeleteNotificationRecipientCommand` | Open |
| GAP-04 | Provider configuration creation (2) | `CreateSmtpConfigCommand`, `CreateSmsConfigCommand` | Open |
| GAP-05 | Template inspection and editing (3) | `GetResolvedTemplateMembersCommand`, `MoveTemplateToFolderCommand`, `UpdateTemplateNativeAlarmSourceCommand` | Open |
| GAP-06 | Instance override management (2) | `DeleteInstanceAttributeOverrideCommand`, `ListInstanceNativeAlarmSourceOverridesCommand` | Open |
| GAP-07 | Data-connection relocation (1) | `MoveDataConnectionCommand` | Open |
| GAP-01 | Shared-schema library (5) | `ListSharedSchemasCommand`, `GetSharedSchemaCommand`, `CreateSharedSchemaCommand`, `UpdateSharedSchemaCommand`, `DeleteSharedSchemaCommand` | Completed |
| GAP-02 | Secured-write lifecycle (3) | `SubmitSecuredWriteCommand`, `ApproveSecuredWriteCommand`, `RejectSecuredWriteCommand` | Completed; full lifecycle exposed |
| GAP-03 | Individual notification editing (3) | `RenameNotificationListCommand`, `AddNotificationRecipientCommand`, `DeleteNotificationRecipientCommand` | Completed |
| GAP-04 | Provider configuration creation (2) | `CreateSmtpConfigCommand`, `CreateSmsConfigCommand` | Completed |
| GAP-05 | Template inspection and editing (3) | `GetResolvedTemplateMembersCommand`, `MoveTemplateToFolderCommand`, `UpdateTemplateNativeAlarmSourceCommand` | Completed |
| GAP-06 | Instance override management (2) | `DeleteInstanceAttributeOverrideCommand`, `ListInstanceNativeAlarmSourceOverridesCommand` | Completed |
| GAP-07 | Data-connection relocation (1) | `MoveDataConnectionCommand` | Completed |
Evidence:
- [ManagementActor dispatch](../../src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs)
- [CLI root registration](../../src/ZB.MOM.WW.ScadaBridge.CLI/Program.cs)
- [CLI root registration](../../src/ZB.MOM.WW.ScadaBridge.CLI/CliApplication.cs)
- [CLI command implementations](../../src/ZB.MOM.WW.ScadaBridge.CLI/Commands/)
- [Management command contracts](../../src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/)
@@ -57,14 +57,14 @@ contracts and are dispatched through the corresponding update handlers. They
are not unhandled API contracts. The handlers distinguish the create subtype;
sending an ordinary update with ID zero is not equivalent.
## Behavioral and contract findings
## Original behavioral and contract findings
Severity is a review estimate. These findings overlap the operation inventory;
do not add the row counts together as unique missing commands.
### PAR-01 — Deployment deadlines differ between API and CLI
**Severity:** Medium · **Status:** Open
**Severity:** Medium · **Status:** Completed
`deploy instance`, `instance deploy`, `deploy artifacts`, and
`site deploy-artifacts` use the default 30-second CLI request deadline. The API
@@ -84,7 +84,7 @@ policy and add delayed-response regression coverage for every CLI alias.
### PAR-02 — Notification replacement is not equivalent to individual editing
**Severity:** Medium · **Status:** Open · **Related:** GAP-03
**Severity:** Medium · **Status:** Completed · **Related:** GAP-03
The existing CLI whole-list update reaches `HandleUpdateNotificationList`, which
deletes existing recipients and recreates them. It cannot faithfully replace
@@ -99,7 +99,7 @@ verify unrelated recipients retain their identities and names.
### PAR-03 — SMS retry and timeout options are missing
**Severity:** Low · **Status:** Open
**Severity:** Low · **Status:** Completed
The actor/API accept `ConnectionTimeoutSeconds`, `MaxRetries`, and `RetryDelay`
on `UpdateSmsConfigCommand`. CLI payload construction supplies none of these
@@ -116,7 +116,7 @@ explicit values and omission behavior against the API contract.
### PAR-04 — Registry accepts two contracts the actor cannot dispatch
**Severity:** Low · **Status:** Open
**Severity:** Low · **Status:** Completed
The registry automatically includes every concrete `*Command` type in the
management namespace. `ReadTagValuesCommand` and `ResolveRolesCommand` therefore
@@ -140,7 +140,7 @@ flow's security restriction.
### PAR-05 — Tests do not enforce complete surface parity
**Severity:** Low · **Status:** Open
**Severity:** Low · **Status:** Completed
Command-tree tests verify existing groups and selected operations, but do not
require every supported actor command to map to a CLI command or an explicit
@@ -163,3 +163,77 @@ inheritance, and test representative payload fields and deadline policies.
This is a bounded surface comparison, not an exhaustive security audit or a
field-by-field review of all 130 CLI-referenced contracts.
## Implementation plan and progress
The requested remediation implements all 19 CLI mappings, including secured-write
submit/approve/reject through existing server authorization. The HTTP registry
will exclude site-only ReadTagValues and retired ResolveRoles contracts; their
internal types remain intact. Existing update semantics remain compatible.
| Work package | Files / scope | Verification | Status |
|---|---|---|---|
| Notifications | CLI NotificationCommands; focused notification tests; GAP-03/04, PAR-02/03 | Capture real command payloads, preserve named recipients, create and optional SMS settings | Completed |
| Template/instance/connection commands | CLI TemplateCommands, InstanceCommands, DataConnectionCommands; GAP-05/06/07 | Parse and HTTP-envelope regressions for every added operation | Completed |
| Schema and secured writes | New SharedSchemaCommands, SecuredWriteCommands; GAP-01/02 | Real command payloads, role enforcement remains server-side | Completed |
| Deadline and registry policy | CommandHelpers, Commons registry, API tests; PAR-01/04 | Delayed responses for all deploy aliases; rejected HTTP-ineligible contracts | Completed |
| Parity gate and integration | CLI root, command mapping tests, CLI docs; PAR-05 | Exhaustive registry/dispatch/CLI mapping with explicit internal exclusions | Completed |
| Completion | Full solution build/tests, local deployment/read-only smoke, report updates, merge/commit/push | Fresh verification evidence recorded below | In progress |
Each package follows failing regression tests, minimal implementation, focused
verification, and code review. Builds/tests use a shared lock in this worktree to
avoid concurrent dotnet output races. The final merge and git operations are
owned by the primary agent.
### Progress checkpoint
- Notification/Smtp/Sms focused suite: 52 passed, including 19 new parse/HTTP cases.
- Editing parity: 15 passed, covering all six added operations and an existing alias.
- Deployment deadline regression: all four aliases now accept the server's response
after 31 seconds; the same test failed with the old 30-second client deadline.
- HTTP registry regressions: 11 passed; ReadTagValues and ResolveRoles no longer resolve.
- Production-root parity probe: all 149 HTTP-eligible contracts actually dispatched
to a loopback recorder. Removing the schema group produces missing coverage.
- Independent review approved the editing and notification mappings. Additional
actor preservation coverage and secured-write execution-failure exit handling
are being verified before final completion.
### Independent review follow-ups
- Added email and SMS actor-dispatch preservation tests: rename, add, and delete
leave the existing named recipient and ID untouched (2 passed).
- Secured-write approval now treats HTTP 200 with `status: Failed` as CLI failure,
and rejects malformed or unexpected approval outcomes. Schema/secured focused
tests: 33 passed, including existing listing behavior and new outcome checks.
- Fixed a pre-existing blind spot in the actor dispatch gate: its sentinel now
passes through the configuration transaction before throwing on handler
dependencies. A negative control detects an unsupported command (2 passed).
- New CLI tests that invoke Console-writing actions share the Console collection
to avoid racing tests that redirect process-global output.
All implementation packages are present. Final solution verification, canonical
local deployment, and integration remain in progress.
### Final pre-integration verification
- Full solution build: zero warnings and errors.
- Full solution run (excluding deployed Playwright): 9,551 passed, one failure in
the UI toast unobserved-exception test. Root cause was unrelated incomplete
JavaScript success stubs in UI fixtures; no product UI behavior changed.
- Fixed 15 successful void stubs across 11 fixtures to complete explicitly. Two
direct regression tests failed before and passed after. Full CentralUI rerun:
**1,418/1,418 passed**; the original toast assertion remains unchanged.
- Replacing the initial UI result with the corrected full UI suite gives
**9,554 passed, zero outstanding failures or skips** across 29 test suites.
Key suites: CLI **543**, ManagementService **665**, Commons **852**,
Communication **766**, Integration **118**, Host **598**.
- Documentation links and `git diff --check` passed. All GAP-01 through GAP-07 and
PAR-01 through PAR-05 are complete. Canonical deployment and final merge/push
evidence will be added after integration.
Local verification logs: `/tmp/parity-full-build.log`, `/tmp/parity-full-tests.log`,
`/tmp/parity-ui-red.log`, `/tmp/parity-ui-green.log`, `/tmp/parity-ui-full.log`.
These logs are local evidence, not committed artifacts.
+22 -1
View File
@@ -447,7 +447,7 @@ Configuration is resolved in the following priority order (highest wins):
## Error Handling
- **Connection failure**: If the CLI cannot connect to the management URL (e.g., DNS failure, connection refused), it exits with code 1 and a descriptive error message.
- **Command timeout**: If the server does not respond within 30 seconds, the command fails with a timeout error (HTTP 504).
- **Command timeout**: Ordinary CLI commands use a 30-second client deadline. All instance/artifact/site deployment aliases defer the overall deadline to the server, retaining a bounded socket-connect timeout. Server Ask expiry returns HTTP 504; a client deadline is reported locally. Bundle and Flow Debugger commands retain their explicit timeout policies.
- **Authentication failure**: If the server returns HTTP 401 (LDAP bind failed), the CLI exits with code 1.
- **Authorization failure**: If the server returns HTTP 403, the CLI exits with code 2.
@@ -472,3 +472,24 @@ deploy site preserves the returned summary in JSON/table output and exits 1 when
is nonzero or the summary is malformed, even when HTTP returned 2xx. A zero failure count exits
0; HTTP authorization failures retain exit 2. The server owns the bounded bulk operation deadline;
the client does not impose a shorter total timer on this command.
## Management parity (2026-09-10)
The CLI exposes all 149 HTTP-eligible management contracts. The production root
is constructed by `CliApplication.BuildRoot`; the test suite invokes that tree
against a loopback HTTP recorder and requires every registered contract to be
sent, with a negative control for a removed group. Actor dispatch coverage uses
the same HTTP eligibility boundary with no unhandled-command exemptions.
Added operations include the five `shared-schema` CRUD commands, secured-write
submit/approve/reject, notification rename and individual recipient add/delete,
SMTP/SMS create, effective template member inspection, template folder moves,
native alarm source updates, individual attribute-override deletion, native alarm
override listing, and data-connection moves. SMS timeout/retry settings are also
exposed. Their exact syntax and omission semantics are maintained in the
[CLI command reference](../../src/ZB.MOM.WW.ScadaBridge.CLI/README.md#management-parity-additions-2026-09-10).
All additions retain server-owned roles, scope restrictions, validation, and audit
handling. In particular, secured-write approval requires a different verifier
identity and exits with failure when the returned device execution failed.