Commit Graph

207 Commits

Author SHA1 Message Date
Joseph Doherty 98b27fc1b6 fix(code-review): resolve Batch 1 open findings (AdminUI auth, AlarmHistorian dispose guards, docs)
- AdminUI-001: gate Script editor pages at Administrator,Designer + loosen ScriptAnalysis backend to match
- AdminUI-004: explicit [Authorize] on FleetStatus/Alert/ScriptLog hubs
- Core.AlarmHistorian-014: ObjectDisposedException guards on GetStatus/RetryDeadLettered (+ regression test)
- Core.Scripting.Abstractions-004/-007: Deadband tolerance doc + stale ScriptedAlarms.md path
- Host-003: correct config-overlay precedence in ServiceHosting.md
- Configuration-014: LdapGroupRoleMapping collation-dependency doc
- Driver.TwinCAT.Contracts-002: Structure enum doc (discovery-only sentinel)
2026-06-20 22:30:33 -04:00
Joseph Doherty 6b4210cb17 review(Core.AlarmHistorian): reset drain state on cancel + volatile _disposed
Re-review at 7286d320. -012 (Medium): OperationCanceledException left _drainState stuck
at Draining on the status surface; now resets to BackingOff + test. -013: _disposed ->
volatile (mirrors _backoffIndex). -014 (post-dispose status guards) deferred cross-module.
2026-06-19 11:21:35 -04:00
Joseph Doherty 48af117bff review(Core.VirtualTags): fix Good-null upstream blocking downstream (Medium)
Re-review at 7286d320. -014 (Medium): AreInputsReady gated on value!=null, so a script
returning null (Good quality) permanently blocked change-triggered dependents at
BadWaitingForInitialData; now gates on the StatusCode Good bit only + test. -015:
TimerTriggerScheduler.Start throws on double-call. -016: fix wrong status-code comment.
2026-06-19 11:21:35 -04:00
Joseph Doherty 272a9da61e review(Core.ScriptedAlarms): stop shelving timer on failed reload + drop dead branch
Re-review at 7286d320. -015: dispose shelving timer at top of LoadAsync so a failed
reload doesn't leave it firing against partially-cleared state + test. -014: make
pendingEmissions required (removes unreachable fire-under-gate branch that could
reintroduce the -003 deadlock).
2026-06-19 11:21:35 -04:00
Joseph Doherty c3d148e396 review(Configuration): fix LiteDB global BsonMapper cross-instance race (High)
Re-review at 7286d320. Configuration-012 (High): LiteDbConfigCache/GenerationSealedCache built
LiteDatabase on the process-wide BsonMapper.Global whose lazy member resolution races across
concurrently-constructed DBs (NotSupportedException/duplicate-key under contention; also caused
intermittent suite flakiness). Fix: per-cache fresh BsonMapper + pre-registered entity + TDD.
-013 (dead ValidateClusterTopology, ControlPlane) / -014 (collation case-sensitivity, needs
migration) deferred. No migration touched.
2026-06-19 11:06:56 -04:00
Joseph Doherty 145b06bec9 review(Core.Scripting.Abstractions): refresh stale Phase7 labels + document {{equip}}
First review at 7286d320. Five Low doc fixes (BadNodeIdUnknown comment parity, three stale
Phase7 labels -> design-doc cites, {{equip}} token doc on GetTag/SetVirtualTag). Deadband
NaN/negative-tolerance (004) + a stale docs path (007) left Open.
2026-06-19 11:06:56 -04:00
Joseph Doherty 38c48a009c review(Core.Scripting): block Unsafe.As sandbox bypass (Security)
Re-review at 7286d320. Core.Scripting-017 (Medium, Security): System.Runtime.CompilerServices.Unsafe
added to ForbiddenFullTypeNames (Unsafe.As bypasses the type system without an unsafe context;
CWE-843 type-confusion into SetVirtualTag) + regression tests (rejects Unsafe.As, still allows
benign CompilerServices attributes). -018: refresh stale rejection message. Sandbox holds.
2026-06-19 11:06:56 -04:00
Joseph Doherty 65e6af6001 review(Core.Abstractions): document ReadEventsAsync continuation contract (OpcUaServer-002 root)
Re-review at 7286d320. Core.Abstractions-009: ReadEventsAsync maxEvents<=0 sentinel now
documents the implementer's continuation-point obligation when a backend cap truncates
(the root of OpcUaServer-002). -010: PollGroupEngineTests pass CancellationToken. Plus
EquipmentTagRefResolver.TryResolve [MaybeNullWhen(false)] NRT cleanup + test.
2026-06-19 11:06:56 -04:00
Joseph Doherty 354b0e7613 review(Core): re-review at HEAD; clean up duplicate/unexplained doc comments
Re-review at 7286d320. Core-013 (duplicate <summary> on HostBoundHandle), Core-014
(clarify EquipmentNodeWalker test-only hardcoded attrs). Both Low, doc-only. Prior
authz/Galaxy churn verified correct.
2026-06-19 11:06:56 -04:00
Joseph Doherty b1946194d6 review(Cluster): record findings + fix snapshot consistency, dispose, stale docs
Code review at HEAD 7286d320. Cluster-001 (SeedFromCurrentState reads from one
snapshot), Cluster-003 (HoconLoader double-dispose), Cluster-004 (stale akka.conf
header), Cluster-005 (ServiceLevelCalculator tests added to Cluster.Tests). Cluster-002
deferred (no production caller).
2026-06-19 10:22:59 -04:00
Joseph Doherty 6dc74289ce review(Commons): record findings + add deferred-sink/equip-nodeid tests, fix stale Phase7 doc
Code review at HEAD 7286d320. Commons-001 (stale Phase7 telemetry doc) fixed;
Commons-003/004 close test-coverage gaps (DeferredAddressSpaceSink/ServiceLevelPublisher
forwarding seam + EquipmentNodeIds whitespace branch). Commons-002 (CorrelationId
typing) deferred as cross-cutting.
2026-06-19 10:22:59 -04:00
Joseph Doherty fb094fa566 feat(opcua): FB-7 surgical DataType/array-shape in-place tag writes
Widen the F10b surgical address-space path so a changed equipment tag whose
only differences are DataType / IsArray / ArrayLength (on top of the existing
Writable / Historizing) is applied IN PLACE on the live node instead of forcing
a full RebuildAddressSpace that drops every client's subscriptions server-wide.

ISurgicalAddressSpaceSink.UpdateTagAttributes gains (dataType, isArray,
arrayLength); the DeferredAddressSpaceSink wrapper forwards all six args (the
prod-inertness seam). OtOpcUaNodeManager swaps DataType + ValueRank +
ArrayDimensions in place, and on a real shape change (a) resets the node to
BadWaitingForInitialData so no stale wrong-typed value is exposed (closes the
prior brief-value-type-mismatch objection) and (b) raises a Part 3
GeneralModelChangeEvent (verb=DataTypeChanged) so model-aware clients re-read
the definition. A Writable/Historizing-only change leaves the shape untouched
(no reset, no model event) — original behaviour preserved byte-for-byte.

AddressSpaceApplier.TagDeltaIsSurgicalEligible adds the three shape fields to
its whitelist; FullName/Name/DriverInstanceId/alarm differences still rebuild.

Tests: new NodeManagerSurgicalShapeUpdateTests boots a real server to prove the
in-place swap + value reset + the no-reset backward-compat path + the model-event
builder; AddressSpaceApplierTests invert the two former DataType/IsArray-rebuild
cases to surgical and assert the shape args land; DeferredAddressSpaceSinkTests
assert the shape args forward. 273/273 OpcUaServer.Tests green; full solution builds.
2026-06-19 03:21:03 -04:00
Joseph Doherty 40e8a23e7c refactor(opcuaserver): rename Phase7* address-space pipeline to AddressSpace*
v2-ci / build (push) Failing after 37s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
The OPC UA address-space build pipeline was named after a v2-roadmap
milestone number rather than its domain. Rename the family to describe
what it does (build/diff/apply the OPC UA address space):

  Phase7Composer          -> AddressSpaceComposer
  Phase7CompositionResult -> AddressSpaceComposition
  Phase7Planner           -> AddressSpacePlanner
  Phase7Plan              -> AddressSpacePlan
  Phase7Applier           -> AddressSpaceApplier
  Phase7ApplyOutcome      -> AddressSpaceApplyOutcome

The 9 Phase7*Tests suites follow suit; Phase7ScriptingEntitiesTests ->
ScriptingEntitiesTests (it tests the scripting migration, not the
pipeline). Log-message prefixes move to the new class names.

Pure mechanical rename, no behavioral change. EF migration classes/IDs
(AddPhase7ScriptingTables, ExtendComputeGenerationDiffWithPhase7) are
immutable and left untouched, as are historical design docs.

Build clean; OpcUaServer 261/261, Runtime 272/272, ScriptingEntities
12/12 green.
2026-06-18 19:16:28 -04:00
Joseph Doherty 22b0611fb9 fix(opcua): forward ISurgicalAddressSpaceSink through DeferredAddressSpaceSink (F10b surgical path was inert in prod) 2026-06-18 13:57:53 -04:00
Joseph Doherty 3fc258bd42 feat(opcua): add ISurgicalAddressSpaceSink + node-manager in-place tag-attribute update (F10b) 2026-06-18 13:32:53 -04:00
Joseph Doherty 68637396b5 docs(abstractions): correct ReadEventsAsync remark — OpcUaClient now overrides
Code-review minor: the DIM remark said the OPC UA Client driver stays with the
default; it now overrides (forwards HistoryReadEvents upstream). Comment-only —
no contract/signature change. The session-capture-before-gate race the review
also noted is a pre-existing ExecuteHistoryReadAsync pattern (shared by
raw/processed/attime); ReadEventsAsync intentionally mirrors it — tracked as a
follow-up to fix all four history paths together.
2026-06-18 06:11:31 -04:00
Joseph Doherty a792820283 feat(opcua): EnsureVariable array params (ValueRank=OneDimension + ArrayDimensions) 2026-06-16 21:16:07 -04:00
Joseph Doherty a40c77de87 fix(adminui): flip remaining ModbusTcp test seeds + doc comments to Modbus (review) 2026-06-16 19:51:56 -04:00
Joseph Doherty 069a5f3165 feat(adminui): Galaxy picker pre-fills native-alarm fields from IsAlarm 2026-06-16 16:55:05 -04:00
Joseph Doherty fcb3801415 fix(historian): dead-letter poison events after maxAttempts (finding 002) 2026-06-16 05:25:43 -04:00
Joseph Doherty be6858baa1 fix(alarms): OnEnableDisable native-check via lock-guarded IsNativeAlarmNode + unstale AlarmCommand doc (code-review) 2026-06-15 14:30:17 -04:00
Joseph Doherty 418663b359 feat(alarms): thread isNative through MaterialiseAlarmCondition; node manager tracks native conditions [H6a] 2026-06-15 14:13:30 -04:00
Joseph Doherty ed941c51da feat(alarms): AlarmAcknowledgeRequest carries OperatorUser; Galaxy/ScriptedAlarmSource honor it [H6b] 2026-06-15 14:11:40 -04:00
Joseph Doherty c236263e8d fix(authz): give HistoryUpdate its own NodePermissions bit (was aliased to HistoryRead) [H2] 2026-06-15 14:09:35 -04:00
Joseph Doherty ff0f62db38 refactor(redundancy): move ServiceLevelCalculator to Core.Cluster (shared, Runtime-reachable) 2026-06-15 12:45:17 -04:00
Joseph Doherty a9d267c91a docs(security,core): correct stale write-outcome doc + note benign DraftSnapshot/LeaderChanged residue (stillpending §9/§3) 2026-06-15 09:48:14 -04:00
Joseph Doherty b4af9e7f37 docs(comments): correct 7 stale 'later task/milestone' comments (stillpending §9) 2026-06-15 09:47:08 -04:00
Joseph Doherty 13fba8f8fb feat(historian): HistoryRead override (Raw/Processed/AtTime) over IHistorianDataSource 2026-06-14 19:31:39 -04:00
Joseph Doherty 6041dc202b feat(historian): materialise historized vars with Historizing + HistoryRead bit + NodeId->tagname map 2026-06-14 19:09:32 -04:00
Joseph Doherty f44d8d1e6b feat(alarms): carry transition Kind on AlarmEventArgs; Galaxy populates it (Phase B WS-1) 2026-06-14 03:04:44 -04:00
Joseph Doherty 0f7c47a559 feat(commons): IOpcUaNodeWriteGateway + NodeWriteOutcome for write-outcome routing 2026-06-14 01:20:14 -04:00
Joseph Doherty a23fb2b82e feat(server): equipment-tag node writability from Tag.AccessLevel (parity-safe, no migration) 2026-06-13 11:46:00 -04:00
Joseph Doherty eaa335d779 feat(drivers): shared EquipmentTagRefResolver (by-name + parse-on-miss + cache) 2026-06-13 11:07:23 -04:00
Joseph Doherty 26816fd17e feat(commons): EquipmentNodeIds — single source of truth for folder-scoped equipment NodeIds 2026-06-13 06:26:59 -04:00
Joseph Doherty b8277922b6 fix(config): also clean NodeAcl + release ExternalIdReservation in SystemPlatform cleanup migration 2026-06-12 22:34:13 -04:00
Joseph Doherty 7d25480fee docs(galaxy): neutralize remaining stale SystemPlatform/alias terminology in comments + a test name
Replace "SystemPlatform mirror tag", "Galaxy alias", and "SystemPlatform-kind" in doc-comments and
test names with neutral accurate wording ("FolderPath-scoped tag", "EquipmentId == null", etc.).
No code, logic, or test bodies changed — comments and one test method name only.
2026-06-12 22:30:50 -04:00
Joseph Doherty ba42bed538 feat(config): forward-only migration deleting orphaned SystemPlatform namespace data (clean break) 2026-06-12 22:25:00 -04:00
Joseph Doherty dcbaf63ab1 feat(config): remove the SystemPlatform NamespaceKind (capstone) — Galaxy is Equipment-kind 2026-06-12 22:18:56 -04:00
Joseph Doherty 5edea52bd7 docs(galaxy): fix stale SystemPlatform/alias/Galaxy doc comments (review follow-up)
Resolves the code-review notes on 95be607a + the AdminUI bundle: the
EnsureVariable docs (IOpcUaAddressSpaceSink, OtOpcUaNodeManager) and the Tag
entity doc no longer say 'Galaxy / SystemPlatform / alias'; the DriverHostActor
ForwardToMux comment now states the real equipment-tag value-routing gap (the
FullName→NodeId 'live values' milestone) instead of claiming Galaxy values map
straight through.
2026-06-12 22:00:52 -04:00
Joseph Doherty b4b7cd7d0f feat(authz): remove SystemPlatform scope + permission-trie walk (Galaxy resolves via Equipment) 2026-06-12 21:54:28 -04:00
Joseph Doherty 499c9b9165 feat(validation): allow GalaxyMxGateway under Equipment; rename Galaxy-tag FullName check 2026-06-12 21:11:06 -04:00
Joseph Doherty 57355405a6 chore(security): drop dead audit suppressions; patch OpenTelemetry + Tmds.DBus CVEs
All five suppressed advisories are now resolved at baseline/resolved versions,
so every NuGetAuditSuppress is removed repo-wide:
- System.Security.Cryptography.Xml (GHSA-37gx-xxp4-5rgx / GHSA-w3x6-4m5h-cxqf)
  -> fixed by the .NET 10 baseline (10.0.6)
- OPCFoundation Opc.Ua.Core (GHSA-h958-fxgg-g7w3) -> fixed at resolved 1.5.378.106

Two were still live and are now patched via direct security pins:
- OpenTelemetry.Api 1.9.0 -> 1.15.3 (GHSA-g94r-2vxg-569j) pinned in Cluster;
  Runtime/ControlPlane/AdminUI + tests inherit via project reference
- Tmds.DBus.Protocol 0.20.0 -> 0.21.3 (GHSA-xrw6-gwf8-vvr9) pinned in Client.UI

Also correct the Historian sidecar runtime comments (x86 -> x64, matching the
csproj PlatformTarget). Solution audit: 0 vulnerable packages; full build clean.
2026-06-12 09:03:42 -04:00
Joseph Doherty 9f13101896 feat(validation): require TagConfig.FullName on Galaxy alias tags; reframe Tag doc 2026-06-11 21:21:32 -04:00
Joseph Doherty 2ba2f8a899 feat(commons): TryParseRelayBody — detect pure ctx.GetTag relay scripts 2026-06-11 20:59:10 -04:00
Joseph Doherty 61b230d79a harden(historian): nullable HistorizeToAveva (missing→historize) for rolling-restart-safe deserialize + middle-link test 2026-06-11 13:00:57 -04:00
Joseph Doherty c20d228384 fix(historian): volatile _backoffIndex + read _evictedCount under lock (thread-safety) 2026-06-11 12:49:44 -04:00
Joseph Doherty 8012509584 feat(historian): honor per-alarm HistorizeToAveva opt-out at the durable write 2026-06-11 12:48:13 -04:00
Joseph Doherty 8ac3ac5be9 feat(alarms): carry AlarmTypeName + operator Comment on AlarmTransitionEvent (historian feed prep) 2026-06-11 11:03:00 -04:00
Joseph Doherty f9932f2d8e refactor(admin): use CorrelationId wrapper for alarm ack/shelve commands 2026-06-11 09:27:24 -04:00
Joseph Doherty 370a2b7b48 feat(alerts): AdminUI alarm ack/shelve via AdminOperationsActor singleton
T21: add an AdminUI path for acknowledging/shelving alarms that routes
through the admin-pinned AdminOperationsActor cluster singleton, which
republishes onto the same 'alarm-commands' DPS topic the OPC UA method
path (T18) and the engine subscriber (T19) use. The broadcast + the
ScriptedAlarmHostActor ownership filter handle cross-node routing, so
the singleton needs no knowledge of which node owns the alarm.

- Commons: AcknowledgeAlarmCommand/ShelveAlarmCommand (+ result records)
  and a shared AlarmCommandsTopic const; ScriptedAlarmHostActor now
  re-exports that const (mirrors the DriverControlTopic pattern).
- AdminOperationsActor: two handlers map the control-plane messages to
  AlarmCommand (Acknowledge / OneShotShelve / TimedShelve / Unshelve,
  threading User/Comment/UnshelveAtUtc) and publish via the DPS mediator.
- IAdminOperationsClient + AdminOperationsClient: typed Acknowledge/Shelve
  ask wrappers mirroring StartDeploymentAsync.
- Alerts.razor: per-row DriverOperator-gated Ack/Shelve/Unshelve controls;
  operator name from AuthenticationState. Timed-shelve datetime UI deferred.
- 5 TestKit tests (mediator-probe subscribed to alarm-commands) verifying
  each kind's mapping + reply; 56/56 ControlPlane tests green.
2026-06-11 06:44:27 -04:00