diff --git a/docs/plans/2026-05-24-second-environment-verification.md b/docs/plans/2026-05-24-second-environment-verification.md new file mode 100644 index 0000000..e3f8576 --- /dev/null +++ b/docs/plans/2026-05-24-second-environment-verification.md @@ -0,0 +1,91 @@ +# Env2 + Transport Manual Verification Checklist + +**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` +- `scadalink-mssql` reachable (`docker ps | grep scadalink-mssql`) + +## Step 0: Bring up env2 + +- [ ] `bash docker-env2/deploy.sh` completes without error +- [ ] `docker ps --format '{{.Names}}'` shows 5 new `scadalink-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 scadalink-mssql /opt/mssql-tools18/bin/sqlcmd \ + -S localhost -U sa -P 'ScadaLink_Dev1#' -C \ + -Q "DROP DATABASE ScadaLinkConfig2; DROP DATABASE ScadaLinkMachineData2;" + ``` + +## Pass criteria + +All checkboxes ticked, no defects found, both stacks remain healthy after the run.