# Env2 + Transport Manual Verification Checklist

> **RETIRED 2026-08-01 — never run as written; superseded by automated suites + a live cross-environment run.**
> The step list below predates the M8 import-wizard Map step and was never annotated. Instead of
> refreshing ~48 stale steps, the core scenario this checklist exists for was run live on 2026-08-01
> (rig session, task #12): CLI `bundle export` from the primary cluster (encrypted, `--include-dependencies`,
> template closure + shared scripts + external system + site-a + instances) → `bundle preview` against the
> empty env2 (correct Map requirements surfaced) → `bundle import --create-missing-sites
> --create-missing-connections` into env2 → 20 entities added, secrets (`AuthConfiguration`) intact,
> instances landed `NotDeployed`, connection FK wired to the created site. **The run caught a real bug**
> (create-missing site id never materialised before the connection insert → FK 547 on real SQL Server,
> masked by the in-memory test provider) — fixed the same day with an SQLite regression test
> (`CreateMissingSiteRelationalTests`, commit `0c9dffed`). Env2 boot/PSK/LocalDb were separately proven
> PASS 3/3 by Gitea #31 (2026-07-23). Remaining coverage lives in
> `tests/ZB.MOM.WW.ScadaBridge.Transport.IntegrationTests` (RoundTrip/RoundTripEquivalence/
> ConflictResolution/ValidationFailure/SiteInstanceImport/CreateMissingSiteRelational). This checklist
> is retired — do not run or refresh it.

**Date created:** 2026-05-24
**Companion to:** [`2026-05-24-second-environment-design.md`](2026-05-24-second-environment-design.md), [`Component-Transport.md`](../requirements/Component-Transport.md)
**Goal:** Exercise the Transport (#24) bundle export/import flow against two real running environments (primary + env2).

## Prerequisites

- `infra/` services running: `cd infra && docker compose up -d`
- Primary stack running and healthy: `bash docker/deploy.sh && bash docker/seed-sites.sh`
- `scadabridge-mssql` reachable (`docker ps | grep scadabridge-mssql`)

## Step 0: Bring up env2

- [ ] `bash docker-env2/deploy.sh` completes without error
- [ ] `docker ps --format '{{.Names}}'` shows 5 new `scadabridge-env2-*` containers
- [ ] `curl -s http://localhost:9101/health/ready` returns 200 with `"status": "Healthy"`
- [ ] `curl -s http://localhost:9100/health/active` is routed through Traefik
- [ ] http://localhost:9100 loads the env2 login page in a browser
- [ ] Login as `multi-role` / `password` succeeds
- [ ] Env2 dashboard renders, Sites page is empty

## Step 1: Seed env2's test site

- [ ] `bash docker-env2/seed-sites.sh` completes without error
- [ ] Env2 UI → Sites page shows `site-x` (Env2 Site X)
- [ ] Within ~30s, site-x health turns green

## Step 2: Prepare bundle source on primary

- [ ] Primary UI (http://localhost:9000) → Design → Templates contains at least one template (create one if empty)
- [ ] Optional: prepare at least one shared script and one external system for fuller round-trip coverage

## Step 3: Export from primary

- [ ] Primary UI → Design → **Export Bundle**
- [ ] Selection step: tick at least one template (folder + items)
- [ ] Review step: confirm selected entity counts
- [ ] Encrypt step: set passphrase `test-passphrase-1`
- [ ] Download step: receive a `.scadabundle` file (note exact filename)
- [ ] Verify the manifest's `SourceEnvironment` field equals `docker-cluster` (peek inside the zip; `manifest.json` is plaintext)

## Step 4: Import into env2

- [ ] Env2 UI (http://localhost:9101) → Admin → **Import Bundle**
- [ ] Upload step: select the bundle file from Step 3
- [ ] Passphrase step: enter `test-passphrase-1` → diff loads successfully
- [ ] Diff step: all rows are "Create" (env2 was empty for these entities)
- [ ] Confirm step: import succeeds; result step shows the per-row outcome
- [ ] Env2 audit log row(s) are tagged with the bundle's `BundleImportId`

## Step 5: Verify imported artifacts in env2

- [ ] Env2 UI → Design → Templates shows the imported template(s)
- [ ] Env2 UI → Audit → Configuration Audit Log filtered by `BundleImportId` shows the import events
- [ ] (Optional) Deploy an imported template to env2's `site-x` to prove runtime validity

## Step 6: Conflict-resolution probe

- [ ] Re-upload the same `.scadabundle` to env2 with the same passphrase
- [ ] Diff step: all rows are now "Update"
- [ ] Pick mixed Skip / Overwrite / Rename per row; confirm
- [ ] Verify the chosen resolutions land correctly (Skip rows unchanged, Overwrite rows match the bundle, Rename rows present under the new name)

## Negative tests

- [ ] Wrong passphrase: try `wrong-passphrase` → friendly error, no diff loaded
- [ ] Wrong passphrase 3 times in one session → session lockout enforced (`MaxUnlockAttemptsPerSession`)
- [ ] Bump primary's `Transport.SchemaVersionMajor` to 99, export, attempt env2 import → schema-version mismatch error
- [ ] Tamper with `manifest.json` content hash (unzip → edit → re-zip) → content-hash mismatch error

## Round-trip parity

- [ ] Export the same templates from env2 (with `Transport.SourceEnvironment` = `docker-cluster-env2`)
- [ ] Re-import into primary with Skip-on-conflict for all rows
- [ ] Primary's audit log shows no actual mutations
- [ ] Primary's template revision hashes are unchanged after the no-op import

## Cleanup (optional)

- [ ] `bash docker-env2/teardown.sh` stops env2 containers
- [ ] Drop env2 databases if needed:
  ```bash
  docker exec scadabridge-mssql /opt/mssql-tools18/bin/sqlcmd \
      -S localhost -U sa -P 'ScadaBridge_Dev1#' -C \
      -Q "DROP DATABASE ScadaBridgeConfig2; DROP DATABASE ScadaBridgeMachineData2;"
  ```

## Pass criteria

All checkboxes ticked, no defects found, both stacks remain healthy after the run.
