Add data-path ACL design (acl-design.md, closes corrections B1) + dev-environment inventory and setup plan (dev-environment.md), and remove consumer cutover from OtOpcUa v2 scope.

ACL design defines NodePermissions bitmask flags covering Browse / Read / Subscribe / HistoryRead / WriteOperate / WriteTune / WriteConfigure / AlarmRead / AlarmAcknowledge / AlarmConfirm / AlarmShelve / MethodCall plus common bundles (ReadOnly / Operator / Engineer / Admin); 6-level scope hierarchy (Cluster / Namespace / UnsArea / UnsLine / Equipment / Tag) with default-deny + additive grants and Browse-implication on ancestors; per-LDAP-group grants in a new generation-versioned NodeAcl table edited via the same draft → diff → publish → rollback boundary as every other content table; per-session permission-trie evaluator with O(depth × group-count) cost cached for the lifetime of the session and rebuilt on generation-apply or LDAP group cache expiry; cluster-create workflow seeds a default ACL set matching the v1 LmxOpcUa LDAP-role-to-permission map for v1 → v2 consumer migration parity; Admin UI ACL tab with two views (by LDAP group, by scope), bulk-grant flow, and permission simulator that lets operators preview "as user X" effective permissions across the cluster's UNS tree before publishing; explicit Deny deferred to v2.1 since verbose grants suffice at v2.0 fleet sizes; only denied OPC UA operations are audit-logged (not allowed ones — would dwarf the audit log). Schema doc gains the NodeAcl table with cross-cluster invariant enforcement and same-generation FK validation; admin-ui.md gains the ACLs tab; phase-1 doc gains Task E.9 wiring this through Stream E plus a NodeAcl entry in Task B.1's DbContext list.

Dev-environment doc inventories every external resource the v2 build needs across two tiers per decision #99 — inner-loop (in-process simulators on developer machines: SQL Server local or container, GLAuth at C:\publish\glauth\, local dev Galaxy) and integration (one dedicated Windows host with Docker Desktop on WSL2 backend so TwinCAT XAR VM can run in Hyper-V alongside containerized oitc/modbus-server, plus WSL2-hosted Snap7 and ab_server, plus OPC Foundation reference server, plus FOCAS TestStub and FaultShim) — with concrete container images, ports, default dev credentials (clearly marked dev-only since production uses Integrated Security / gMSA per decision #46), bootstrap order for both tiers, network topology diagram, test data seed locations, and operational risks (TwinCAT trial expiry automation, Docker pricing, integration host SPOF mitigation, per-developer GLAuth config sync, Aveva license scoping that keeps Galaxy tests on developer machines and off the shared host).

Removes consumer cutover (ScadaBridge / Ignition / System Platform IO) from OtOpcUa v2 scope per decision #136 — owned by a separate integration / operations team, tracked in 3-year-plan handoff §"Rollout Posture" and corrections §C5; OtOpcUa team's scope ends at Phase 5. Updates implementation/overview.md phase index to drop the "6+" row and add an explicit "OUT of v2 scope" callout; updates phase-1 and phase-2 docs to reframe cutover as integration-team-owned rather than future-phase numbered.

Decisions #129–137 added: ACL model (#129), NodeAcl generation-versioned (#130), v1-compatibility seed (#131), denied-only audit logging (#132), two-tier dev environment (#133), Docker WSL2 backend for TwinCAT VM coexistence (#134), TwinCAT VM centrally managed / Galaxy on dev machines only (#135), cutover out of v2 scope (#136), dev credentials documented openly (#137).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-04-17 11:58:33 -04:00
parent 2a6c9828e4
commit 4903a19ec9
8 changed files with 735 additions and 7 deletions

View File

@@ -177,4 +177,5 @@ The implementation **deviates from the plan** when any of those conditions fails
| 3 | (Phase 3: Modbus TCP driver — TBD) | NOT STARTED |
| 4 | (Phase 4: PLC drivers AB CIP / AB Legacy / S7 / TwinCAT — TBD) | NOT STARTED |
| 5 | (Phase 5: Specialty drivers FOCAS / OPC UA Client — TBD) | NOT STARTED |
| 6+ | (Phases 68: tier 1/2/3 consumer cutover — separate planning track per corrections doc C5) | NOT SCOPED |
**Consumer cutover (ScadaBridge / Ignition / System Platform IO) is OUT of v2 scope.** It is a separate work track owned by the integration / operations team, tracked in the 3-year-plan handoff (`handoffs/otopcua-handoff.md` §"Rollout Posture") and the corrections doc (§C5). The OtOpcUa team's responsibility ends at Phase 5 (all drivers built, all stability protections in place, full Admin UI shipped). Cutover sequencing, validation methodology, rollback procedures, and Aveva-pattern validation for tier 3 are the integration team's deliverables.

View File

@@ -40,7 +40,7 @@ Stand up the **central configuration substrate** for the v2 fleet:
| OPC UA wire behavior | Galaxy address space still served exactly as v1; the Configuration substrate is read but not yet driving everything |
| Equipment-class template integration with future schemas repo | `EquipmentClassRef` is a nullable hook column; no validation yet (decisions #112, #115) |
| Per-driver custom config editors in Admin | Generic JSON editor only in v2.0 (decision #27); driver-specific editors land in their respective phases |
| Consumer cutover (ScadaBridge / Ignition / SystemPlatform IO) | Phases 68 |
| Consumer cutover (ScadaBridge / Ignition / SystemPlatform IO) | OUT of v2 scope — separate integration-team track per `implementation/overview.md` |
## Entry Gate Checklist
@@ -139,6 +139,7 @@ Implement DbContext with entities matching `config-db-schema.md` exactly:
- `UnsArea`, `UnsLine`
- `ConfigGeneration`
- `DriverInstance`, `Device`, `Equipment`, `Tag`, `PollGroup`
- `NodeAcl` (generation-versioned per decision #130; data-path authorization grants per `acl-design.md`)
- `ClusterNodeGenerationState`, `ConfigAuditLog`
- `ExternalIdReservation` (NOT generation-versioned per decision #124)
@@ -443,6 +444,24 @@ Per `admin-ui.md` §"Release an external-ID reservation" and §"Merge or rebind
- After release: same `(Kind, Value)` can be reserved by a different EquipmentUuid in a future publish
- Merge equipment A → B: draft preview shows tag re-pointing + ID re-reservation; publish executes atomically; A is disabled with `EquipmentMergedAway` audit entry
#### Task E.9 — ACLs tab + bulk-grant + permission simulator
Per `admin-ui.md` Cluster Detail tab #8 ("ACLs") and `acl-design.md` §"Admin UI":
- ACLs tab on Cluster Detail with two views ("By LDAP group" + "By scope")
- Edit grant flow: pick scope, group, permission bundle or per-flag, save to draft
- Bulk-grant flow: multi-select scope, group, permissions, preview rows that will be created, publish via draft
- Permission simulator: enter username + LDAP groups → live trie of effective permissions across the cluster's UNS tree
- Cluster-create workflow seeds the v1-compatibility default ACL set (per decision #131)
- Banner on Cluster Detail when the cluster's ACL set diverges from the seed
**Acceptance**:
- Add an ACL grant via draft → publishes → row in `NodeAcl` table; appears in both Admin views
- Bulk grant 10 LDAP groups × 1 permission set across 5 UnsAreas → preview shows 50 rows; publish creates them atomically
- Simulator: a user in `OtOpcUaReadOnly` group sees `ReadOnly` bundle effective at every node in the cluster
- Simulator: a user in `OtOpcUaWriteTune` sees `Engineer` bundle effective; `WriteConfigure` is denied
- Cluster-create workflow seeds 5 default ACL grants matching v1 LDAP roles (table in `acl-design.md` §"Default Permissions")
- Divergence banner appears when an operator removes any of the seeded grants
## Compliance Checks (run at exit gate)
A `phase-1-compliance.ps1` script that exits non-zero on any failure:
@@ -599,8 +618,8 @@ The exit gate signs off only when **every** item below is checked. Each item lin
- Any Modbus / AB / S7 / TwinCAT / FOCAS driver code (Phases 35)
- Per-driver custom config editors in Admin (each driver's phase)
- Equipment-class template integration with the schemas repo
- Consumer cutover (Phases 68, separate planning track)
- ACL / namespace-level authorization for OPC UA clients (corrections doc B1 — needs scoping before Phase 6, parallel work track)
- Consumer cutover (out of v2 scope, separate integration-team track per `implementation/overview.md`)
- Wiring the OPC UA NodeManager to enforce ACLs at runtime (Phase 2+ in each driver phase). Phase 1 ships the `NodeAcl` table + Admin UI ACL editing + evaluator unit tests; per-driver enforcement lands in each driver's phase per `acl-design.md` §"Implementation Plan"
- Push-from-DB notification (decision #96 — v2.1)
- Generation pruning operator UI (decision #93 — v2.1)
- Cluster-scoped admin grant editor in UI (admin-ui.md "Deferred / Out of Scope" — v2.1)

View File

@@ -501,5 +501,5 @@ foreach ($p in $protections) {
- Equipment-class template integration with the schemas repo (Galaxy doesn't use `EquipmentClassRef`)
- Push-from-DB notification (decision #96 — v2.1)
- Any change to OPC UA wire behavior visible to clients (parity is the gate)
- ScadaBridge cutover (Phase 6 — separate planning track)
- Consumer cutover (ScadaBridge, Ignition, System Platform IO) — out of v2 scope, separate integration-team track per `implementation/overview.md`
- Removing the v1 deployment from production (a v2 release decision, not Phase 2)