Compare commits
6 Commits
f428804bef
...
3797af7f0f
| Author | SHA1 | Date | |
|---|---|---|---|
| 3797af7f0f | |||
| a47317d010 | |||
| c899cb162c | |||
| d69031dd08 | |||
| d317c07ea5 | |||
| e01f3bdabe |
@@ -6,17 +6,31 @@ When a change is requested, the default assumption is: update the design doc *an
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Top-level directories
|
||||
|
||||
- `src/` — C#/.NET implementation, one project per component (e.g. `ZB.MOM.WW.ScadaBridge.AuditLog`, `ZB.MOM.WW.ScadaBridge.NotificationOutbox`, `ZB.MOM.WW.ScadaBridge.SiteCallAudit`, `ZB.MOM.WW.ScadaBridge.CentralUI`, `ZB.MOM.WW.ScadaBridge.Host`, …). Solution file: `ZB.MOM.WW.ScadaBridge.slnx`.
|
||||
- `tests/` — Test projects (unit + integration).
|
||||
- `docs/` — Design documentation: `docs/requirements/` (high-level + per-component specs), `docs/test_infra/` (test infrastructure), `docs/plans/` (design-decision and implementation-plan docs). The spec the code implements.
|
||||
- `docker/` — 8-node cluster topology (2 central + 3 sites), `deploy.sh`, per-node `appsettings.*.json`. See [`docker/README.md`](docker/README.md) for setup, ports, and management commands. Rebuild + redeploy with `bash docker/deploy.sh`.
|
||||
- `docker-env2/` — Minimal second cluster topology (2 central + 1 site × 2 nodes), runs concurrently with `docker/` on host ports 91XX. Built specifically for testing the Transport (#24) feature with two real environments. See [`docker-env2/README.md`](docker-env2/README.md). Rebuild + redeploy with `bash docker-env2/deploy.sh`.
|
||||
- `infra/` — Docker Compose for local test services (LDAP, MS SQL, OPC UA, SMTP, REST API, Traefik).
|
||||
- `deploy/` — Production/on-host deployment artifacts (e.g. `deploy/wonder-app-vd03/`: `appsettings.Central.json`, `appsettings.Site.json`, `install.ps1`/`uninstall.ps1`, `RUNBOOK.md`).
|
||||
- `deployments/` — Deployment topology notes (`docker-cluster.md`, `docker-cluster-env2.md`, `README.md`).
|
||||
- `code-reviews/` — Per-component code-review notes (one folder per component, plus `_template`).
|
||||
- `tools/` — Repo maintenance/utility scripts (e.g. `rename-to-scadabridge.sh`).
|
||||
- `AkkaDotNet/` — Akka.NET reference documentation and best-practices notes.
|
||||
- `deprecated/` — Retired docs/notes kept for reference.
|
||||
- `logs/` — Local runtime log output.
|
||||
- `vendor/` — Vendored third-party assets (currently an empty placeholder).
|
||||
- `.claude/` — Claude Code project config (settings, skills, agents).
|
||||
|
||||
### Key documents
|
||||
|
||||
- `README.md` — Master index with component table and architecture diagrams.
|
||||
- `docs/requirements/HighLevelReqs.md` — Complete high-level requirements covering all functional areas.
|
||||
- `docs/requirements/Component-*.md` — Individual component design documents (one per component) — the spec the code implements.
|
||||
- `docs/test_infra/test_infra.md` — Master test infrastructure doc (OPC UA, LDAP, MS SQL, SMTP, REST API, Traefik).
|
||||
- `docs/plans/` — Design decision and implementation-plan documents from refinement sessions.
|
||||
- `AkkaDotNet/` — Akka.NET reference documentation and best practices notes.
|
||||
|
||||
## Sister Projects
|
||||
|
||||
|
||||
@@ -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`).
|
||||
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# Folder + Repo Rename `scadalink-design` → `ScadaBridge` — Design
|
||||
|
||||
**Date:** 2026-05-31
|
||||
**Status:** Approved, ready for implementation planning
|
||||
**Scope:** Rename the repo folder `~/Desktop/scadalink-design` → `~/Desktop/ScadaBridge`, rename the Gitea repository `dohertj2/scadalink-design` → `dohertj2/ScadaBridge`, and scrub every residual `scadalink`/`ScadaLink` reference inside the repo to its `ScadaBridge` equivalent.
|
||||
|
||||
This reverses the earlier decision (in `2026-05-28-scadabridge-rename-design.md`) to leave the folder name diverged from the product name, and completes the residual reference scrub that the earlier effort deliberately left out (the `SCADALINK_*` runtime env vars and the production deploy script).
|
||||
|
||||
## Context
|
||||
|
||||
The product was already renamed from "ScadaLink" to "ScadaBridge" in the `2026-05-28` effort: the solution (`ZB.MOM.WW.ScadaBridge.slnx`), all `src/`/`tests/` projects, namespaces, MS SQL databases, docker containers/network/image, the CLI config dir (`~/.scadabridge/`), `CLAUDE.md`, and `README.md` already say ScadaBridge. What remained untouched were the runtime environment variables (`SCADALINK_*`), one `.NET` config-key convention (`ScadaLink__*`), a stale assembly-name reference in the production deploy script, a few cosmetic identifiers, and historical doc/code-review mentions.
|
||||
|
||||
## Decisions
|
||||
|
||||
| # | Decision | Selected option |
|
||||
|---|----------|-----------------|
|
||||
| 1 | Folder-name collision (`~/Desktop/ScadaBridge` already exists — a separate, older, non-git project) | Rename the existing folder aside to `~/Desktop/ScadaBridge-old` (non-destructive); nothing deleted |
|
||||
| 2 | Reference scope | Full scrub — env vars, config keys, assembly name, SQL login, cosmetic identifiers, and historical docs/code-reviews |
|
||||
| 3 | Env-var cutover style | Hard cutover (no backward-compat fallback); dev stack is redeployed |
|
||||
| 4 | New env-var/identifier prefix | Short product name `SCADABRIDGE_` / `ScadaBridge__` (no `ZB.MOM.WW`), consistent with existing runtime artifacts (`scadabridge-*` containers, `~/.scadabridge/`) |
|
||||
| 5 | Gitea server-side rename | User renames via the Gitea web UI; Claude updates the local `origin` remote and verifies |
|
||||
| 6 | Execution mechanism | Scripted multi-pass `sed` over `git ls-files`, most-specific-first, with a completeness-gate `git grep` |
|
||||
| 7 | Migration records | Carved out of the scrub so their before→after meaning survives (see §2) |
|
||||
|
||||
## Section 1 — Order of operations
|
||||
|
||||
1. **Safety check** — confirm the working tree is clean (commit/stash WIP first); record the current branch.
|
||||
2. **Clear the collision** — `mv ~/Desktop/ScadaBridge ~/Desktop/ScadaBridge-old`.
|
||||
3. **Move the folder** — `mv ~/Desktop/scadalink-design ~/Desktop/ScadaBridge`. Plain OS move; git tracks contents, not the repo-root directory name, so history is untouched. `.idea/` and `.claude/` ride along inside the moved folder.
|
||||
4. **Scrub references** — run the scripted multi-pass `sed` (§2).
|
||||
5. **Build + test gate** — `dotnet build ZB.MOM.WW.ScadaBridge.slnx`, unit tests, completeness `git grep`.
|
||||
6. **Commit** (§5).
|
||||
7. **Runtime cutover** — rebuild + redeploy docker so running containers read the new env-var names (§4). No DB changes.
|
||||
8. **Gitea rename** — user web-UI rename; Claude updates local `origin` + verifies fetch/push.
|
||||
9. **Write/commit this design doc** (already produced by the brainstorm).
|
||||
|
||||
## Section 2 — The scrub
|
||||
|
||||
A new `tools/scrub-scadalink-refs.sh` operating on `git ls-files -z | xargs -0 sed -i ''` (skips `.git/` and `bin/obj` build artifacts), applied **most-specific-first** so a broad rule cannot double-replace an earlier result:
|
||||
|
||||
```
|
||||
1. ScadaLink.Host.exe → ZB.MOM.WW.ScadaBridge.Host.exe (stale assembly name, deploy/install.ps1)
|
||||
2. ScadaLink__ → ScadaBridge__ (.NET hierarchical config keys, deploy/install.ps1)
|
||||
3. SCADALINK_ → SCADABRIDGE_ (13 runtime env vars)
|
||||
4. scadaLinkVersion → scadaBridgeVersion (Transport param/local var — cosmetic)
|
||||
5. scadalink_app → scadabridge_app (SQL login)
|
||||
6. ScadaLink → ScadaBridge (residual)
|
||||
7. scadalink → scadabridge (residual)
|
||||
```
|
||||
|
||||
### The 13 `SCADALINK_*` env vars in scope
|
||||
|
||||
`SCADALINK_CONFIG`, `SCADALINK_FORMAT`, `SCADALINK_USERNAME`, `SCADALINK_PASSWORD`, `SCADALINK_MANAGEMENT_URL`, `SCADALINK_CONFIGURATIONDB_CONNECTION_STRING`, `SCADALINK_DESIGNTIME_CONNECTIONSTRING`, `SCADALINK_MSSQL_TEST_CONN`, `SCADALINK_PLAYWRIGHT_DB`, `SCADALINK_JWT_SIGNING_KEY`, `SCADALINK_LDAP_SERVICE_ACCOUNT_PASSWORD`, `SCADALINK_AUDIT_FILTER_4KB_P95_US`, `SCADALINK_AUDIT_FILTER_RAW_P95_US`.
|
||||
|
||||
They are read by code (`Environment.GetEnvironmentVariable(...)` in Host/CLI/tests) **and** set by `docker/docker-compose.yml`, `docker-env2/docker-compose.yml`, `appsettings.Central.json` (`${...}` placeholders), and `deploy/wonder-app-vd03/install.ps1`. All sites change together in one pass.
|
||||
|
||||
### Carved out (excluded — migration records)
|
||||
|
||||
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 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-plan.md'
|
||||
```
|
||||
|
||||
## Section 3 — Collision folder
|
||||
|
||||
The existing `~/Desktop/ScadaBridge` (non-git, older project containing `akka.md`, `netstd.md`, `CommentChecker`, its own `src/`/`tests/`/`tsdb/`) is renamed to `~/Desktop/ScadaBridge-old`. Nothing is deleted. If the user later confirms it is dead, they delete it themselves.
|
||||
|
||||
## Section 3a — Git-ignored `deploy/` tree (added during implementation)
|
||||
|
||||
`/deploy/` is git-ignored, so the `git grep`-based scrub script (and its completeness gate) structurally could not reach it — a gap surfaced by code review. The `deploy/wonder-app-vd03/` production artifacts (`install.ps1`, `appsettings.Central.json`, `appsettings.Site.json`, `RUNBOOK.md`, `ldap/glauth.cfg`) still held old references that would break against the renamed binary: `SCADALINK_*` env vars, `ScadaLink__*` config keys, the `"ScadaLink"` config-section root, `ScadaLink.Host.exe` (now `ZB.MOM.WW.ScadaBridge.Host.exe`), `scadalink.exe` (CLI `AssemblyName` is `scadabridge`), and `akka.tcp://scadalink@…` seed URIs (the actor system name in code is `scadabridge`).
|
||||
|
||||
Per user decision, this tree was scrubbed by hand with the **same** substitution set, **including** the internal LDAP directory domain (`dc=scadalink,dc=local` → `dc=scadabridge,dc=local` and `@scadalink.local` → `@scadabridge.local`) applied in lockstep across both `appsettings` and `glauth.cfg` so LDAP login stays consistent. Because `deploy/` is git-ignored, these edits are **local-only / not committed** — they fix the on-disk artifacts for the next `wonder-app-vd03` deploy. Verified clean with `grep -rniI scadalink deploy/`.
|
||||
|
||||
## Section 4 — Runtime cutover
|
||||
|
||||
Hard cutover. After the scrub, rebuild the image and `docker compose up -d --force-recreate` on both clusters (`docker/`, `docker-env2/`) so the running containers read `SCADABRIDGE_*`. **No database rename or wipe** — database names were already migrated in the `2026-05-28` effort and are unchanged here. If no stack is currently running, the cutover applies on the next `bash docker/deploy.sh`.
|
||||
|
||||
## Section 5 — Commits
|
||||
|
||||
Two staged commits on the current branch, `git diff`-reviewed between them:
|
||||
|
||||
1. `refactor: scrub residual ScadaLink refs → ScadaBridge (env vars, config keys, assembly name, SQL login)` — the scrub + any build/test fixes.
|
||||
2. `docs: add folder/repo rename design doc` — this document.
|
||||
|
||||
The folder `mv` and the Gitea rename are not git commits.
|
||||
|
||||
## Section 6 — Risks & rollback
|
||||
|
||||
- **Missed env var** → silent config-read failure. Mitigated by the completeness-gate grep + build/test + redeploy smoke check.
|
||||
- **Folder move breaks editor/Claude session paths** — the concern that drove the `2026-05-28` "don't rename the folder" decision; accepted by the user this time.
|
||||
- **Gitea redirect** — Gitea auto-redirects the old repo URL after rename, so pushes do not hard-fail even before the remote is updated; `origin` is updated regardless.
|
||||
- **Rollback** — pre-scrub state is the last git commit (`git reset --hard`); folder moves reverse with `mv`.
|
||||
|
||||
## Section 7 — Verification
|
||||
|
||||
- `dotnet build ZB.MOM.WW.ScadaBridge.slnx` clean; unit tests green.
|
||||
- Completeness grep returns only the four carve-outs.
|
||||
- `git remote -v` shows `https://gitea.dohertylan.com/dohertj2/ScadaBridge.git`; `git ls-remote origin` / `git fetch` succeeds.
|
||||
- (If a stack is running) CLI smoke against the redeployed cluster.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Renaming the MS SQL databases, docker containers/network, or CLI config dir — already done in the `2026-05-28` effort.
|
||||
- Sister repos `~/Desktop/MxAccessGateway`, `~/Desktop/OtOpcUa`.
|
||||
- Deleting `~/Desktop/ScadaBridge-old` — left to the user.
|
||||
@@ -0,0 +1,349 @@
|
||||
# Folder + Repo Rename `scadalink-design` → `ScadaBridge` Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers-extended-cc:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Rename the repo folder `~/Desktop/scadalink-design` → `~/Desktop/ScadaBridge`, rename the Gitea repository `dohertj2/scadalink-design` → `dohertj2/ScadaBridge`, and scrub every residual `scadalink`/`ScadaLink` reference inside the repo to its `ScadaBridge` equivalent.
|
||||
|
||||
**Architecture:** A scripted, most-specific-first `sed` pass over git-tracked text files does the content scrub; the folder rename is a plain OS `mv` (git tracks contents, not the repo-root directory name); the Gitea rename is a user web-UI action followed by a local `origin` URL update. Migration records (the prior rename tooling/design and the DB-rename helper) are carved out so their before→after meaning survives. Hard env-var cutover, no DB changes.
|
||||
|
||||
**Tech Stack:** bash 3.2 (macOS), BSD `sed -i ''`, git, `git grep`, dotnet (`ZB.MOM.WW.ScadaBridge.slnx`), docker compose.
|
||||
|
||||
**Design doc:** `docs/plans/2026-05-31-folder-repo-rename-scadabridge-design.md`
|
||||
|
||||
> **CRITICAL — path change after Task 0:** Task 0 moves the repo. From Task 1 onward, the repo root is `/Users/dohertj2/Desktop/ScadaBridge` (NOT `scadalink-design`). Every command below `cd`s there.
|
||||
|
||||
---
|
||||
|
||||
### Task 0: Safety checkpoint, clear the collision, move the folder
|
||||
|
||||
**Classification:** standard
|
||||
**Estimated implement time:** ~3 min
|
||||
**Parallelizable with:** none
|
||||
|
||||
**Files:** (filesystem operations only — no file edits)
|
||||
- Move: `~/Desktop/ScadaBridge` → `~/Desktop/ScadaBridge-old`
|
||||
- Move: `~/Desktop/scadalink-design` → `~/Desktop/ScadaBridge`
|
||||
|
||||
**Step 1: Confirm the working tree is clean and record the branch**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/scadalink-design && git status --short && git branch --show-current
|
||||
```
|
||||
Expected: no output from `git status --short` (clean tree) and a branch name (e.g. `main`). If there is uncommitted work, STOP and ask the user whether to commit or stash before proceeding.
|
||||
|
||||
**Step 2: Verify both move endpoints are safe**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
ls -ld /Users/dohertj2/Desktop/ScadaBridge /Users/dohertj2/Desktop/ScadaBridge-old /Users/dohertj2/Desktop/scadalink-design 2>&1
|
||||
```
|
||||
Expected: `ScadaBridge` exists (the old non-git project), `scadalink-design` exists, and `ScadaBridge-old` does **not** exist (`No such file or directory`). If `ScadaBridge-old` already exists, STOP and ask the user for a different aside-name.
|
||||
|
||||
**Step 3: Move the existing ScadaBridge aside, then move the repo into place**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
mv /Users/dohertj2/Desktop/ScadaBridge /Users/dohertj2/Desktop/ScadaBridge-old
|
||||
mv /Users/dohertj2/Desktop/scadalink-design /Users/dohertj2/Desktop/ScadaBridge
|
||||
```
|
||||
Expected: no output (success).
|
||||
|
||||
**Step 4: Verify the move and that git still works in the new location**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && git status --short && git log --oneline -1
|
||||
```
|
||||
Expected: clean tree; the HEAD commit is the design-doc commit (`docs: add folder/repo rename design doc ...`). Confirms git history survived the folder move.
|
||||
|
||||
**Step 5: No commit** — filesystem moves are not git changes. Proceed to Task 1.
|
||||
|
||||
**Acceptance:** `~/Desktop/ScadaBridge` is the git repo (clean tree, intact history); `~/Desktop/ScadaBridge-old` holds the former non-git project; `~/Desktop/scadalink-design` no longer exists.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Create the scrub script
|
||||
|
||||
**Classification:** small
|
||||
**Estimated implement time:** ~3 min
|
||||
**Parallelizable with:** none
|
||||
|
||||
**Files:**
|
||||
- Create: `/Users/dohertj2/Desktop/ScadaBridge/tools/scrub-scadalink-refs.sh`
|
||||
|
||||
**Step 1: Write the script**
|
||||
|
||||
Create `tools/scrub-scadalink-refs.sh` with exactly this content:
|
||||
|
||||
```bash
|
||||
#!/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 two rename design docs.
|
||||
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)$'
|
||||
|
||||
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."
|
||||
```
|
||||
|
||||
**Step 2: Make it executable**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && chmod +x tools/scrub-scadalink-refs.sh
|
||||
```
|
||||
Expected: no output.
|
||||
|
||||
**Step 3: Dry-run preview (list candidate files WITHOUT editing)**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && git grep -liI 'scadalink' -- . | grep -Ev '^(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)$'
|
||||
```
|
||||
Expected: a list of ~27 tracked source/config/test/doc files (the same set surfaced in the design doc), and NONE of the five carve-outs. No binary files (e.g. `site_events.db`) appear. If a carve-out appears, the script's `EXCLUDES_RE` is wrong — fix before running.
|
||||
|
||||
**Step 4: No commit yet** — the script is committed together with the scrub in Task 4.
|
||||
|
||||
**Acceptance:** `tools/scrub-scadalink-refs.sh` exists, is executable, and the dry-run lists only the intended files.
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Run the scrub and pass the completeness gate
|
||||
|
||||
**Classification:** high-risk
|
||||
**Estimated implement time:** ~3 min
|
||||
**Parallelizable with:** none
|
||||
|
||||
**Files:** (the script edits ~27 tracked files in place; see Task 1 dry-run)
|
||||
|
||||
**Step 1: Run the scrub**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && bash tools/scrub-scadalink-refs.sh
|
||||
```
|
||||
Expected: `Scrubbing N file(s):` followed by the file list and `Done.`
|
||||
|
||||
**Step 2: Completeness gate — only the five carve-outs may still match**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && git grep -niI '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'
|
||||
```
|
||||
Expected: **no output** (zero hits outside the carve-outs). If any line prints, inspect it — it is either a new case variant the substitution list missed (add a rule and re-run) or a file that should have been carved out.
|
||||
|
||||
**Step 3: Sanity-check the new env-var names landed**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && git grep -nE 'SCADABRIDGE_CONFIG|ScadaBridge__|scadabridge_app|ZB\.MOM\.WW\.ScadaBridge\.Host\.exe' -- src/ deploy/ docker/ docker-env2/ | head
|
||||
```
|
||||
Expected: hits showing `SCADABRIDGE_CONFIG` in compose/Host, `ScadaBridge__` and `ZB.MOM.WW.ScadaBridge.Host.exe` in `deploy/wonder-app-vd03/install.ps1`.
|
||||
|
||||
**Step 4: Review the diff**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && git diff --stat
|
||||
```
|
||||
Expected: ~27 files changed, all content-only. Spot-check `git diff docker/docker-compose.yml src/ZB.MOM.WW.ScadaBridge.Host/Program.cs` shows clean `SCADALINK_` → `SCADABRIDGE_` swaps.
|
||||
|
||||
**Step 5: No commit yet** — commit after the build/test gate (Task 4).
|
||||
|
||||
**Acceptance:** completeness gate returns zero hits outside the five carve-outs; new names present in code/config; diff is content-only.
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Build, run unit tests, fix any stragglers
|
||||
|
||||
**Classification:** standard
|
||||
**Estimated implement time:** ~5 min
|
||||
**Parallelizable with:** none
|
||||
|
||||
**Files:** (no planned edits; only stragglers surfaced by the build, if any)
|
||||
|
||||
**Step 1: Restore + build the solution**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && dotnet build ZB.MOM.WW.ScadaBridge.slnx 2>&1 | tail -20
|
||||
```
|
||||
Expected: `Build succeeded` with 0 errors. The scrub only renamed env-var string literals, a method parameter (`scadaLinkVersion` → `scadaBridgeVersion`), comments, and docs — no type/namespace changes — so the build should be clean. If an error appears (e.g. a parameter referenced by name elsewhere), fix that single reference and rebuild.
|
||||
|
||||
**Step 2: Run the CLI + Transport + ConfigurationDatabase unit tests (the projects whose code changed)**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && dotnet test tests/ZB.MOM.WW.ScadaBridge.CLI.Tests/ tests/ZB.MOM.WW.ScadaBridge.Transport.Tests/ 2>&1 | tail -25
|
||||
```
|
||||
Expected: all tests pass. These projects assert on the env-var name string literals (`SCADABRIDGE_FORMAT`, `SCADABRIDGE_USERNAME`, …) and the `scadaBridgeVersion` parameter — they were scrubbed in lockstep with the code, so they stay consistent. If a test references an env var the code no longer sets (or vice-versa), reconcile the pair.
|
||||
|
||||
**Step 3: No commit yet** — commit in Task 4.
|
||||
|
||||
**Acceptance:** `dotnet build` clean; the changed projects' unit tests green.
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Commit the scrub
|
||||
|
||||
**Classification:** trivial
|
||||
**Estimated implement time:** ~1 min
|
||||
**Parallelizable with:** none
|
||||
|
||||
**Files:** (commit only)
|
||||
|
||||
**Step 1: Stage and commit**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && git add -A && git commit -m "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."
|
||||
```
|
||||
Expected: commit succeeds; `~28` files changed (the 27 scrubbed + the new script).
|
||||
|
||||
**Step 2: Verify**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && git log --oneline -2 && git status --short
|
||||
```
|
||||
Expected: the refactor commit on top of the design-doc commit; clean tree.
|
||||
|
||||
**Acceptance:** scrub committed; clean working tree.
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Update the local Git remote after the Gitea web-UI rename
|
||||
|
||||
**Classification:** small
|
||||
**Estimated implement time:** ~2 min
|
||||
**Parallelizable with:** Task 6
|
||||
|
||||
**Files:** (git remote config only)
|
||||
|
||||
**Step 1: Manual gate — user renames the repo in the Gitea web UI**
|
||||
|
||||
Ask the user to rename the repository at `https://gitea.dohertylan.com/dohertj2/scadalink-design` to `ScadaBridge` via **Settings → Repository Name**, and to confirm when done. Do NOT proceed until confirmed.
|
||||
|
||||
**Step 2: Point `origin` at the new URL**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && git remote set-url origin https://gitea.dohertylan.com/dohertj2/ScadaBridge.git && git remote -v
|
||||
```
|
||||
Expected: both fetch and push lines show `.../dohertj2/ScadaBridge.git`.
|
||||
|
||||
**Step 3: Verify the remote is reachable and refs match**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && git ls-remote origin HEAD
|
||||
```
|
||||
Expected: prints a commit SHA for `HEAD` (auth via macOS keychain succeeds). If it fails with not-found, the web-UI rename has not propagated — re-confirm with the user.
|
||||
|
||||
**Step 4: Push the new commits**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && git push origin HEAD
|
||||
```
|
||||
Expected: push succeeds; the design-doc + scrub commits land on the renamed remote.
|
||||
|
||||
**Acceptance:** `origin` points at `dohertj2/ScadaBridge`; `git ls-remote` and `git push` succeed.
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Runtime cutover — rebuild + redeploy so containers read the new env vars (conditional)
|
||||
|
||||
**Classification:** high-risk
|
||||
**Estimated implement time:** ~5 min
|
||||
**Parallelizable with:** Task 5
|
||||
|
||||
**Files:** (no edits — runtime only)
|
||||
|
||||
**Step 1: Check whether a stack is running**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
docker ps --format '{{.Names}}' | grep -E 'scadabridge|central|site' || echo "no stack running"
|
||||
```
|
||||
Expected: either a list of running containers, or `no stack running`. **If `no stack running`, SKIP this task** — the new env-var names apply automatically on the next `bash docker/deploy.sh`. Note this to the user and mark the task done.
|
||||
|
||||
**Step 2: Rebuild the image and recreate the primary cluster**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && bash docker/deploy.sh 2>&1 | tail -30
|
||||
```
|
||||
Expected: image rebuilds; containers recreated. (`deploy.sh` already force-recreates.) Containers now receive `SCADABRIDGE_*` from the scrubbed `docker/docker-compose.yml`.
|
||||
|
||||
**Step 3: Recreate the second cluster (if it was running)**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && bash docker-env2/deploy.sh 2>&1 | tail -30
|
||||
```
|
||||
Expected: env2 cluster recreated from the scrubbed `docker-env2/docker-compose.yml`.
|
||||
|
||||
**Step 4: Smoke-test readiness + CLI**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
sleep 20
|
||||
curl -s http://localhost:9000/health/ready && echo
|
||||
cd /Users/dohertj2/Desktop/ScadaBridge && dotnet run --project src/ZB.MOM.WW.ScadaBridge.CLI -- --username multi-role --password password template list 2>&1 | tail -15
|
||||
```
|
||||
Expected: `/health/ready` reports healthy; the CLI returns a template list (proves the Host read its config via the renamed `SCADABRIDGE_*` env vars). No DB rename/wipe is needed — database names are unchanged by this effort.
|
||||
|
||||
**Acceptance:** either the stack is confirmed not-running (skipped), or the redeployed cluster is healthy and the CLI smoke passes against the new env-var names.
|
||||
|
||||
---
|
||||
|
||||
## Execution Notes
|
||||
|
||||
- Tasks are strictly sequential 0 → 1 → 2 → 3 → 4, then 5 and 6 may run in parallel (both depend only on 4).
|
||||
- The completeness gate in Task 2 and the build/test gate in Task 3 are the safety net for a missed reference.
|
||||
- Rollback: `git reset --hard HEAD~1` (or `~2`) undoes the scrub commit; `mv` reverses the folder moves; `git remote set-url` reverts the remote.
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"planPath": "docs/plans/2026-05-31-folder-repo-rename-scadabridge-plan.md",
|
||||
"tasks": [
|
||||
{"id": 0, "subject": "Task 0: Safety checkpoint, clear collision, move folder", "status": "completed"},
|
||||
{"id": 1, "subject": "Task 1: Create the scrub script", "status": "completed", "blockedBy": [0]},
|
||||
{"id": 2, "subject": "Task 2: Run scrub + completeness gate", "status": "completed", "blockedBy": [1]},
|
||||
{"id": 3, "subject": "Task 3: Build, run unit tests, fix stragglers", "status": "completed", "blockedBy": [2]},
|
||||
{"id": 4, "subject": "Task 4: Commit the scrub", "status": "completed", "blockedBy": [3]},
|
||||
{"id": 5, "subject": "Task 5: Update local Git remote after Gitea web-UI rename", "status": "pending", "blockedBy": [4]},
|
||||
{"id": 6, "subject": "Task 6: Runtime cutover redeploy (conditional)", "status": "pending", "blockedBy": [4]}
|
||||
],
|
||||
"lastUpdated": "2026-06-01T01:59:34Z"
|
||||
}
|
||||
@@ -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
+45
@@ -0,0 +1,45 @@
|
||||
#!/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)"
|
||||
|
||||
# NOTE: this script only sees git-TRACKED files (via git grep). Git-ignored
|
||||
# trees — notably /deploy/ (see .gitignore) — are out of its reach and were
|
||||
# scrubbed separately, by hand, with the same substitution set. A git-based
|
||||
# completeness gate likewise cannot see them; verify those trees with a plain
|
||||
# `grep -rniI scadalink <dir>`.
|
||||
|
||||
# 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