Files
ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CLI/README.md
T
Joseph Doherty 639e331db1 test+docs(m5): M5.7 — de-date 2 EndToEnd purge tests (closes #52); document T3-T8 in Component-AuditLog/-CLI/README/CLAUDE
Tests: anchor SeedOccurredAt() to a fixed thresholdAnchor (2026-01-20) and compute
RetentionDays dynamically (UtcNow - anchor + 1d) so the threshold always sits near
Jan 20 2026, between the Jan-15 "old" seed (purged) and Apr-15/Jun-15 "kept" seeds.
Seed dates stay within the explicit pf_AuditLog_Month boundary range (Jan 2026 –
Dec 2027) — relative-from-now offsets landed before 2026-01-01 (the catch-all
partition, invisible to GetPartitionBoundariesOlderThanAsync). Both tests confirmed
passing; all 284 AuditLog tests green.

Docs:
- Component-AuditLog.md: per-channel retention overrides (T3, PerChannelRetentionDays
  + bounded DELETE + AuditLogPurge:ChannelPurgeBatchSize); ParentExecutionId tag-cascade
  now spans alarm-triggered + nested CallScript/CallShared + inbound→routed (T4, "no
  further spawn points deferred"); per-node stuck KPIs for Notification Outbox +
  Site Call Audit (T6); T7 structured response-capture increments (request headers in
  Extra.requestHeaders, AuditInboundCeilingHits counter, per-method SkipBodyCapture);
  T8 CLI audit tree; T1 hash-chain + T2 Parquet explicitly marked deferred to v1.x.
- Component-CLI.md + README.md: document audit tree --execution-id <guid> and
  audit backfill-source-node --sentinel/--before/--batch with exact options verified
  against AuditCommands.cs; update Interactions to list new endpoints.
- CLAUDE.md: update audit-log design-decision bullets for T3 per-channel retention,
  T4 tag-cascade complete, T6 per-node KPIs, T7 inbound capture increments, T8 tree
  command; clarify T1/T2 remain deferred to v1.x.
2026-06-16 22:26:09 -04:00

55 KiB
Raw Blame History

ScadaBridge CLI

Command-line tool for managing the ScadaBridge SCADA system. Connects to a Central node via HTTP and routes commands through the Management API endpoint (POST /management), which dispatches to the ManagementActor. Authentication is handled server-side via LDAP.

Installation

dotnet build src/ZB.MOM.WW.ScadaBridge.CLI

The output binary is scadabridge (or scadabridge.exe on Windows).

Connection

Every command requires a connection to a running Central node. The management URL can be supplied three ways, evaluated in this priority order:

  1. --url flag on the command line
  2. SCADABRIDGE_MANAGEMENT_URL environment variable
  3. managementUrl field in ~/.scadabridge/config.json
scadabridge --url http://central-host:5000 <command>

Docker: With the Docker setup, the Central UI (and management API) is available at http://localhost:9001:

scadabridge --url http://localhost:9001 <command>

For HA failover, use a load balancer URL. The management API is stateless (Basic Auth per request), so any central node can handle any request without sticky sessions.

Global Options

These options are accepted by the root command and inherited by all subcommands.

Option Description
--url <value> Management API URL (e.g., http://localhost:9001)
--username <value> LDAP username for authentication
--password <value> LDAP password for authentication
--format <json|table> Output format (default: json)

Configuration File

~/.scadabridge/config.json is loaded at startup. All fields are optional.

{
  "managementUrl": "http://localhost:9001"
}

For the Docker test environment, see docker/README.md for a ready-to-use config.

Environment Variables

Variable Description
SCADABRIDGE_MANAGEMENT_URL Management API URL (overrides config file)
SCADABRIDGE_FORMAT Default output format (overrides config file)
SCADABRIDGE_USERNAME LDAP username (fallback when --username is not supplied)
SCADABRIDGE_PASSWORD LDAP password (fallback when --password is not supplied). Preferred over --password on the command line, which leaks into process listings and shell history.

Output

All commands write JSON to stdout on success. Errors are written as JSON to stderr:

{ "error": "Human-readable message", "code": "ERROR_CODE" }

Exit codes:

Code Meaning
0 Success
1 Command error
2 Authorization failure

Command Reference

template — Manage templates

template list

List all templates with their full attribute, alarm, script, and composition definitions.

scadabridge --url <url> template list

template get

Get a single template by ID.

scadabridge --url <url> template get --id <int>
Option Required Description
--id yes Template ID

template create

Create a new template, optionally inheriting from a parent.

scadabridge --url <url> template create --name <string> [--description <string>] [--parent-id <int>]
Option Required Description
--name yes Template name
--description no Template description
--parent-id no Parent template ID for inheritance

template update

Update an existing template. An update replaces the whole entity — every required field below must be supplied with the value it should have after the update, even if it is unchanged.

scadabridge --url <url> template update --id <int> --name <string> [--description <string>] [--parent-id <int>]
Option Required Description
--id yes Template ID
--name yes Template name
--description no Updated description
--parent-id no Updated parent template ID

template delete

Delete a template by ID.

scadabridge --url <url> template delete --id <int>
Option Required Description
--id yes Template ID

template validate

Run pre-deployment validation on a template (flattening, naming collisions, script compilation).

scadabridge --url <url> template validate --id <int>
Option Required Description
--id yes Template ID

template attribute add

Add an attribute to a template.

scadabridge --url <url> template attribute add --template-id <int> --name <string> --data-type <string> [--value <string>] [--element-type <string>] [--description <string>] [--data-source <string>] [--locked]
Option Required Description
--template-id yes Template ID
--name yes Attribute name
--data-type yes Attribute data type (Boolean, Int32, Float, Double, String, DateTime, List)
--value no Default value. For a List attribute, supply a JSON array (e.g. '["WO-1","WO-2"]'); the raw string is forwarded to the API, which parses it
--element-type no Element scalar type for a List attribute (String, Int32, Float, Double, Boolean, DateTime). Required when --data-type is List; must be omitted otherwise
--description no Description
--data-source no Data source reference
--locked no Lock the attribute in derived templates

List example — add a multi-value String attribute with two default elements:

scadabridge --url <url> template attribute add --template-id 7 --name WorkOrders \
  --data-type List --element-type String --value '["WO-1","WO-2"]'

The CLI validates the data-type / element-type combination locally before calling the API: --data-type List requires a valid --element-type, and --element-type may only be supplied when --data-type is List. The Management API re-validates server-side.

template attribute update

Update an attribute on a template. An update replaces the whole entity — every required field below must be supplied with its post-update value, even if unchanged.

scadabridge --url <url> template attribute update --id <int> --name <string> --data-type <string> [--value <string>] [--element-type <string>] [--description <string>] [--data-source <string>] [--locked]
Option Required Description
--id yes Attribute ID
--name yes Attribute name
--data-type yes Attribute data type (Boolean, Int32, Float, Double, String, DateTime, List)
--value no Default value. For a List attribute, supply a JSON array (e.g. '["WO-1","WO-2"]')
--element-type no Element scalar type for a List attribute (String, Int32, Float, Double, Boolean, DateTime). Required when --data-type is List; must be omitted otherwise
--description no Description
--data-source no Data source reference
--locked no Lock the attribute in derived templates

template attribute delete

Remove an attribute from a template.

scadabridge --url <url> template attribute delete --id <int>
Option Required Description
--id yes Attribute ID

template alarm add

Add an alarm definition to a template.

scadabridge --url <url> template alarm add --template-id <int> --name <string> --trigger-type <string> --priority <int> [--description <string>] [--trigger-config <json>] [--locked] [typed-setpoint-flags]
Option Required Description
--template-id yes Template ID
--name yes Alarm name
--trigger-type yes Trigger type (e.g. ValueMatch, RangeViolation, RateOfChange, HiLo, Expression)
--priority yes Alarm priority (01000)
--description no Description
--trigger-config no Trigger configuration as a JSON string (overrides typed flags when both are supplied)
--locked no Lock the alarm in derived templates
--attribute no Attribute name the trigger watches (all trigger types except Expression)
--match-value no ValueMatch: value to compare against
--not-equals no ValueMatch: match when the value is NOT equal
--min no RangeViolation: minimum allowed value
--max no RangeViolation: maximum allowed value
--threshold-per-second no RateOfChange: rate threshold per second
--window-seconds no RateOfChange: sliding window in seconds
--direction no RateOfChange: direction (rising, falling, or either)
--lolo no HiLo: low-low setpoint
--lo no HiLo: low setpoint
--hi no HiLo: high setpoint
--hihi no HiLo: high-high setpoint
--expression no Expression: boolean trigger expression

template alarm update

Update an alarm definition on a template. An update replaces the whole entity — every required field below must be supplied with its post-update value, even if unchanged.

scadabridge --url <url> template alarm update --id <int> --name <string> --trigger-type <string> --priority <int> [--description <string>] [--trigger-config <json>] [--locked]
Option Required Description
--id yes Alarm ID
--name yes Alarm name
--trigger-type yes Trigger type
--priority yes Alarm priority (01000)
--description no Description
--trigger-config no Trigger configuration JSON
--locked no Lock the alarm in derived templates

template alarm delete

Remove an alarm definition from a template.

scadabridge --url <url> template alarm delete --id <int>
Option Required Description
--id yes Alarm ID

template native-alarm-source add

Bind a native alarm source to a template — a read-only mirror of an OPC UA Alarms & Conditions server's or the MxAccess Gateway's alarms (no ack-back).

scadabridge --url <url> template native-alarm-source add --template-id <int> --name <string> --connection <string> --source-ref <string> [--filter <string>] [--description <string>] [--locked]
Option Required Description
--template-id yes Template ID
--name yes Source binding name
--connection yes Alarm-capable data connection name (OPC UA or MxGateway)
--source-ref yes Source reference (OPC UA SourceNode nodeId, or MxAccess object/area)
--filter no Condition filter (omit to mirror all conditions under the source)
--description no Description
--locked no Lock the binding in derived templates

template native-alarm-source list

List the native alarm source bindings on a template.

scadabridge --url <url> template native-alarm-source list --template-id <int>

template native-alarm-source remove

Remove a native alarm source binding from a template (by its ID).

scadabridge --url <url> template native-alarm-source remove --id <int>

template script add

Add a script to a template.

scadabridge --url <url> template script add --template-id <int> --name <string> --trigger-type <string> --code <string> [--trigger-config <json>] [--locked] [--parameters <json>] [--return-def <json>]
Option Required Description
--template-id yes Template ID
--name yes Script name
--trigger-type yes Trigger type (e.g. OnChange, Periodic, OnAlarm)
--code yes Script source code
--trigger-config no Trigger configuration as a JSON string (e.g. interval, attribute name)
--locked no Lock the script in derived templates
--parameters no Parameter definitions JSON
--return-def no Return definition JSON

template script update

Update a script on a template. An update replaces the whole entity — every required field below must be supplied with its post-update value, even if unchanged.

scadabridge --url <url> template script update --id <int> --name <string> --trigger-type <string> --code <string> [--trigger-config <json>] [--locked] [--parameters <json>] [--return-def <json>]
Option Required Description
--id yes Script ID
--name yes Script name
--trigger-type yes Trigger type
--code yes Script source code
--trigger-config no Trigger configuration JSON
--locked no Lock the script in derived templates
--parameters no Parameter definitions JSON
--return-def no Return definition JSON

template script delete

Remove a script from a template.

scadabridge --url <url> template script delete --id <int>
Option Required Description
--id yes Script ID

template composition add

Add a feature module composition to a template.

scadabridge --url <url> template composition add --template-id <int> --composed-template-id <int> --instance-name <string>
Option Required Description
--template-id yes Target template ID
--composed-template-id yes Feature module template ID to compose
--instance-name yes Instance name for the composed module (used in path-qualified addressing)

template composition delete

Remove a feature module composition from a template, identified by its own composition ID.

scadabridge --url <url> template composition delete --id <int>
Option Required Description
--id yes Composition ID to remove

instance — Manage instances

instance get

Get a single instance by ID.

scadabridge --url <url> instance get --id <int>
Option Required Description
--id yes Instance ID

instance list

List instances, with optional filters.

scadabridge --url <url> instance list [--site-id <int>] [--template-id <int>] [--search <string>]
Option Required Description
--site-id no Filter by site ID
--template-id no Filter by template ID
--search no Search term matched against instance name

instance create

Create a new instance of a template at a site.

scadabridge --url <url> instance create --name <string> --template-id <int> --site-id <int> [--area-id <int>]
Option Required Description
--name yes Unique instance name
--template-id yes Template to instantiate
--site-id yes Site where the instance will run
--area-id no Area within the site

instance native-alarm-source set

Override an inherited native alarm source binding for a single instance (upsert). Blank options keep the inherited value.

scadabridge --url <url> instance native-alarm-source set --instance-id <int> --source <string> [--connection <string>] [--source-ref <string>] [--filter <string>]
Option Required Description
--instance-id yes Instance ID
--source yes Source binding canonical name (e.g. Pressure or Module.Pressure)
--connection no Connection name override (blank = inherited)
--source-ref no Source reference override (blank = inherited)
--filter no Condition filter override (blank = inherited)

instance native-alarm-source clear

Clear an instance's native alarm source override, reverting to the inherited binding.

scadabridge --url <url> instance native-alarm-source clear --instance-id <int> --source <string>

instance deploy

Deploy an instance to its site. Acquires the per-instance operation lock.

scadabridge --url <url> instance deploy --id <int>
Option Required Description
--id yes Instance ID

instance enable

Enable a previously disabled instance.

scadabridge --url <url> instance enable --id <int>
Option Required Description
--id yes Instance ID

instance disable

Disable a running instance without deleting it.

scadabridge --url <url> instance disable --id <int>
Option Required Description
--id yes Instance ID

instance delete

Delete an instance. The instance must be disabled first.

scadabridge --url <url> instance delete --id <int>
Option Required Description
--id yes Instance ID

instance set-bindings

Set data connection bindings for an instance's attributes.

scadabridge --url <url> instance set-bindings --id <int> --bindings <json>
Option Required Description
--id yes Instance ID
--bindings yes JSON array of [attributeName, dataConnectionId] pairs (e.g. [["Speed",7],["Temperature",7]])

instance set-overrides

Set attribute value overrides for an instance.

scadabridge --url <url> instance set-overrides --id <int> --overrides <json>
Option Required Description
--id yes Instance ID
--overrides yes JSON object of attribute name to value (e.g. {"Speed": "100", "Mode": null}); null clears an override

instance alarm-override set

Set (upsert) an alarm override on an instance.

scadabridge --url <url> instance alarm-override set --instance-id <int> --alarm <string> [--trigger-config <json>] [--priority <int>]
Option Required Description
--instance-id yes Instance ID
--alarm yes Alarm canonical name (e.g. TempLevels or Pump.TempSensor.Heat)
--trigger-config no JSON override for TriggerConfiguration (HiLo: partial merge; others: whole-replace)
--priority no Priority override (01000)

instance alarm-override delete

Remove an alarm override on an instance.

scadabridge --url <url> instance alarm-override delete --instance-id <int> --alarm <string>
Option Required Description
--instance-id yes Instance ID
--alarm yes Alarm canonical name

instance alarm-override list

List all alarm overrides for an instance.

scadabridge --url <url> instance alarm-override list --instance-id <int>
Option Required Description
--instance-id yes Instance ID

instance set-area

Reassign an instance to a different area (or clear its area assignment).

scadabridge --url <url> instance set-area --id <int> [--area-id <int>]
Option Required Description
--id yes Instance ID
--area-id no Area ID; omit to clear area assignment

instance diff

Show the deployment diff between the currently deployed configuration and the current template state.

scadabridge --url <url> instance diff --id <int>
Option Required Description
--id yes Instance ID

site — Manage sites

site get

Get a single site by ID.

scadabridge --url <url> site get --id <int>
Option Required Description
--id yes Site ID

site list

List all registered sites.

scadabridge --url <url> site list

site create

Register a new site.

scadabridge --url <url> site create --name <string> --identifier <string> [--description <string>] [--node-a-address <string>] [--node-b-address <string>] [--grpc-node-a-address <string>] [--grpc-node-b-address <string>]
Option Required Description
--name yes Human-readable site name
--identifier yes Unique machine identifier used for cluster routing (e.g. site-a)
--description no Site description
--node-a-address no Akka.NET cluster address for Node A
--node-b-address no Akka.NET cluster address for Node B
--grpc-node-a-address no gRPC streaming address for Node A
--grpc-node-b-address no gRPC streaming address for Node B

site update

Update an existing site. An update replaces the whole entity — every required field below must be supplied with its post-update value, even if unchanged.

scadabridge --url <url> site update --id <int> --name <string> [--description <string>] [--node-a-address <string>] [--node-b-address <string>] [--grpc-node-a-address <string>] [--grpc-node-b-address <string>]
Option Required Description
--id yes Site ID
--name yes Human-readable site name
--description no Site description
--node-a-address no Akka.NET cluster address for Node A
--node-b-address no Akka.NET cluster address for Node B
--grpc-node-a-address no gRPC streaming address for Node A
--grpc-node-b-address no gRPC streaming address for Node B

site delete

Delete a site. Fails if any instances are assigned to it.

scadabridge --url <url> site delete --id <int>
Option Required Description
--id yes Site ID

site deploy-artifacts

Push compiled artifacts to one or all sites.

scadabridge --url <url> site deploy-artifacts [--site-id <int>]
Option Required Description
--site-id no Target site ID; omit to deploy to all sites

site area list

List all areas for a site.

scadabridge --url <url> site area list --site-id <int>
Option Required Description
--site-id yes Site ID

site area create

Create an area within a site.

scadabridge --url <url> site area create --site-id <int> --name <string> [--parent-id <int>]
Option Required Description
--site-id yes Site ID
--name yes Area name
--parent-id no Parent area ID for nested areas

site area update

Update an area's name. An update replaces the whole entity — the required field below must be supplied, even if unchanged.

scadabridge --url <url> site area update --id <int> --name <string>
Option Required Description
--id yes Area ID
--name yes Area name

site area delete

Delete an area. Fails if any instances are assigned to it.

scadabridge --url <url> site area delete --id <int>
Option Required Description
--id yes Area ID

deploy — Deployment operations

deploy instance

Deploy a single instance (same as instance deploy).

scadabridge --url <url> deploy instance --id <int>
Option Required Description
--id yes Instance ID

deploy artifacts

Deploy compiled artifacts to one or all sites (same as site deploy-artifacts).

scadabridge --url <url> deploy artifacts [--site-id <int>]
Option Required Description
--site-id no Target site ID; omit for all sites

deploy status

Query deployment records, with optional filters and pagination.

scadabridge --url <url> deploy status [--instance-id <int>] [--status <string>] [--page <int>] [--page-size <int>]
Option Required Default Description
--instance-id no Filter by instance ID
--status no Filter by deployment status string
--page no 1 Page number
--page-size no 50 Results per page

data-connection — Manage data connections

data-connection get

Get a single data connection by ID.

scadabridge --url <url> data-connection get --id <int>
Option Required Description
--id yes Data connection ID

data-connection list

List data connections, optionally filtered by site.

scadabridge --url <url> data-connection list [--site-id <int>]
Option Required Description
--site-id no Filter by site ID

data-connection create

Create a new data connection belonging to a specific site.

scadabridge --url <url> data-connection create --site-id <int> --name <string> --protocol <string> [--primary-config <json>] [--backup-config <json>] [--failover-retry-count <int>]
Option Required Description
--site-id yes Site ID the connection belongs to
--name yes Connection name
--protocol yes Protocol identifier (e.g. OpcUa)
--primary-config no Primary protocol-specific configuration as a JSON string (alias --configuration)
--backup-config no Backup protocol-specific configuration as a JSON string
--failover-retry-count no Retries before failover to the backup configuration (default: 3)

data-connection update

Update a data connection definition. An update replaces the whole entity — every required field below must be supplied, even if unchanged.

scadabridge --url <url> data-connection update --id <int> --name <string> --protocol <string> [--primary-config <json>] [--backup-config <json>] [--failover-retry-count <int>]
Option Required Description
--id yes Data connection ID
--name yes Connection name
--protocol yes Protocol identifier
--primary-config no Primary protocol-specific configuration as a JSON string (alias --configuration)
--backup-config no Backup protocol-specific configuration as a JSON string
--failover-retry-count no Retries before failover to the backup configuration (default: 3)

data-connection delete

Delete a data connection.

scadabridge --url <url> data-connection delete --id <int>
Option Required Description
--id yes Data connection ID

external-system — Manage external HTTP systems

external-system get

Get a single external system definition by ID.

scadabridge --url <url> external-system get --id <int>
Option Required Description
--id yes External system ID

external-system list

List all external system definitions.

scadabridge --url <url> external-system list

external-system create

Register an external HTTP system that scripts can call.

scadabridge --url <url> external-system create --name <string> --endpoint-url <url> --auth-type <string> [--auth-config <json>]
Option Required Description
--name yes Display name
--endpoint-url yes Base URL of the external system
--auth-type yes Authentication type: ApiKey or BasicAuth
--auth-config no Auth credentials as a JSON string

external-system update

Update an external system definition. An update replaces the whole entity — every required field below must be supplied, even if unchanged.

scadabridge --url <url> external-system update --id <int> --name <string> --endpoint-url <url> --auth-type <string> [--auth-config <json>]
Option Required Description
--id yes External system ID
--name yes Display name
--endpoint-url yes Base URL
--auth-type yes Authentication type
--auth-config no Updated auth credentials as a JSON string

external-system delete

Delete an external system definition.

scadabridge --url <url> external-system delete --id <int>
Option Required Description
--id yes External system ID

notification — Manage notification lists

notification get

Get a single notification list by ID.

scadabridge --url <url> notification get --id <int>
Option Required Description
--id yes Notification list ID

notification list

List all notification lists.

scadabridge --url <url> notification list

notification create

Create a notification list with one or more recipients.

scadabridge --url <url> notification create --name <string> --emails <email1,email2,...>
Option Required Description
--name yes Notification list name
--emails yes Comma-separated list of recipient email addresses

notification update

Update a notification list. An update replaces the whole entity — every required field below must be supplied, even if unchanged.

scadabridge --url <url> notification update --id <int> --name <string> --emails <email1,email2,...>
Option Required Description
--id yes Notification list ID
--name yes List name
--emails yes Comma-separated list of recipient email addresses

notification delete

Delete a notification list.

scadabridge --url <url> notification delete --id <int>
Option Required Description
--id yes Notification list ID

notification smtp list

Show the current SMTP configuration.

scadabridge --url <url> notification smtp list

notification smtp update

Update the SMTP configuration.

scadabridge --url <url> notification smtp update --id <int> --server <string> --port <int> --auth-mode <string> --from-address <string> [--tls-mode <string>] [--credentials <string>]
Option Required Description
--id yes SMTP config ID
--server yes SMTP server hostname
--port yes SMTP server port
--auth-mode yes Authentication mode (e.g. OAuth2ClientCredentials, Basic)
--from-address yes Sender email address
--tls-mode no TLS mode: None, StartTLS, or SSL (preserves existing if omitted)
--credentials no SMTP credentials — username:password for Basic, or client secret for OAuth2 (preserves existing if omitted)

security — Security settings

security api-key list

List all inbound API keys.

scadabridge --url <url> security api-key list

security api-key create

Create a new inbound API key. The generated key value is returned in the response and not stored in plaintext — save it immediately.

scadabridge --url <url> security api-key create --name <string> --methods <string>
Option Required Description
--name yes Descriptive label for the key
--methods yes Comma-separated API method names this key may call (e.g. "MethodA,MethodB")

security api-key update

Enable or disable an API key.

scadabridge --url <url> security api-key update --key-id <string> --enabled <bool>
Option Required Description
--key-id yes API key ID
--enabled yes Enable or disable the key (true or false)

security api-key set-methods

Replace the method scopes on an existing API key.

scadabridge --url <url> security api-key set-methods --key-id <string> --methods <string>
Option Required Description
--key-id yes API key ID
--methods yes Comma-separated API method names (replaces the existing set)

security api-key delete

Revoke and delete an API key.

scadabridge --url <url> security api-key delete --key-id <string>
Option Required Description
--key-id yes API key ID

security role-mapping list

List all LDAP group → role mappings.

scadabridge --url <url> security role-mapping list

security role-mapping create

Map an LDAP group to a ScadaBridge role.

scadabridge --url <url> security role-mapping create --ldap-group <string> --role <string>
Option Required Description
--ldap-group yes LDAP group distinguished name or CN
--role yes ScadaBridge role: Admin, Design, or Deployment

security role-mapping update

Update an LDAP role mapping. An update replaces the whole entity — every required field below must be supplied, even if unchanged.

scadabridge --url <url> security role-mapping update --id <int> --ldap-group <string> --role <string>
Option Required Description
--id yes Mapping ID
--ldap-group yes LDAP group distinguished name or CN
--role yes ScadaBridge role

security role-mapping delete

Remove an LDAP role mapping.

scadabridge --url <url> security role-mapping delete --id <int>
Option Required Description
--id yes Mapping ID

security scope-rule list

List all site scope rules for a role mapping.

scadabridge --url <url> security scope-rule list --mapping-id <int>
Option Required Description
--mapping-id yes Role mapping ID

security scope-rule add

Add a site scope rule to a role mapping, restricting it to a specific site.

scadabridge --url <url> security scope-rule add --mapping-id <int> --site-id <int>
Option Required Description
--mapping-id yes Role mapping ID
--site-id yes Site ID to scope the mapping to

security scope-rule delete

Remove a site scope rule from a role mapping.

scadabridge --url <url> security scope-rule delete --id <int>
Option Required Description
--id yes Scope rule ID

health — Health monitoring

health summary

Return the current health state for all known sites as a JSON object keyed by site identifier.

scadabridge --url <url> health summary

health site

Return the health state for a single site.

scadabridge --url <url> health site --identifier <string>
Option Required Description
--identifier yes Site identifier (e.g. site-a)

health event-log

Query the site event log for a specific site. Events are fetched remotely from the site's local SQLite store.

scadabridge --url <url> health event-log --site <string> [--event-type <string>] [--severity <string>] [--keyword <string>] [--from <datetime>] [--to <datetime>] [--page <int>] [--page-size <int>] [--instance-name <string>]
Option Required Default Description
--site yes Site identifier
--event-type no Filter by event type
--severity no Filter by severity
--keyword no Keyword search term
--from no Start timestamp in ISO 8601 format
--to no End timestamp in ISO 8601 format
--page no 1 Page number
--page-size no 50 Results per page
--instance-name no Filter by instance name

health parked-messages

Query parked (dead-letter) messages at a specific site.

scadabridge --url <url> health parked-messages --site <string> [--page <int>] [--page-size <int>]
Option Required Default Description
--site yes Site identifier
--page no 1 Page number
--page-size no 50 Results per page

debug — Runtime debugging

debug snapshot

Request a point-in-time snapshot of a running instance's current attribute values and alarm states from the site. The instance must be deployed and enabled.

scadabridge --url <url> debug snapshot --id <int>
Option Required Description
--id yes Instance ID

The command resolves the instance's site internally and routes the request to the correct site cluster. Returns all attribute values (name, value, quality, timestamp) and alarm states (name, state, priority, timestamp) at the moment the request reaches the site.

debug stream

Stream live attribute values and alarm state changes in real-time using a SignalR WebSocket connection to the central server's /hubs/debug-stream hub. Events are printed as they arrive. Press Ctrl+C to disconnect.

scadabridge --url <url> debug stream --id <int>
Option Required Description
--id yes Instance ID

The default JSON format outputs one NDJSON object per event line with a type field (snapshot, attributeChanged, or alarmChanged). Table format (--format table) shows a formatted initial snapshot followed by streaming rows prefixed with ATTR or ALARM.

Features:

  • Automatic reconnection on connection loss with re-subscribe.
  • Works through the Traefik load balancer (WebSocket upgrade proxied natively).
  • Requires the Deployment role.

audit — Centralized Audit Log

Read access to the central append-only Audit Log (#23) — the record of every script-trust-boundary action: outbound API calls (sync + cached), outbound DB operations (sync + cached), notifications, and inbound API calls. This is distinct from the configuration-change audit trail exposed by audit-config.

The subcommands map directly onto the GET /api/audit/query, GET /api/audit/export, GET /api/audit/tree, and POST /api/audit/backfill-source-node management endpoints. Filters and the result columns mirror the Central UI Audit page, so a CLI query and a UI query with the same filters return the same rows — CLI ↔ UI filter parity is intentional.

Permissions. Querying and tree traversal require the OperationalAudit permission (roles Admin, Audit, or AuditReadOnly). Exporting requires the stricter AuditExport permission (roles Admin or Audit) — read access does not imply export access. The backfill-source-node maintenance command requires the Admin role. A request without the required role returns exit code 2.

audit query

Query audit log events with optional filters and keyset pagination.

scadabridge --url <url> audit query [options]
Option Required Default Description
--since no Start time: relative (1h, 24h, 7d) or ISO-8601
--until no End time: relative (1h, 24h, 7d) or ISO-8601
--channel no Filter by channel (ApiOutbound, DbOutbound, Notification, ApiInbound); repeatable — multiple values are OR-combined
--kind no Filter by event kind (ApiCall, ApiCallCached, DbWrite, DbWriteCached, NotifySend, NotifyDeliver, InboundRequest, InboundAuthFailure, CachedSubmit, CachedResolve); repeatable — multiple values are OR-combined
--status no Filter by status (Submitted, Forwarded, Attempted, Delivered, Failed, Parked, Discarded, Skipped); repeatable — multiple values are OR-combined
--site no Filter by source site ID; repeatable — multiple values are OR-combined
--target no Filter by target (external system, DB connection, notification list)
--actor no Filter by actor
--correlation-id no Filter by correlation ID
--execution-id no Filter by execution ID
--parent-execution-id no Filter by parent execution ID
--errors-only no false Show only failed events (status=Failed; overrides --status)
--page-size no 100 Events per page (11000)
--all no false Fetch every page, following the keyset cursor
--format no json Output format: json (JSONL, one event per line) or table

The --channel/--kind/--status/--site filters accept multiple values — either as repeated flags (--channel ApiOutbound --channel DbOutbound) or space-separated after one flag (--channel ApiOutbound DbOutbound). Values within one filter are OR-combined; the different filters are AND-combined.

With --format table, events render as an aligned text table with columns OccurredAtUtc, Channel, Kind, Status, Target, Actor, DurationMs, HttpStatus; long Target/Actor values are truncated with an ellipsis. With --format json (the default), each page is emitted as JSONL — one JSON object per line — which streams cleanly under --all across many pages.

audit export

Export audit log events to a file. The export streams from the server, so it is not bounded by the query page size.

scadabridge --url <url> audit export --since <time> --until <time> --format <fmt> --output <path> [filters]
Option Required Default Description
--since yes Start time: relative (1h, 24h, 7d) or ISO-8601
--until yes End time: relative (1h, 24h, 7d) or ISO-8601
--format yes Export format: csv, jsonl, or parquet
--output yes Destination file path
--channel no Filter by channel
--kind no Filter by event kind
--status no Filter by status
--site no Filter by source site ID
--target no Filter by target
--actor no Filter by actor

--format parquet is accepted by the CLI but the server returns 501 Not Implemented — Parquet archival is deferred to v1.x (see Component-AuditLog.md). Use csv or jsonl.

audit tree (M5.3 T8)

Display the full execution-chain tree for a given execution ID. The server walks ParentExecutionId to find the root, then traverses downward to collect all reachable executions in the chain.

scadabridge --url <url> audit tree --execution-id <guid> [--format table|json]
Option Required Default Description
--execution-id yes Any ExecutionId in the chain (root or child)
--format no json Output format: json (structured tree) or table (indented tree)

The --execution-id can be any node in the chain — the server resolves the root automatically. With --format table the tree is printed as an indented text representation. With --format json (the default) a structured JSON tree is returned, suitable for scripting. Backed by GET /api/audit/tree?executionId=<guid>. Requires OperationalAudit permission.

audit backfill-source-node (M5.6 T5)

Set SourceNode to a sentinel value on pre-feature rows where SourceNode IS NULL and OccurredAtUtc is older than --before. Admin-only maintenance command.

scadabridge --url <url> audit backfill-source-node --before <ISO-8601-UTC> [--sentinel <value>] [--batch <n>]
Option Required Default Description
--before yes ISO-8601 UTC datetime; only rows older than this date are eligible
--sentinel no unknown Value to write (must be non-empty)
--batch no 5000 Max rows updated per batch; controls transaction size

The command is idempotent — running it multiple times converges (only rows where SourceNode IS NULL are eligible; already-set rows are untouched). Backed by POST /api/audit/backfill-source-node. Requires Admin role.

audit verify-chain

Verify the audit log hash chain for a given month.

scadabridge --url <url> audit verify-chain --month <YYYY-MM>
Option Required Default Description
--month yes Month to verify, YYYY-MM (e.g. 2026-05)

v1 no-op. Hash-chain tamper-evidence is not enabled in this release (T1 deferred to v1.x). The subcommand validates the --month argument and prints a notice pointing at the v1.x roadmap in Component-AuditLog.md; it exits 0 without contacting the server. The command exists now so scripts and operator habits do not need to change when tamper-evidence ships.


audit-config — Configuration-change audit log

Query the configuration-change audit trail (the IAuditService record of admin edits to templates, instances, sites, etc.). This is separate from the centralized audit group above.

Renamed. This group was named audit-log before #23 M8. The old name still works as a deprecated alias — scadabridge audit-log query ... resolves the full subcommand tree unchanged — but prints a deprecation warning to stderr: Warning: 'audit-log' is deprecated and will be removed in a future release. Use 'audit-config' instead. Migrate scripts to audit-config; the audit-log alias will be removed in a future release.

audit-config query

Query the configuration-change audit log with optional filters and pagination.

scadabridge --url <url> audit-config query [options]
Option Required Default Description
--user no Filter by username
--entity-type no Filter by entity type (e.g. Template, Instance)
--action no Filter by action (e.g. Create, Delete)
--from no Start timestamp in ISO 8601 format
--to no End timestamp in ISO 8601 format
--page no 1 Page number
--page-size no 50 Results per page

shared-script — Manage shared scripts

shared-script list

List all shared script definitions.

scadabridge --url <url> shared-script list

shared-script get

Get a single shared script by ID.

scadabridge --url <url> shared-script get --id <int>
Option Required Description
--id yes Shared script ID

shared-script create

Create a new shared script.

scadabridge --url <url> shared-script create --name <string> --code <string>
Option Required Description
--name yes Shared script name
--code yes Script source code (or @filepath to read from file)

shared-script update

Update a shared script. An update replaces the whole entity — every required field below must be supplied, even if unchanged.

scadabridge --url <url> shared-script update --id <int> --name <string> --code <string> [--parameters <json>] [--return-def <json>]
Option Required Description
--id yes Shared script ID
--name yes Shared script name
--code yes Script source code
--parameters no Parameter definitions JSON
--return-def no Return type definition JSON

shared-script delete

Delete a shared script.

scadabridge --url <url> shared-script delete --id <int>
Option Required Description
--id yes Shared script ID

db-connection — Manage database connections

db-connection list

List all database connection definitions.

scadabridge --url <url> db-connection list

db-connection get

Get a single database connection by ID.

scadabridge --url <url> db-connection get --id <int>
Option Required Description
--id yes Database connection ID

db-connection create

Create a new database connection definition.

scadabridge --url <url> db-connection create --name <string> --connection-string <string>
Option Required Description
--name yes Connection name
--connection-string yes Database connection string

db-connection update

Update a database connection definition. An update replaces the whole entity — every required field below must be supplied, even if unchanged.

scadabridge --url <url> db-connection update --id <int> --name <string> --connection-string <string>
Option Required Description
--id yes Database connection ID
--name yes Connection name
--connection-string yes Database connection string

db-connection delete

Delete a database connection definition.

scadabridge --url <url> db-connection delete --id <int>
Option Required Description
--id yes Database connection ID

api-method — Manage inbound API methods

api-method list

List all inbound API method definitions.

scadabridge --url <url> api-method list

api-method get

Get a single inbound API method by ID.

scadabridge --url <url> api-method get --id <int>
Option Required Description
--id yes API method ID

api-method create

Create a new inbound API method.

scadabridge --url <url> api-method create --name <string> --script <string> [--timeout <int>] [--parameters <json>] [--return-def <json>]
Option Required Default Description
--name yes Method name (used as the URL path segment in POST /api/{methodName})
--script yes Script source code implementing the method
--timeout no 30 Timeout in seconds
--parameters no Parameter definitions JSON
--return-def no Return type definition JSON

api-method update

Update an inbound API method. An update replaces the whole entity — every required field below must be supplied, even if unchanged.

scadabridge --url <url> api-method update --id <int> --script <string> [--timeout <int>] [--parameters <json>] [--return-def <json>]
Option Required Default Description
--id yes API method ID
--script yes Script source code implementing the method
--timeout no 30 Timeout in seconds
--parameters no Parameter definitions JSON
--return-def no Return type definition JSON

Script changes take effect immediately — the updated code is recompiled in-memory on the active central node. No restart is required.

api-method delete

Delete an inbound API method.

scadabridge --url <url> api-method delete --id <int>
Option Required Description
--id yes API method ID

bundle — Transport bundle export / preview / import

Export, preview, and import Transport (#24) bundles. Bundles carry templates, shared scripts, external systems, database connections, notification lists, SMTP configurations, and API methods between environments. Inbound API keys are not transported — recreate them on the destination via the CLI or UI.

Bundle commands use a 5-minute timeout (larger payloads may be slow over WAN).

bundle export

Export selected entities to a .scadabundle file.

scadabridge --url <url> bundle export --output <path> [--passphrase <string>] [--all] [--include-dependencies] [entity-selectors]
Option Required Description
--output yes Output file path (e.g. env-baseline.scadabundle)
--passphrase no Encryption passphrase; omit to produce an unencrypted bundle
--all no Export every entity of every supported type (ignores per-type name flags)
--include-dependencies no Pull transitive dependencies (referenced shared scripts, parents, composed members) into the bundle
--templates no Comma-separated template names to include
--shared-scripts no Comma-separated shared-script names to include
--external-systems no Comma-separated external-system names to include
--db-connections no Comma-separated database-connection names to include
--notification-lists no Comma-separated notification-list names to include
--smtp-configs no Comma-separated SMTP host names to include
--api-methods no Comma-separated API-method names to include
--source-environment no SourceEnvironment value stamped into the bundle manifest (default: cli)

Example — export two templates and all their dependencies:

scadabridge --url <url> bundle export --output baseline.scadabundle \
  --templates "PumpTemplate,TankTemplate" --include-dependencies

bundle preview

Load a bundle and print the diff preview (Added / Modified / Unchanged per entity) without applying any changes.

scadabridge --url <url> bundle preview --input <path> [--passphrase <string>]
Option Required Description
--input yes Bundle file path (.scadabundle)
--passphrase no Passphrase for encrypted bundles

bundle import

Load and apply a bundle with a single global conflict policy. Preview first with bundle preview to review the diff.

scadabridge --url <url> bundle import --input <path> [--passphrase <string>] [--on-conflict <policy>]
Option Required Default Description
--input yes Bundle file path (.scadabundle)
--passphrase no Passphrase for encrypted bundles
--on-conflict no overwrite Resolution policy for Modified rows: skip, overwrite, or rename

Architecture Notes

The CLI connects to the Central cluster using Akka.NET's ClusterClient. It does not join the cluster — it contacts the ClusterClientReceptionist on one of the configured Central nodes and sends commands to the ManagementActor at path /user/management.

The connection is established per-command invocation and torn down cleanly via CoordinatedShutdown when the command completes.

Role enforcement is applied by the ManagementActor on the server side. The CLI authenticates against LDAP using --username / --password, resolves LDAP group memberships, then maps groups to ScadaBridge roles (Admin, Design, Deployment) via role mappings configured in the security settings. Operations require the appropriate role — for example, creating templates requires Design, deploying requires Deployment. In the test environment, use the multi-role user (password: password) which has all three roles.

Issues & Missing Features

If you encounter bugs, unexpected behavior, or missing features in the CLI, log them in cli_issues.md in the project root. Include a brief description, the command involved, and any relevant error output.