Commit Graph

3 Commits

Author SHA1 Message Date
Joseph Doherty
a2b8b69281 fix(transport): NavMenu Admin-only visibility + BundleImportUnlockFailed audit + docker appsettings
- NavMenu: move Import Bundle out of the nested RequireDesign/RequireAdmin
  double-gate into the top-level Admin section so an Admin-only user sees it
  without needing the Design role; Export Bundle stays in the Design section.
- TransportImport: inject IAuditService + ScadaLinkDbContext; emit a
  BundleImportUnlockFailed audit row (best-effort, swallowed on failure) on
  every wrong-passphrase attempt in SubmitPassphraseAsync, with attempt
  number and error reason in afterState.
- docker central-node-a/b appsettings: add ScadaLink:Transport section with
  SourceEnvironment = "docker-cluster" so the importer picks up a non-null
  environment name in the audit trail.
- CentralUI.Tests: register IAuditService mock + SQLite in-memory
  ScadaLinkDbContext in TransportImportPageTests to satisfy the two new injects.
2026-05-24 05:59:04 -04:00
Joseph Doherty
acadb83712 feat(centralui): TransportImport wizard under Design nav group 2026-05-24 05:38:09 -04:00
Joseph Doherty
0dbc0c02f9 feat(centralui): TransportExport wizard under Design nav group
Implements Task T21 of the Transport feature. A four-step Blazor wizard
(Select → Review → Encrypt → Download) under /design/transport/export,
gated on AuthorizationPolicies.RequireDesign:

  1. Select  — TemplateFolderTree (checkbox-mode) plus flat checkbox
               lists for shared scripts, external systems, DB connections,
               notification lists, SMTP configs, API keys, API methods.
  2. Review  — runs DependencyResolver, surfaces seed vs auto-included.
               "Include all dependencies" toggle re-resolves on flip.
  3. Encrypt — passphrase + confirm with strength meter, secret-count
               warning over the resolved closure, explicit unencrypted
               opt-out path (calls BundleExporter with passphrase=null
               so the audit row tags UnencryptedBundleExport).
  4. Download— calls IBundleExporter.ExportAsync, streams bytes to the
               browser via JS interop (wwwroot/js/transport.js), displays
               filename + size + SHA-256 + encryption status.

Source environment is sourced from new TransportOptions.SourceEnvironment
(bound from ScadaLink:Transport:SourceEnvironment, defaults "scadalink"),
filename pattern scadabundle-{env}-{yyyy-MM-dd-HHmmss}.scadabundle.

Tests (bUnit + policy): step 1 group rendering, step 2 dependency
expansion (Pump composes Motor), step 4 full walkthrough verifying
ExportAsync receives the selected ids + authenticated identity, and a
RequireDesign policy-deny test for users without the Design role. Also
unit-pins the filename-sanitisation contract.
2026-05-24 05:30:16 -04:00