refactor: rename ScadaLink → ZB.MOM.WW.ScadaBridge (code + projects + namespaces)

Solution + 23 src projects + 26 test projects renamed; folders, csproj,
namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated.
ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated.
SQL roles/logins, LDAP domains, CLI command name, and CLI config dir
(~/.scadalink → ~/.scadabridge) also renamed.

Build green; 5 Host.Tests fail awaiting SQL login rename in next commit.
Pre-existing StaleTagMonitor timing flakes unchanged.

Rename script committed at tools/rename-to-scadabridge.sh.
This commit is contained in:
Joseph Doherty
2026-05-28 09:37:45 -04:00
parent 6d87ee3c3b
commit 7b0b9c7365
1531 changed files with 11180 additions and 11054 deletions
+21 -21
View File
@@ -8,7 +8,7 @@
## 1. Purpose
Provide a file-based, encrypted, environment-agnostic way to **promote configuration artifacts from one ScadaLink cluster to another** (e.g., dev → staging → prod) through the Central UI.
Provide a file-based, encrypted, environment-agnostic way to **promote configuration artifacts from one ScadaBridge cluster to another** (e.g., dev → staging → prod) through the Central UI.
A user with the `Design` role on the source cluster exports a selected set of templates and supporting artifacts to a `.scadabundle` file. A user with the `Admin` role on the target cluster uploads the bundle, reviews a diff, resolves conflicts, and applies it. Import is **config-only**: it updates the central configuration database and marks affected instances stale; the user redeploys to sites via the existing Deployments page.
@@ -18,11 +18,11 @@ Transport does **not** touch site nodes, does not move runtime state, and does n
## 2. Location
- New project: `src/ScadaLink.Transport/`
- New tests: `tests/ScadaLink.Transport.Tests/`, `tests/ScadaLink.Transport.IntegrationTests/`
- New project: `src/ZB.MOM.WW.ScadaBridge.Transport/`
- New tests: `tests/ZB.MOM.WW.ScadaBridge.Transport.Tests/`, `tests/ZB.MOM.WW.ScadaBridge.Transport.IntegrationTests/`
- New design doc: `docs/requirements/Component-Transport.md` (created as part of implementation).
- Central UI pages: `src/ScadaLink.CentralUI/Components/Pages/Design/TransportExport.razor`, `TransportImport.razor`.
- EF migration in `src/ScadaLink.ConfigurationDatabase/Migrations/` (adds `BundleImportId` column to `ConfigurationAuditLog`).
- Central UI pages: `src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/TransportExport.razor`, `TransportImport.razor`.
- EF migration in `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Migrations/` (adds `BundleImportId` column to `ConfigurationAuditLog`).
---
@@ -123,7 +123,7 @@ The manifest is plaintext so the import wizard can preview bundle contents and s
## 5. Architecture (Option A — new component)
```
ScadaLink.Transport
ZB.MOM.WW.ScadaBridge.Transport
├── IBundleExporter
│ ExportAsync(ExportSelection, Passphrase?, ct) → Stream
├── IBundleImporter
@@ -137,8 +137,8 @@ ScadaLink.Transport
└── ManifestValidator (schema/version gating, hash check)
```
- Component is **central-only**. Registered in `ScadaLink.Host` for central roles, never for site roles.
- All persistence goes through **existing audited repository interfaces** in `ScadaLink.ConfigurationDatabase` — no raw `DbContext.SaveChangesAsync` from this component.
- Component is **central-only**. Registered in `ZB.MOM.WW.ScadaBridge.Host` for central roles, never for site roles.
- All persistence goes through **existing audited repository interfaces** in `ZB.MOM.WW.ScadaBridge.ConfigurationDatabase` — no raw `DbContext.SaveChangesAsync` from this component.
- `BundleSessionStore` is in-process on the active central node (matches Blazor Server circuit affinity). 30-minute TTL, GC on expiry, 3-strike passphrase lockout per session.
Rejected alternatives:
@@ -260,8 +260,8 @@ When an applied conflict overwrites a template (or a template composed by other
| Where | Failure | Surfaced as |
|---|---|---|
| Upload | Not a zip / missing `manifest.json` | Step 1 error: "Not a valid ScadaLink bundle" |
| Upload | `bundleFormatVersion` newer than supported | Step 1 error: "Bundle was created by ScadaLink v{x}; upgrade this cluster" |
| Upload | Not a zip / missing `manifest.json` | Step 1 error: "Not a valid ScadaBridge bundle" |
| Upload | `bundleFormatVersion` newer than supported | Step 1 error: "Bundle was created by ScadaBridge v{x}; upgrade this cluster" |
| Upload | Content hash mismatch | Step 1 error: "Bundle integrity check failed — file may be corrupt" |
| Unlock | Wrong passphrase | Step 2 error; 3rd wrong attempt invalidates session, audit `BundleImportUnlockFailed` |
| Preview | Bundle references shared script not in bundle and not in target DB | Listed as a blocker row in Step 3; cannot Apply until resolved |
@@ -281,7 +281,7 @@ Imports are **all-or-nothing per bundle.** A bundle either applies fully or not
- **Bundle size cap** on upload (default 100 MB, configurable) to bound memory.
- **In-transit:** existing HTTPS to Central UI; no new channel.
- **Audit trail is the chain of custody.** Every export, every import (including aborted ones at validation), every unlock failure is audit-logged with source env, content hash, encrypted yes/no, and artifact summary.
- **Defense in depth on authorization:** `RequireDesign` (export) and `RequireAdmin` (import) enforced both on the Razor page and inside `ScadaLink.Transport` service entrypoints. UI is not the only gate.
- **Defense in depth on authorization:** `RequireDesign` (export) and `RequireAdmin` (import) enforced both on the Razor page and inside `ZB.MOM.WW.ScadaBridge.Transport` service entrypoints. UI is not the only gate.
- **Bundles are not retained server-side** after download (export) or after `ApplyAsync` commits (import).
---
@@ -334,16 +334,16 @@ Import flows through the **same audited repository methods** the UI and CLI use,
## 13. CLI (Deferred)
The `ScadaLink.Transport` library is callable from both Razor pages and `ScadaLink.CLI`. CLI commands are **not** built in v1 but the design leaves a clean path:
The `ZB.MOM.WW.ScadaBridge.Transport` library is callable from both Razor pages and `ZB.MOM.WW.ScadaBridge.CLI`. CLI commands are **not** built in v1 but the design leaves a clean path:
```
scadalink transport export \
scadabridge transport export \
--templates Pump,Pump.WaterPump \
--shared-scripts PumpUtils \
--out bundle.scadabundle \
--passphrase-file /run/secrets/p
scadalink transport import bundle.scadabundle \
scadabridge transport import bundle.scadabundle \
--passphrase-file /run/secrets/p \
--on-conflict overwrite|skip|rename \
--dry-run
@@ -357,16 +357,16 @@ Same auth model via the Management API.
| Layer | Project | Coverage |
|---|---|---|
| Unit | `tests/ScadaLink.Transport.Tests` (new) | `BundleSerializer` round-trip, `DependencyResolver` topology + cycle handling, `SecretEncryptor` (encrypt → decrypt round-trip, wrong passphrase fails, tampered ciphertext fails GCM auth tag), `ManifestBuilder` schema-version gating, `ImportPreview` diff for each entity type (identical / modified / new), per-conflict resolution merge logic, stale-instance cascade through composed templates |
| Integration | `tests/ScadaLink.Transport.IntegrationTests` (new) | End-to-end against in-memory + real SQL Server: export → import on same DB (no-op idempotency), export → wipe → import (full restore), export → modify-target → import under each conflict resolution, validation failure rolls back cleanly, audit rows correlated by `BundleImportId` |
| UI | `tests/ScadaLink.CentralUI.Tests` | Razor page authorization (`RequireDesign` for export, `RequireAdmin` for import), wizard step navigation, session TTL expiry, tri-state checkbox tree behavior |
| Unit | `tests/ZB.MOM.WW.ScadaBridge.Transport.Tests` (new) | `BundleSerializer` round-trip, `DependencyResolver` topology + cycle handling, `SecretEncryptor` (encrypt → decrypt round-trip, wrong passphrase fails, tampered ciphertext fails GCM auth tag), `ManifestBuilder` schema-version gating, `ImportPreview` diff for each entity type (identical / modified / new), per-conflict resolution merge logic, stale-instance cascade through composed templates |
| Integration | `tests/ZB.MOM.WW.ScadaBridge.Transport.IntegrationTests` (new) | End-to-end against in-memory + real SQL Server: export → import on same DB (no-op idempotency), export → wipe → import (full restore), export → modify-target → import under each conflict resolution, validation failure rolls back cleanly, audit rows correlated by `BundleImportId` |
| UI | `tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests` | Razor page authorization (`RequireDesign` for export, `RequireAdmin` for import), wizard step navigation, session TTL expiry, tri-state checkbox tree behavior |
| Manual | docker cluster | Cross-cluster: bring up two clusters, export from one, import to the other, verify stale instances surface on Deployments page, redeploy works |
---
## 15. Deployment
- New component registered in `ScadaLink.Host` for central roles only.
- New component registered in `ZB.MOM.WW.ScadaBridge.Host` for central roles only.
- No new ports, no new database (uses existing central MS SQL).
- One EF migration: `BundleImportId` nullable `uniqueidentifier` column on `ConfigurationAuditLog` + supporting index.
- `bash docker/deploy.sh` picks up the change with the standard rebuild + restart — no compose changes.
@@ -398,9 +398,9 @@ Same auth model via the Management API.
## 18. Open Questions / Future Work
- **Site-scoped artifact transport** (Instances, Areas, bindings, DataConnections). Requires a name-mapping subsystem (source-env-site → target-env-site). Deferred until concrete demand.
- **Direct cluster-to-cluster pull** as an alternative to file handoff. Same `ScadaLink.Transport` library can back it; needs cross-env auth design.
- **Direct cluster-to-cluster pull** as an alternative to file handoff. Same `ZB.MOM.WW.ScadaBridge.Transport` library can back it; needs cross-env auth design.
- **Bundle signing** with an asymmetric keypair (separate from passphrase encryption) for stronger non-repudiation. Manifest content hash is sufficient for v1 tamper detection.
- **CLI commands** (`scadalink transport export/import`). Shape pre-decided in §13; not built in v1.
- **CLI commands** (`scadabridge transport export/import`). Shape pre-decided in §13; not built in v1.
- **Differential bundles** ("only what changed since last export"). YAGNI for v1.
---
@@ -420,4 +420,4 @@ Same auth model via the Management API.
| Post-import behavior | Config-only; user redeploys via existing Deployments page |
| Authorization | `Design` to export, `Admin` to import |
| Audit | Per-entity rows via existing audited repositories, correlated by `BundleImportId` |
| Architecture | New component `ScadaLink.Transport` (Option A) |
| Architecture | New component `ZB.MOM.WW.ScadaBridge.Transport` (Option A) |