refactor: scrub residual ScadaLink refs → ScadaBridge (env vars, config keys, assembly name, SQL login)
Renames the 13 SCADALINK_* runtime env vars → SCADABRIDGE_*, the ScadaLink__ .NET config keys → ScadaBridge__, the stale ScadaLink.Host.exe assembly name → ZB.MOM.WW.ScadaBridge.Host.exe, the scadalink_app SQL login → scadabridge_app, and residual identifiers/comments/docs. Migration records (prior rename tooling/design, DB-rename helper, this scrub script) carved out. Adds tools/scrub-scadalink-refs.sh.
This commit is contained in:
@@ -22,7 +22,7 @@ The dominant theme is **graceful-degradation gaps**: several user-supplied input
|
||||
URLs, malformed `--bindings`/`--overrides` JSON, non-JSON success bodies) are deserialized
|
||||
or constructed without `try/catch`, so a normal user mistake surfaces as an unhandled
|
||||
exception with a stack trace instead of a clean error message and exit code 1. A second
|
||||
theme is **dead configuration**: the `SCADALINK_FORMAT` environment variable and the
|
||||
theme is **dead configuration**: the `SCADABRIDGE_FORMAT` environment variable and the
|
||||
`defaultFormat` config-file field are loaded by `CliConfig` but never consulted by any
|
||||
command, so the documented format-precedence chain does not work. The third theme is
|
||||
**substantial design-document drift**: `Component-CLI.md` describes a name-keyed,
|
||||
@@ -126,7 +126,7 @@ _Re-review (2026-05-28, `1eb6e97`):_
|
||||
|
||||
## Findings
|
||||
|
||||
### CLI-001 — `SCADALINK_FORMAT` env var and config-file format are dead; format precedence broken
|
||||
### CLI-001 — `SCADABRIDGE_FORMAT` env var and config-file format are dead; format precedence broken
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
@@ -137,7 +137,7 @@ _Re-review (2026-05-28, `1eb6e97`):_
|
||||
|
||||
**Description**
|
||||
|
||||
`CliConfig.Load()` reads `SCADALINK_FORMAT` and the `defaultFormat` config-file field into
|
||||
`CliConfig.Load()` reads `SCADABRIDGE_FORMAT` and the `defaultFormat` config-file field into
|
||||
`CliConfig.DefaultFormat`, and `Component-CLI.md` documents a format-precedence chain
|
||||
(command-line option → env var → config file). However, every command resolves the format
|
||||
with `var format = result.GetValue(formatOption) ?? "json";` and `formatOption` is created
|
||||
@@ -145,7 +145,7 @@ in `Program.cs:11` with `DefaultValueFactory = _ => "json"`. `GetValue` therefor
|
||||
returns a non-null value ("json" when the flag is absent), so the `?? "json"` fallback never
|
||||
fires and `config.DefaultFormat` is never consulted. The env var and config-file format
|
||||
settings are dead code: `scadabridge site list` always outputs JSON regardless of
|
||||
`SCADALINK_FORMAT=table` or a `defaultFormat` entry in `~/.scadabridge/config.json`. The
|
||||
`SCADABRIDGE_FORMAT=table` or a `defaultFormat` entry in `~/.scadabridge/config.json`. The
|
||||
documented behaviour silently does not work.
|
||||
|
||||
**Recommendation**
|
||||
@@ -312,14 +312,14 @@ wrong element types, and JSON null).
|
||||
Credentials are supplied only via `--username` / `--password`. A password on the command
|
||||
line is visible to any local user via the process list (`ps`, `/proc/<pid>/cmdline`) and is
|
||||
typically persisted into shell history. Unlike the management URL — which can also come
|
||||
from `SCADALINK_MANAGEMENT_URL` or the config file — there is no environment-variable
|
||||
from `SCADABRIDGE_MANAGEMENT_URL` or the config file — there is no environment-variable
|
||||
fallback, no `--password-stdin`, and no interactive prompt for the password. For a tool
|
||||
explicitly intended for CI/CD automation this materially increases the chance of credential
|
||||
leakage.
|
||||
|
||||
**Recommendation**
|
||||
|
||||
Add a `SCADALINK_PASSWORD` environment variable fallback and/or a `--password-stdin`
|
||||
Add a `SCADABRIDGE_PASSWORD` environment variable fallback and/or a `--password-stdin`
|
||||
option (read the password from stdin), and document that `--password` on the command line
|
||||
is discouraged. Optionally prompt interactively when stdin is a TTY and no password was
|
||||
supplied.
|
||||
@@ -327,7 +327,7 @@ supplied.
|
||||
**Resolution**
|
||||
|
||||
Resolved 2026-05-16 (commit pending). Root cause confirmed — credentials had no
|
||||
non-command-line source. Added `SCADALINK_USERNAME` / `SCADALINK_PASSWORD` environment
|
||||
non-command-line source. Added `SCADABRIDGE_USERNAME` / `SCADABRIDGE_PASSWORD` environment
|
||||
fallbacks: `CliConfig.Load` now reads them into new `CliConfig.Username` / `Password`
|
||||
properties (credentials are sourced from environment variables only, never the config
|
||||
file, so they are not persisted). `CommandHelpers.ResolveCredential` resolves precedence
|
||||
@@ -387,7 +387,7 @@ bind-connections`/`assign-area`, `data-connection assign/unassign`, `security ap
|
||||
enable/disable`) are removed; previously-omitted commands (`instance alarm-override
|
||||
set/delete/list`, `external-system method` subgroup, `site deploy-artifacts`) are added.
|
||||
A note now points to `src/ZB.MOM.WW.ScadaBridge.CLI/README.md` as the authoritative reference. The
|
||||
Configuration section also documents the new `SCADALINK_USERNAME`/`SCADALINK_PASSWORD`
|
||||
Configuration section also documents the new `SCADABRIDGE_USERNAME`/`SCADABRIDGE_PASSWORD`
|
||||
env vars (see CLI-006).
|
||||
|
||||
### CLI-008 — `--format` value is not validated
|
||||
@@ -817,7 +817,7 @@ and a caller-supplied success handler. In duplicating it, two contracts that
|
||||
`2` = authorization failure," so this is a contract regression.
|
||||
2. **Error-message phrasing drift.** The two duplicated error paths
|
||||
(`bundle:258-260`, `:264-266`) emit shorter messages that omit the
|
||||
`SCADALINK_MANAGEMENT_URL` / `SCADALINK_USERNAME` env-var hints the canonical paths
|
||||
`SCADABRIDGE_MANAGEMENT_URL` / `SCADABRIDGE_USERNAME` env-var hints the canonical paths
|
||||
give — confusing if the user is trying to debug what's missing.
|
||||
|
||||
**Recommendation**
|
||||
|
||||
@@ -230,7 +230,7 @@ Resolved 2026-05-16 (commit pending). Root cause confirmed against source: the f
|
||||
fell back to a literal `User Id=sa;Password=YourPassword;...` connection string when no
|
||||
configured value was found. Removed the hardcoded fallback entirely. The factory now
|
||||
resolves the connection string from the Host's appsettings files or, when those are not
|
||||
present, from the `SCADALINK_DESIGNTIME_CONNECTIONSTRING` environment variable, and
|
||||
present, from the `SCADABRIDGE_DESIGNTIME_CONNECTIONSTRING` environment variable, and
|
||||
throws a clear `InvalidOperationException` (naming both the config key and the env var)
|
||||
when neither yields a value. Also hardened `SetBasePath` to be applied only when the
|
||||
`ZB.MOM.WW.ScadaBridge.Host` directory exists, so the factory degrades cleanly instead of throwing
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-env2-central-a
|
||||
environment:
|
||||
SCADALINK_CONFIG: Central
|
||||
SCADABRIDGE_CONFIG: Central
|
||||
ASPNETCORE_ENVIRONMENT: Development
|
||||
ASPNETCORE_URLS: "http://+:5000"
|
||||
ports:
|
||||
@@ -20,7 +20,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-env2-central-b
|
||||
environment:
|
||||
SCADALINK_CONFIG: Central
|
||||
SCADABRIDGE_CONFIG: Central
|
||||
ASPNETCORE_ENVIRONMENT: Development
|
||||
ASPNETCORE_URLS: "http://+:5000"
|
||||
ports:
|
||||
@@ -37,7 +37,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-env2-site-x-a
|
||||
environment:
|
||||
SCADALINK_CONFIG: Site
|
||||
SCADABRIDGE_CONFIG: Site
|
||||
ports:
|
||||
- "9121:8082" # Akka remoting
|
||||
- "9123:8083" # gRPC streaming
|
||||
@@ -53,7 +53,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-env2-site-x-b
|
||||
environment:
|
||||
SCADALINK_CONFIG: Site
|
||||
SCADABRIDGE_CONFIG: Site
|
||||
ports:
|
||||
- "9122:8082" # Akka remoting
|
||||
- "9124:8083" # gRPC streaming
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-central-a
|
||||
environment:
|
||||
SCADALINK_CONFIG: Central
|
||||
SCADABRIDGE_CONFIG: Central
|
||||
ASPNETCORE_ENVIRONMENT: Development
|
||||
ASPNETCORE_URLS: "http://+:5000"
|
||||
ports:
|
||||
@@ -20,7 +20,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-central-b
|
||||
environment:
|
||||
SCADALINK_CONFIG: Central
|
||||
SCADABRIDGE_CONFIG: Central
|
||||
ASPNETCORE_ENVIRONMENT: Development
|
||||
ASPNETCORE_URLS: "http://+:5000"
|
||||
ports:
|
||||
@@ -37,7 +37,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-site-a-a
|
||||
environment:
|
||||
SCADALINK_CONFIG: Site
|
||||
SCADABRIDGE_CONFIG: Site
|
||||
ports:
|
||||
- "9021:8082" # Akka remoting (host access for debugging)
|
||||
- "9023:8083" # gRPC streaming
|
||||
@@ -53,7 +53,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-site-a-b
|
||||
environment:
|
||||
SCADALINK_CONFIG: Site
|
||||
SCADABRIDGE_CONFIG: Site
|
||||
ports:
|
||||
- "9022:8082" # Akka remoting
|
||||
- "9024:8083" # gRPC streaming
|
||||
@@ -69,7 +69,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-site-b-a
|
||||
environment:
|
||||
SCADALINK_CONFIG: Site
|
||||
SCADABRIDGE_CONFIG: Site
|
||||
ports:
|
||||
- "9031:8082" # Akka remoting
|
||||
- "9033:8083" # gRPC streaming
|
||||
@@ -85,7 +85,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-site-b-b
|
||||
environment:
|
||||
SCADALINK_CONFIG: Site
|
||||
SCADABRIDGE_CONFIG: Site
|
||||
ports:
|
||||
- "9032:8082" # Akka remoting
|
||||
- "9034:8083" # gRPC streaming
|
||||
@@ -101,7 +101,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-site-c-a
|
||||
environment:
|
||||
SCADALINK_CONFIG: Site
|
||||
SCADABRIDGE_CONFIG: Site
|
||||
ports:
|
||||
- "9041:8082" # Akka remoting
|
||||
- "9043:8083" # gRPC streaming
|
||||
@@ -117,7 +117,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-site-c-b
|
||||
environment:
|
||||
SCADALINK_CONFIG: Site
|
||||
SCADABRIDGE_CONFIG: Site
|
||||
ports:
|
||||
- "9042:8082" # Akka remoting
|
||||
- "9044:8083" # gRPC streaming
|
||||
|
||||
@@ -165,7 +165,7 @@ Five indexes with explicit names:
|
||||
- `scadabridge_audit_writer`: GRANT INSERT ON AuditLog; GRANT SELECT ON AuditLog. (No UPDATE, no DELETE.)
|
||||
- `scadabridge_audit_purger`: GRANT ALTER ON SCHEMA::dbo; GRANT SELECT ON AuditLog. (Enables ALTER PARTITION FUNCTION SWITCH and SWITCH PARTITION.)
|
||||
- `Down()` drops indexes, table, scheme, function, then both roles.
|
||||
- Create: `tests/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests/Migrations/AddAuditLogTableMigrationTests.cs` — uses a fixture connecting to the running `infra/mssql` container via the connection string in `infra/mssql/.env` (or skips with `Skip.If` when the env var `SCADALINK_MSSQL_TEST_CONN` is unset, so CI without the container still passes).
|
||||
- Create: `tests/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests/Migrations/AddAuditLogTableMigrationTests.cs` — uses a fixture connecting to the running `infra/mssql` container via the connection string in `infra/mssql/.env` (or skips with `Skip.If` when the env var `SCADABRIDGE_MSSQL_TEST_CONN` is unset, so CI without the container still passes).
|
||||
|
||||
Integration test assertions:
|
||||
- `sys.partition_functions` contains `pf_AuditLog_Month`.
|
||||
@@ -191,10 +191,10 @@ Integration test assertions:
|
||||
|
||||
**Notes for the implementer:**
|
||||
- Use `Microsoft.Data.SqlClient` directly in the test fixture (not EF) to issue raw SQL for grant assertions.
|
||||
- `Skip.If(string.IsNullOrEmpty(Environment.GetEnvironmentVariable("SCADALINK_MSSQL_TEST_CONN")), "MSSQL not available")` — keeps tests CI-safe.
|
||||
- `Skip.If(string.IsNullOrEmpty(Environment.GetEnvironmentVariable("SCADABRIDGE_MSSQL_TEST_CONN")), "MSSQL not available")` — keeps tests CI-safe.
|
||||
- Test database name: `ScadaBridgeAuditMigrationTest_<guid>` (created per fixture, dropped on dispose).
|
||||
|
||||
**Bundle C acceptance:** Migration applied to a fresh test DB on the `infra/mssql` container creates the partition function/scheme/table/indexes/roles. Smoke test confirms UPDATE is denied for the writer role. All migration tests pass when `SCADALINK_MSSQL_TEST_CONN` is set; skip cleanly when unset.
|
||||
**Bundle C acceptance:** Migration applied to a fresh test DB on the `infra/mssql` container creates the partition function/scheme/table/indexes/roles. Smoke test confirms UPDATE is denied for the writer role. All migration tests pass when `SCADABRIDGE_MSSQL_TEST_CONN` is set; skip cleanly when unset.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -414,7 +414,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-env2-central-a
|
||||
environment:
|
||||
SCADALINK_CONFIG: Central
|
||||
SCADABRIDGE_CONFIG: Central
|
||||
ASPNETCORE_ENVIRONMENT: Development
|
||||
ASPNETCORE_URLS: "http://+:5000"
|
||||
ports:
|
||||
@@ -431,7 +431,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-env2-central-b
|
||||
environment:
|
||||
SCADALINK_CONFIG: Central
|
||||
SCADABRIDGE_CONFIG: Central
|
||||
ASPNETCORE_ENVIRONMENT: Development
|
||||
ASPNETCORE_URLS: "http://+:5000"
|
||||
ports:
|
||||
@@ -448,7 +448,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-env2-site-x-a
|
||||
environment:
|
||||
SCADALINK_CONFIG: Site
|
||||
SCADABRIDGE_CONFIG: Site
|
||||
ports:
|
||||
- "9121:8082" # Akka remoting
|
||||
- "9123:8083" # gRPC streaming
|
||||
@@ -464,7 +464,7 @@ services:
|
||||
image: scadabridge:latest
|
||||
container_name: scadabridge-env2-site-x-b
|
||||
environment:
|
||||
SCADALINK_CONFIG: Site
|
||||
SCADABRIDGE_CONFIG: Site
|
||||
ports:
|
||||
- "9122:8082" # Akka remoting
|
||||
- "9124:8083" # gRPC streaming
|
||||
|
||||
@@ -81,7 +81,7 @@ Exactly one of `content.json` or `content.enc` is present.
|
||||
"createdAtUtc": "2026-05-24T12:34:56Z",
|
||||
"sourceEnvironment": "dev-cluster-a",
|
||||
"exportedBy": "alice@corp.example",
|
||||
"scadaLinkVersion": "1.4.2",
|
||||
"scadaBridgeVersion": "1.4.2",
|
||||
"contentHash": "sha256:...",
|
||||
"encryption": {
|
||||
"algorithm": "AES-256-GCM",
|
||||
|
||||
@@ -734,7 +734,7 @@ Tests:
|
||||
|
||||
**Step 2-5:** Run-fail → implement → run-pass → commit.
|
||||
|
||||
`ManifestBuilder` accepts: `sourceEnvironment, exportedBy, scadaLinkVersion, encryption?, contents[], contentBytes` and returns a `BundleManifest` with `ContentHash = SHA-256(contentBytes)`.
|
||||
`ManifestBuilder` accepts: `sourceEnvironment, exportedBy, scadaBridgeVersion, encryption?, contents[], contentBytes` and returns a `BundleManifest` with `ContentHash = SHA-256(contentBytes)`.
|
||||
|
||||
`ManifestValidator.Validate(BundleManifest manifest, byte[] contentBytes)` returns a `ValidationResult` enum (`Ok | UnsupportedFormatVersion | ContentHashMismatch | MalformedManifest`).
|
||||
|
||||
|
||||
@@ -59,20 +59,24 @@ They are read by code (`Environment.GetEnvironmentVariable(...)` in Host/CLI/tes
|
||||
Scrubbing these would destroy their before→after meaning:
|
||||
|
||||
- `tools/rename-to-scadabridge.sh` — prior rename tooling.
|
||||
- `tools/scrub-scadalink-refs.sh` — this scrub script (its substitution rules are the mapping).
|
||||
- `docker/rename-databases.sh` — DB rename helper (`ALTER DATABASE ScadaLinkConfig MODIFY NAME = ScadaBridgeConfig`, `ALTER LOGIN [scadalink_app] ...`).
|
||||
- `docs/plans/2026-05-28-scadabridge-rename-design.md` — prior rename design.
|
||||
- `docs/plans/2026-05-31-folder-repo-rename-scadabridge-design.md` — **this document** (also a before→after record).
|
||||
- `docs/plans/2026-05-31-folder-repo-rename-scadabridge-plan.md` — the implementation plan (its substitution table and embedded script are the mapping).
|
||||
|
||||
### Completeness gate
|
||||
|
||||
Must return only the four carve-outs:
|
||||
Must return only the six carve-outs:
|
||||
|
||||
```bash
|
||||
git grep -niE "scadalink" -- . \
|
||||
':!tools/rename-to-scadabridge.sh' \
|
||||
':!tools/scrub-scadalink-refs.sh' \
|
||||
':!docker/rename-databases.sh' \
|
||||
':!docs/plans/2026-05-28-scadabridge-rename-design.md' \
|
||||
':!docs/plans/2026-05-31-folder-repo-rename-scadabridge-design.md'
|
||||
':!docs/plans/2026-05-31-folder-repo-rename-scadabridge-design.md' \
|
||||
':!docs/plans/2026-05-31-folder-repo-rename-scadabridge-plan.md'
|
||||
```
|
||||
|
||||
## Section 3 — Collision folder
|
||||
|
||||
@@ -310,9 +310,9 @@ Configuration is resolved in the following priority order (highest wins):
|
||||
|
||||
1. **Command-line options**: `--url`, `--username`, `--password`, `--format`.
|
||||
2. **Environment variables**:
|
||||
- `SCADALINK_MANAGEMENT_URL` — Management API URL (e.g., `http://central-host:5000`).
|
||||
- `SCADALINK_FORMAT` — Default output format (`json` or `table`).
|
||||
- `SCADALINK_USERNAME` / `SCADALINK_PASSWORD` — LDAP credentials. Preferred over
|
||||
- `SCADABRIDGE_MANAGEMENT_URL` — Management API URL (e.g., `http://central-host:5000`).
|
||||
- `SCADABRIDGE_FORMAT` — Default output format (`json` or `table`).
|
||||
- `SCADABRIDGE_USERNAME` / `SCADABRIDGE_PASSWORD` — LDAP credentials. Preferred over
|
||||
`--password` on the command line, which is visible in process listings and shell
|
||||
history. Credentials are never read from the config file.
|
||||
3. **Configuration file**: `~/.scadabridge/config.json` — Persistent defaults for management URL and output format only (never credentials).
|
||||
|
||||
@@ -53,7 +53,7 @@ Exactly one of `content.json` or `content.enc` is present.
|
||||
"createdAtUtc": "2026-05-24T12:34:56Z",
|
||||
"sourceEnvironment": "dev-cluster-a",
|
||||
"exportedBy": "alice@corp.example",
|
||||
"scadaLinkVersion": "1.4.2",
|
||||
"scadaBridgeVersion": "1.4.2",
|
||||
"contentHash": "sha256:...",
|
||||
"encryption": {
|
||||
"algorithm": "AES-256-GCM",
|
||||
@@ -325,7 +325,7 @@ The `manifest.json` file is always present in the ZIP root and is never encrypte
|
||||
"createdAtUtc": "2026-05-24T12:34:56Z",
|
||||
"sourceEnvironment": "dev-cluster-a",
|
||||
"exportedBy": "alice@corp.example",
|
||||
"scadaLinkVersion": "1.4.2",
|
||||
"scadaBridgeVersion": "1.4.2",
|
||||
"contentHash": "sha256:abc123...",
|
||||
"encryption": {
|
||||
"algorithm": "AES-256-GCM",
|
||||
@@ -371,7 +371,7 @@ The `manifest.json` file is always present in the ZIP root and is never encrypte
|
||||
| `createdAtUtc` | ISO-8601 UTC timestamp of when the export was created. |
|
||||
| `sourceEnvironment` | The `SourceEnvironment` name of the exporting cluster (from `TransportOptions`). Displayed in the import wizard and required to be retyped at the confirm step. |
|
||||
| `exportedBy` | Authenticated username of the person who performed the export. |
|
||||
| `scadaLinkVersion` | Application version of the exporting node. Used for diagnostic display only. |
|
||||
| `scadaBridgeVersion` | Application version of the exporting node. Used for diagnostic display only. |
|
||||
| `contentHash` | `sha256:<hex>` — SHA-256 of the raw `content.json` or `content.enc` bytes (pre-encryption). Verified on upload before any decryption. |
|
||||
| `encryption` | Present only when a passphrase was supplied. Contains the KDF parameters and the per-bundle random salt and IV needed to re-derive the key and decrypt. Omitted for plaintext bundles. |
|
||||
| `encryption.algorithm` | Always `"AES-256-GCM"` in v1. |
|
||||
|
||||
@@ -531,7 +531,7 @@ Sites log operational events locally, including:
|
||||
- The CLI sends user credentials via HTTP Basic Auth. The server authenticates against **LDAP/AD** and resolves roles before dispatching commands to the ManagementActor.
|
||||
- CLI commands mirror all Management Service operations: templates, instances, sites, data connections, deployments, external systems, notifications, security (API keys and role mappings), audit log queries, and health status.
|
||||
- Output is **JSON by default** (machine-readable, suitable for scripting) with an optional `--format table` flag for human-readable tabular output.
|
||||
- Configuration is resolved from command-line options, **environment variables** (`SCADALINK_MANAGEMENT_URL`, `SCADALINK_FORMAT`), or a **configuration file** (`~/.scadabridge/config.json`).
|
||||
- Configuration is resolved from command-line options, **environment variables** (`SCADABRIDGE_MANAGEMENT_URL`, `SCADABRIDGE_FORMAT`), or a **configuration file** (`~/.scadabridge/config.json`).
|
||||
- The CLI is a separate executable from the Host binary — it is deployed on any machine with HTTP access to a central node.
|
||||
|
||||
## 14. General Conventions
|
||||
|
||||
@@ -13,14 +13,14 @@ public class CliConfig
|
||||
public string DefaultFormat { get; set; } = "json";
|
||||
|
||||
/// <summary>
|
||||
/// LDAP username from the <c>SCADALINK_USERNAME</c> environment variable, if set.
|
||||
/// LDAP username from the <c>SCADABRIDGE_USERNAME</c> environment variable, if set.
|
||||
/// Credentials are intentionally only sourced from environment variables (or the
|
||||
/// command line) — never from the config file — so they are not persisted to disk.
|
||||
/// </summary>
|
||||
public string? Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// LDAP password from the <c>SCADALINK_PASSWORD</c> environment variable, if set.
|
||||
/// LDAP password from the <c>SCADABRIDGE_PASSWORD</c> environment variable, if set.
|
||||
/// Provides a safer alternative to <c>--password</c>, which leaks into process
|
||||
/// listings and shell history.
|
||||
/// </summary>
|
||||
@@ -69,20 +69,20 @@ public class CliConfig
|
||||
}
|
||||
|
||||
// Override from environment variables
|
||||
var envUrl = Environment.GetEnvironmentVariable("SCADALINK_MANAGEMENT_URL");
|
||||
var envUrl = Environment.GetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL");
|
||||
if (!string.IsNullOrEmpty(envUrl))
|
||||
config.ManagementUrl = envUrl;
|
||||
|
||||
var envFormat = Environment.GetEnvironmentVariable("SCADALINK_FORMAT");
|
||||
var envFormat = Environment.GetEnvironmentVariable("SCADABRIDGE_FORMAT");
|
||||
if (!string.IsNullOrEmpty(envFormat))
|
||||
config.DefaultFormat = envFormat;
|
||||
|
||||
// Credentials from environment variables only (never the config file).
|
||||
var envUsername = Environment.GetEnvironmentVariable("SCADALINK_USERNAME");
|
||||
var envUsername = Environment.GetEnvironmentVariable("SCADABRIDGE_USERNAME");
|
||||
if (!string.IsNullOrEmpty(envUsername))
|
||||
config.Username = envUsername;
|
||||
|
||||
var envPassword = Environment.GetEnvironmentVariable("SCADALINK_PASSWORD");
|
||||
var envPassword = Environment.GetEnvironmentVariable("SCADABRIDGE_PASSWORD");
|
||||
if (!string.IsNullOrEmpty(envPassword))
|
||||
config.Password = envPassword;
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ public static class AuditCommandHelpers
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
return AuditConnection.Fail(
|
||||
"No management URL specified. Use --url, set SCADALINK_MANAGEMENT_URL, or add 'managementUrl' to ~/.scadabridge/config.json.",
|
||||
"No management URL specified. Use --url, set SCADABRIDGE_MANAGEMENT_URL, or add 'managementUrl' to ~/.scadabridge/config.json.",
|
||||
"NO_URL");
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ public static class AuditCommandHelpers
|
||||
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
return AuditConnection.Fail(
|
||||
"Credentials required. Use --username/--password or set SCADALINK_USERNAME/SCADALINK_PASSWORD.",
|
||||
"Credentials required. Use --username/--password or set SCADABRIDGE_USERNAME/SCADABRIDGE_PASSWORD.",
|
||||
"NO_CREDENTIALS");
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ internal static class CommandHelpers
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
OutputFormatter.WriteError(
|
||||
"No management URL specified. Use --url, set SCADALINK_MANAGEMENT_URL, or add 'managementUrl' to ~/.scadabridge/config.json.",
|
||||
"No management URL specified. Use --url, set SCADABRIDGE_MANAGEMENT_URL, or add 'managementUrl' to ~/.scadabridge/config.json.",
|
||||
"NO_URL");
|
||||
return 1;
|
||||
}
|
||||
@@ -65,14 +65,14 @@ internal static class CommandHelpers
|
||||
}
|
||||
|
||||
// Resolve credentials: command-line options take precedence, then the
|
||||
// SCADALINK_USERNAME / SCADALINK_PASSWORD environment variables.
|
||||
// SCADABRIDGE_USERNAME / SCADABRIDGE_PASSWORD environment variables.
|
||||
var username = ResolveCredential(result.GetValue(usernameOption), config.Username);
|
||||
var password = ResolveCredential(result.GetValue(passwordOption), config.Password);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
OutputFormatter.WriteError(
|
||||
"Credentials required. Use --username/--password or set SCADALINK_USERNAME/SCADALINK_PASSWORD.",
|
||||
"Credentials required. Use --username/--password or set SCADABRIDGE_USERNAME/SCADABRIDGE_PASSWORD.",
|
||||
"NO_CREDENTIALS");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public static class DebugCommands
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
OutputFormatter.WriteError(
|
||||
"No management URL specified. Use --url, set SCADALINK_MANAGEMENT_URL, or add 'managementUrl' to ~/.scadabridge/config.json.",
|
||||
"No management URL specified. Use --url, set SCADABRIDGE_MANAGEMENT_URL, or add 'managementUrl' to ~/.scadabridge/config.json.",
|
||||
"NO_URL");
|
||||
return 1;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public static class DebugCommands
|
||||
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
OutputFormatter.WriteError(
|
||||
"Credentials required. Use --username/--password or set SCADALINK_USERNAME/SCADALINK_PASSWORD.",
|
||||
"Credentials required. Use --username/--password or set SCADABRIDGE_USERNAME/SCADABRIDGE_PASSWORD.",
|
||||
"NO_CREDENTIALS");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ The output binary is `scadabridge` (or `scadabridge.exe` on Windows).
|
||||
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. `SCADALINK_MANAGEMENT_URL` environment variable
|
||||
2. `SCADABRIDGE_MANAGEMENT_URL` environment variable
|
||||
3. `managementUrl` field in `~/.scadabridge/config.json`
|
||||
|
||||
```sh
|
||||
@@ -57,10 +57,10 @@ For the Docker test environment, see `docker/README.md` for a ready-to-use confi
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `SCADALINK_MANAGEMENT_URL` | Management API URL (overrides config file) |
|
||||
| `SCADALINK_FORMAT` | Default output format (overrides config file) |
|
||||
| `SCADALINK_USERNAME` | LDAP username (fallback when `--username` is not supplied) |
|
||||
| `SCADALINK_PASSWORD` | LDAP password (fallback when `--password` is not supplied). Preferred over `--password` on the command line, which leaks into process listings and shell history. |
|
||||
| `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
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase;
|
||||
/// Factory for creating DbContext instances at design time (used by dotnet ef tooling).
|
||||
/// Resolves the connection string from the Host's appsettings files, or — for environments
|
||||
/// where those files are not present — from the
|
||||
/// <c>SCADALINK_DESIGNTIME_CONNECTIONSTRING</c> environment variable.
|
||||
/// <c>SCADABRIDGE_DESIGNTIME_CONNECTIONSTRING</c> environment variable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// There is deliberately no hardcoded fallback connection string. A credential literal in
|
||||
@@ -19,7 +19,7 @@ namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase;
|
||||
/// </remarks>
|
||||
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ScadaBridgeDbContext>
|
||||
{
|
||||
private const string EnvironmentVariableName = "SCADALINK_DESIGNTIME_CONNECTIONSTRING";
|
||||
private const string EnvironmentVariableName = "SCADABRIDGE_DESIGNTIME_CONNECTIONSTRING";
|
||||
private const string ConfigurationKey = "ScadaBridge:Database:ConfigurationDb";
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -22,9 +22,9 @@ using ZB.MOM.WW.ScadaBridge.TemplateEngine;
|
||||
using ZB.MOM.WW.ScadaBridge.Transport;
|
||||
using Serilog;
|
||||
|
||||
// SCADALINK_CONFIG determines which role-specific config to load (Central or Site)
|
||||
// SCADABRIDGE_CONFIG determines which role-specific config to load (Central or Site)
|
||||
// DOTNET_ENVIRONMENT/ASPNETCORE_ENVIRONMENT stay as "Development" for dev tooling (static assets, EF migrations, etc.)
|
||||
var scadabridgeConfig = Environment.GetEnvironmentVariable("SCADALINK_CONFIG")
|
||||
var scadabridgeConfig = Environment.GetEnvironmentVariable("SCADABRIDGE_CONFIG")
|
||||
?? Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")
|
||||
?? "Production";
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"environmentVariables": {
|
||||
"DOTNET_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"SCADALINK_CONFIG": "Central"
|
||||
"SCADABRIDGE_CONFIG": "Central"
|
||||
}
|
||||
},
|
||||
"ScadaBridge Site": {
|
||||
@@ -19,7 +19,7 @@
|
||||
"environmentVariables": {
|
||||
"DOTNET_ENVIRONMENT": "Development",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"SCADALINK_CONFIG": "Site"
|
||||
"SCADABRIDGE_CONFIG": "Site"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
},
|
||||
"_secrets": "Host-003: Secrets are NOT committed in this file. Supply them via environment variables, which the Host's configuration builder (AddEnvironmentVariables) overlays over this file. Required: ScadaBridge__Database__ConfigurationDb, ScadaBridge__Security__LdapServiceAccountPassword, ScadaBridge__Security__JwtSigningKey. The ${...} placeholders below are intentionally non-functional and must be overridden per environment.",
|
||||
"Database": {
|
||||
"ConfigurationDb": "${SCADALINK_CONFIGURATIONDB_CONNECTION_STRING}"
|
||||
"ConfigurationDb": "${SCADABRIDGE_CONFIGURATIONDB_CONNECTION_STRING}"
|
||||
},
|
||||
"Security": {
|
||||
"LdapServer": "localhost",
|
||||
@@ -29,8 +29,8 @@
|
||||
"AllowInsecureLdap": true,
|
||||
"LdapSearchBase": "dc=scadabridge,dc=local",
|
||||
"LdapServiceAccountDn": "cn=admin,dc=scadabridge,dc=local",
|
||||
"LdapServiceAccountPassword": "${SCADALINK_LDAP_SERVICE_ACCOUNT_PASSWORD}",
|
||||
"JwtSigningKey": "${SCADALINK_JWT_SIGNING_KEY}",
|
||||
"LdapServiceAccountPassword": "${SCADABRIDGE_LDAP_SERVICE_ACCOUNT_PASSWORD}",
|
||||
"JwtSigningKey": "${SCADABRIDGE_JWT_SIGNING_KEY}",
|
||||
"JwtExpiryMinutes": 15,
|
||||
"IdleTimeoutMinutes": 30
|
||||
},
|
||||
|
||||
@@ -115,7 +115,7 @@ public sealed class BundleExporter : IBundleExporter
|
||||
var templateManifest = _manifestBuilder.Build(
|
||||
sourceEnvironment: sourceEnvironment,
|
||||
exportedBy: user,
|
||||
scadaLinkVersion: assemblyVersion,
|
||||
scadaBridgeVersion: assemblyVersion,
|
||||
encryption: encryptionSeed,
|
||||
summary: summary,
|
||||
contents: resolved.ContentManifest,
|
||||
|
||||
@@ -20,7 +20,7 @@ public sealed class ManifestBuilder
|
||||
/// </summary>
|
||||
/// <param name="sourceEnvironment">Environment label identifying where the bundle was exported from.</param>
|
||||
/// <param name="exportedBy">Username of the operator who performed the export.</param>
|
||||
/// <param name="scadaLinkVersion">ScadaBridge version string stamped in the manifest.</param>
|
||||
/// <param name="scadaBridgeVersion">ScadaBridge version string stamped in the manifest.</param>
|
||||
/// <param name="encryption">Encryption metadata when the content is encrypted; null for plain bundles.</param>
|
||||
/// <param name="summary">High-level summary of artifact counts.</param>
|
||||
/// <param name="contents">Per-entry content table describing each artifact in the bundle.</param>
|
||||
@@ -29,7 +29,7 @@ public sealed class ManifestBuilder
|
||||
public BundleManifest Build(
|
||||
string sourceEnvironment,
|
||||
string exportedBy,
|
||||
string scadaLinkVersion,
|
||||
string scadaBridgeVersion,
|
||||
EncryptionMetadata? encryption,
|
||||
BundleSummary summary,
|
||||
IReadOnlyList<ManifestContentEntry> contents,
|
||||
@@ -37,7 +37,7 @@ public sealed class ManifestBuilder
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(sourceEnvironment);
|
||||
ArgumentNullException.ThrowIfNull(exportedBy);
|
||||
ArgumentNullException.ThrowIfNull(scadaLinkVersion);
|
||||
ArgumentNullException.ThrowIfNull(scadaBridgeVersion);
|
||||
ArgumentNullException.ThrowIfNull(summary);
|
||||
ArgumentNullException.ThrowIfNull(contents);
|
||||
ArgumentNullException.ThrowIfNull(contentBytes);
|
||||
@@ -50,7 +50,7 @@ public sealed class ManifestBuilder
|
||||
CreatedAtUtc: DateTimeOffset.UtcNow,
|
||||
SourceEnvironment: sourceEnvironment,
|
||||
ExportedBy: exportedBy,
|
||||
ScadaBridgeVersion: scadaLinkVersion,
|
||||
ScadaBridgeVersion: scadaBridgeVersion,
|
||||
ContentHash: contentHash,
|
||||
Encryption: encryption,
|
||||
Summary: summary,
|
||||
|
||||
@@ -8,13 +8,13 @@ public class CliConfigTests
|
||||
[Fact]
|
||||
public void Load_DefaultFormat_IsJson()
|
||||
{
|
||||
var origUrl = Environment.GetEnvironmentVariable("SCADALINK_MANAGEMENT_URL");
|
||||
var origFormat = Environment.GetEnvironmentVariable("SCADALINK_FORMAT");
|
||||
var origUrl = Environment.GetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL");
|
||||
var origFormat = Environment.GetEnvironmentVariable("SCADABRIDGE_FORMAT");
|
||||
|
||||
try
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_MANAGEMENT_URL", null);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_FORMAT", null);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL", null);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_FORMAT", null);
|
||||
|
||||
var config = CliConfig.Load();
|
||||
|
||||
@@ -23,18 +23,18 @@ public class CliConfigTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_MANAGEMENT_URL", origUrl);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_FORMAT", origFormat);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL", origUrl);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_FORMAT", origFormat);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_ManagementUrl_FromEnvironment()
|
||||
{
|
||||
var orig = Environment.GetEnvironmentVariable("SCADALINK_MANAGEMENT_URL");
|
||||
var orig = Environment.GetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL");
|
||||
try
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_MANAGEMENT_URL", "http://central:5000");
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL", "http://central:5000");
|
||||
|
||||
var config = CliConfig.Load();
|
||||
|
||||
@@ -42,17 +42,17 @@ public class CliConfigTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_MANAGEMENT_URL", orig);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL", orig);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_Format_FromEnvironment()
|
||||
{
|
||||
var orig = Environment.GetEnvironmentVariable("SCADALINK_FORMAT");
|
||||
var orig = Environment.GetEnvironmentVariable("SCADABRIDGE_FORMAT");
|
||||
try
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_FORMAT", "table");
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_FORMAT", "table");
|
||||
|
||||
var config = CliConfig.Load();
|
||||
|
||||
@@ -60,7 +60,7 @@ public class CliConfigTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_FORMAT", orig);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_FORMAT", orig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,19 +81,19 @@ public class CliConfigTests
|
||||
|
||||
var origHome = Environment.GetEnvironmentVariable("HOME");
|
||||
var origUserProfile = Environment.GetEnvironmentVariable("USERPROFILE");
|
||||
var origUrl = Environment.GetEnvironmentVariable("SCADALINK_MANAGEMENT_URL");
|
||||
var origFormat = Environment.GetEnvironmentVariable("SCADALINK_FORMAT");
|
||||
var origUser = Environment.GetEnvironmentVariable("SCADALINK_USERNAME");
|
||||
var origPass = Environment.GetEnvironmentVariable("SCADALINK_PASSWORD");
|
||||
var origUrl = Environment.GetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL");
|
||||
var origFormat = Environment.GetEnvironmentVariable("SCADABRIDGE_FORMAT");
|
||||
var origUser = Environment.GetEnvironmentVariable("SCADABRIDGE_USERNAME");
|
||||
var origPass = Environment.GetEnvironmentVariable("SCADABRIDGE_PASSWORD");
|
||||
var origStderr = Console.Error;
|
||||
try
|
||||
{
|
||||
Environment.SetEnvironmentVariable("HOME", tempHome);
|
||||
Environment.SetEnvironmentVariable("USERPROFILE", tempHome);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_MANAGEMENT_URL", null);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_FORMAT", null);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_USERNAME", null);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_PASSWORD", null);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL", null);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_FORMAT", null);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_USERNAME", null);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_PASSWORD", null);
|
||||
|
||||
var stderrCapture = new StringWriter();
|
||||
Console.SetError(stderrCapture);
|
||||
@@ -112,10 +112,10 @@ public class CliConfigTests
|
||||
Console.SetError(origStderr);
|
||||
Environment.SetEnvironmentVariable("HOME", origHome);
|
||||
Environment.SetEnvironmentVariable("USERPROFILE", origUserProfile);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_MANAGEMENT_URL", origUrl);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_FORMAT", origFormat);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_USERNAME", origUser);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_PASSWORD", origPass);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_MANAGEMENT_URL", origUrl);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_FORMAT", origFormat);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_USERNAME", origUser);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_PASSWORD", origPass);
|
||||
try { Directory.Delete(tempHome, recursive: true); } catch { /* best-effort cleanup */ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace ZB.MOM.WW.ScadaBridge.CLI.Tests;
|
||||
/// <summary>
|
||||
/// Regression tests for CLI-006 — credentials could only be supplied via the
|
||||
/// <c>--password</c> command-line option, which leaks into process listings and
|
||||
/// shell history. A <c>SCADALINK_PASSWORD</c> / <c>SCADALINK_USERNAME</c> environment
|
||||
/// shell history. A <c>SCADABRIDGE_PASSWORD</c> / <c>SCADABRIDGE_USERNAME</c> environment
|
||||
/// fallback gives CI/CD a safer alternative.
|
||||
/// </summary>
|
||||
[Collection("Environment")]
|
||||
@@ -14,10 +14,10 @@ public class CredentialResolutionTests
|
||||
[Fact]
|
||||
public void Load_Password_FromEnvironment()
|
||||
{
|
||||
var orig = Environment.GetEnvironmentVariable("SCADALINK_PASSWORD");
|
||||
var orig = Environment.GetEnvironmentVariable("SCADABRIDGE_PASSWORD");
|
||||
try
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_PASSWORD", "s3cret");
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_PASSWORD", "s3cret");
|
||||
|
||||
var config = CliConfig.Load();
|
||||
|
||||
@@ -25,17 +25,17 @@ public class CredentialResolutionTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_PASSWORD", orig);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_PASSWORD", orig);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_Username_FromEnvironment()
|
||||
{
|
||||
var orig = Environment.GetEnvironmentVariable("SCADALINK_USERNAME");
|
||||
var orig = Environment.GetEnvironmentVariable("SCADABRIDGE_USERNAME");
|
||||
try
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_USERNAME", "ci-user");
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_USERNAME", "ci-user");
|
||||
|
||||
var config = CliConfig.Load();
|
||||
|
||||
@@ -43,19 +43,19 @@ public class CredentialResolutionTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_USERNAME", orig);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_USERNAME", orig);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_NoCredentialEnvVars_LeavesCredentialsNull()
|
||||
{
|
||||
var origUser = Environment.GetEnvironmentVariable("SCADALINK_USERNAME");
|
||||
var origPass = Environment.GetEnvironmentVariable("SCADALINK_PASSWORD");
|
||||
var origUser = Environment.GetEnvironmentVariable("SCADABRIDGE_USERNAME");
|
||||
var origPass = Environment.GetEnvironmentVariable("SCADABRIDGE_PASSWORD");
|
||||
try
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_USERNAME", null);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_PASSWORD", null);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_USERNAME", null);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_PASSWORD", null);
|
||||
|
||||
var config = CliConfig.Load();
|
||||
|
||||
@@ -64,8 +64,8 @@ public class CredentialResolutionTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
Environment.SetEnvironmentVariable("SCADALINK_USERNAME", origUser);
|
||||
Environment.SetEnvironmentVariable("SCADALINK_PASSWORD", origPass);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_USERNAME", origUser);
|
||||
Environment.SetEnvironmentVariable("SCADABRIDGE_PASSWORD", origPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests.Audit;
|
||||
/// Connection string mirrors the Docker cluster's <c>scadabridge_app</c> account
|
||||
/// from <c>docker/central-node-a/appsettings.Central.json</c>, with the host
|
||||
/// pointed at the host-exposed port (<c>localhost:1433</c>). The
|
||||
/// <c>SCADALINK_PLAYWRIGHT_DB</c> env var lets CI override the connection
|
||||
/// <c>SCADABRIDGE_PLAYWRIGHT_DB</c> env var lets CI override the connection
|
||||
/// without recompiling.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
@@ -34,11 +34,11 @@ internal static class AuditDataSeeder
|
||||
private const string DefaultConnectionString =
|
||||
"Server=localhost,1433;Database=ScadaBridgeConfig;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true;Encrypt=false;Connect Timeout=5";
|
||||
|
||||
private const string EnvVar = "SCADALINK_PLAYWRIGHT_DB";
|
||||
private const string EnvVar = "SCADABRIDGE_PLAYWRIGHT_DB";
|
||||
|
||||
/// <summary>
|
||||
/// Connection string for the running cluster's configuration DB. Resolved
|
||||
/// from <c>SCADALINK_PLAYWRIGHT_DB</c> when set, otherwise the local docker
|
||||
/// from <c>SCADABRIDGE_PLAYWRIGHT_DB</c> when set, otherwise the local docker
|
||||
/// dev defaults.
|
||||
/// </summary>
|
||||
public static string ConnectionString
|
||||
|
||||
@@ -30,7 +30,7 @@ public class AuditGridColumnTests
|
||||
/// <summary>Skip reason shared by the DB-seeding tests when MSSQL is down.</summary>
|
||||
private const string DbUnavailableSkipReason =
|
||||
"AuditDataSeeder cannot reach MSSQL at localhost:1433 — bring up infra/docker-compose and docker/deploy.sh, " +
|
||||
"or set SCADALINK_PLAYWRIGHT_DB to a reachable connection string.";
|
||||
"or set SCADABRIDGE_PLAYWRIGHT_DB to a reachable connection string.";
|
||||
|
||||
private readonly PlaywrightFixture _fixture;
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ public class AuditLogPageTests
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"AuditDataSeeder cannot reach MSSQL at localhost:1433 — bring up infra/docker-compose and docker/deploy.sh, " +
|
||||
"or set SCADALINK_PLAYWRIGHT_DB to a reachable connection string.");
|
||||
"or set SCADABRIDGE_PLAYWRIGHT_DB to a reachable connection string.");
|
||||
}
|
||||
|
||||
var runId = Guid.NewGuid().ToString("N");
|
||||
|
||||
+2
-2
@@ -28,11 +28,11 @@ internal static class SiteCallDataSeeder
|
||||
private const string DefaultConnectionString =
|
||||
"Server=localhost,1433;Database=ScadaBridgeConfig;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true;Encrypt=false;Connect Timeout=5";
|
||||
|
||||
private const string EnvVar = "SCADALINK_PLAYWRIGHT_DB";
|
||||
private const string EnvVar = "SCADABRIDGE_PLAYWRIGHT_DB";
|
||||
|
||||
/// <summary>
|
||||
/// Connection string for the running cluster's configuration DB. Resolved
|
||||
/// from <c>SCADALINK_PLAYWRIGHT_DB</c> when set, otherwise the local docker
|
||||
/// from <c>SCADABRIDGE_PLAYWRIGHT_DB</c> when set, otherwise the local docker
|
||||
/// dev defaults.
|
||||
/// </summary>
|
||||
public static string ConnectionString
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ public class SiteCallsPageTests
|
||||
/// <summary>Skip reason shared by the DB-seeding tests when MSSQL is down.</summary>
|
||||
private const string DbUnavailableSkipReason =
|
||||
"SiteCallDataSeeder cannot reach MSSQL at localhost:1433 — bring up infra/docker-compose and docker/deploy.sh, " +
|
||||
"or set SCADALINK_PLAYWRIGHT_DB to a reachable connection string.";
|
||||
"or set SCADABRIDGE_PLAYWRIGHT_DB to a reachable connection string.";
|
||||
|
||||
[SkippableFact]
|
||||
public async Task FilterNarrowing_ChannelFilterShrinksGrid()
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests;
|
||||
|
||||
public class DesignTimeDbContextFactoryTests : IDisposable
|
||||
{
|
||||
private const string EnvVar = "SCADALINK_DESIGNTIME_CONNECTIONSTRING";
|
||||
private const string EnvVar = "SCADABRIDGE_DESIGNTIME_CONNECTIONSTRING";
|
||||
private readonly string? _originalEnv;
|
||||
|
||||
public DesignTimeDbContextFactoryTests()
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public sealed class MsSqlMigrationFixture : IDisposable
|
||||
private const string DefaultAdminConnectionString =
|
||||
"Server=localhost,1433;User Id=sa;Password=ScadaBridge_Dev1#;TrustServerCertificate=true;Encrypt=false;Connect Timeout=3";
|
||||
|
||||
private const string AdminEnvVar = "SCADALINK_MSSQL_TEST_CONN";
|
||||
private const string AdminEnvVar = "SCADABRIDGE_MSSQL_TEST_CONN";
|
||||
|
||||
public string DatabaseName { get; }
|
||||
|
||||
|
||||
@@ -110,10 +110,10 @@ public class HotPathLatencyTests
|
||||
var p95Us = MeasureP95Microseconds(MeasureIterations, () => _ = filter.Apply(evt));
|
||||
|
||||
// Default budget 50 µs (spec target). Override via env for slow CI:
|
||||
// SCADALINK_AUDIT_FILTER_4KB_P95_US — interpret as the regression
|
||||
// SCADABRIDGE_AUDIT_FILTER_4KB_P95_US — interpret as the regression
|
||||
// guard threshold. Print the observed value so a missed budget gives
|
||||
// useful telemetry on the test output.
|
||||
var threshold = GetThresholdMicroseconds("SCADALINK_AUDIT_FILTER_4KB_P95_US", 50d);
|
||||
var threshold = GetThresholdMicroseconds("SCADABRIDGE_AUDIT_FILTER_4KB_P95_US", 50d);
|
||||
Assert.True(p95Us < threshold,
|
||||
$"4KB body filter p95 = {p95Us:F1} µs; threshold = {threshold:F1} µs");
|
||||
}
|
||||
@@ -137,7 +137,7 @@ public class HotPathLatencyTests
|
||||
|
||||
var p95Us = MeasureP95Microseconds(MeasureIterations, () => _ = filter.Apply(evt));
|
||||
|
||||
var threshold = GetThresholdMicroseconds("SCADALINK_AUDIT_FILTER_RAW_P95_US", 10d);
|
||||
var threshold = GetThresholdMicroseconds("SCADABRIDGE_AUDIT_FILTER_RAW_P95_US", 10d);
|
||||
Assert.True(p95Us < threshold,
|
||||
$"Raw-event filter p95 = {p95Us:F1} µs; threshold = {threshold:F1} µs");
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public sealed class BundleImporterLoadTests
|
||||
var manifest = builder.Build(
|
||||
sourceEnvironment: "dev",
|
||||
exportedBy: "alice",
|
||||
scadaLinkVersion: "1.0.0",
|
||||
scadaBridgeVersion: "1.0.0",
|
||||
encryption: null,
|
||||
summary: new BundleSummary(content.Templates.Count, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
contents: Array.Empty<ManifestContentEntry>(),
|
||||
@@ -152,7 +152,7 @@ public sealed class BundleImporterLoadTests
|
||||
var manifest = builder.Build(
|
||||
sourceEnvironment: "dev",
|
||||
exportedBy: "alice",
|
||||
scadaLinkVersion: "1.0.0",
|
||||
scadaBridgeVersion: "1.0.0",
|
||||
encryption: seed,
|
||||
summary: new BundleSummary(content.Templates.Count, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
contents: Array.Empty<ManifestContentEntry>(),
|
||||
@@ -471,7 +471,7 @@ public sealed class BundleImporterLoadTests
|
||||
var manifest = rig.ManifestBuilder.Build(
|
||||
sourceEnvironment: "dev",
|
||||
exportedBy: "alice",
|
||||
scadaLinkVersion: "1.0.0",
|
||||
scadaBridgeVersion: "1.0.0",
|
||||
encryption: null,
|
||||
summary: new BundleSummary(1, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
contents: Array.Empty<ManifestContentEntry>(),
|
||||
|
||||
@@ -28,7 +28,7 @@ public sealed class BundleSerializerTests
|
||||
new ManifestBuilder().Build(
|
||||
sourceEnvironment: "test-env",
|
||||
exportedBy: "tester",
|
||||
scadaLinkVersion: "1.0.0",
|
||||
scadaBridgeVersion: "1.0.0",
|
||||
encryption: encryption,
|
||||
summary: new BundleSummary(0, 1, 1, 0, 0, 0, 0, 0, 0),
|
||||
contents: Array.Empty<ManifestContentEntry>(),
|
||||
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
# One-time scrub of residual ScadaLink/scadalink references → ScadaBridge.
|
||||
# Operates on git-tracked TEXT files only (git grep -I skips binaries),
|
||||
# minus carve-out migration records whose before→after meaning must survive.
|
||||
# Substitutions are applied most-specific-first so a broad rule cannot
|
||||
# double-replace an earlier result. Idempotent: re-running is a no-op.
|
||||
set -euo pipefail
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
# Carve-outs (migration records): prior rename tooling/design, the DB-rename
|
||||
# helper, this script itself, and the rename design + plan docs (which document
|
||||
# the old→new mapping and would be self-corrupted by the substitution).
|
||||
EXCLUDES_RE='^(tools/rename-to-scadabridge\.sh|tools/scrub-scadalink-refs\.sh|docker/rename-databases\.sh|docs/plans/2026-05-28-scadabridge-rename-design\.md|docs/plans/2026-05-31-folder-repo-rename-scadabridge-design\.md|docs/plans/2026-05-31-folder-repo-rename-scadabridge-plan\.md)$'
|
||||
|
||||
files=()
|
||||
while IFS= read -r f; do
|
||||
[[ "$f" =~ $EXCLUDES_RE ]] && continue
|
||||
files+=("$f")
|
||||
done < <(git grep -liI 'scadalink' -- .)
|
||||
|
||||
if [[ ${#files[@]} -eq 0 ]]; then
|
||||
echo "No files to scrub."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
printf 'Scrubbing %d file(s):\n' "${#files[@]}"
|
||||
printf ' %s\n' "${files[@]}"
|
||||
|
||||
sed -i '' \
|
||||
-e 's/ScadaLink\.Host\.exe/ZB.MOM.WW.ScadaBridge.Host.exe/g' \
|
||||
-e 's/ScadaLink__/ScadaBridge__/g' \
|
||||
-e 's/SCADALINK_/SCADABRIDGE_/g' \
|
||||
-e 's/scadaLinkVersion/scadaBridgeVersion/g' \
|
||||
-e 's/scadalink_app/scadabridge_app/g' \
|
||||
-e 's/ScadaLink/ScadaBridge/g' \
|
||||
-e 's/scadalink/scadabridge/g' \
|
||||
"${files[@]}"
|
||||
|
||||
echo "Done."
|
||||
Reference in New Issue
Block a user