Native alarm ack: revert/refuse residuals after #760 (no-driver, stale host, keyed sessions without Galaxy identity) #765

Closed
opened 2026-11-09 13:16:21 -05:00 by dohertj2 · 2 comments
Owner

Residuals from #760 (native alarm ack refusal/revert):

  1. An ack routed to a disabled or not-yet-started driver still leaves the condition Acknowledged. Reverting it breaks DriverHostActorNativeAlarmTests and FocasNativeAlarmEndToEndTests, which rely on the old behaviour — change them to start the host's own driver, then add the revert.
  2. An ack dropped while the host is stale (config DB unreachable) is dropped before it is recorded, so it cannot be reverted and the node shows Acknowledged.
  3. Keyed sessions without a Galaxy ack identity get Good-then-revert; a synchronous BadUserAccessDenied needs a cached, periodically refreshed set of keys with a Galaxy identity readable without I/O.
Residuals from #760 (native alarm ack refusal/revert): 1. An ack routed to a disabled or not-yet-started driver still leaves the condition Acknowledged. Reverting it breaks DriverHostActorNativeAlarmTests and FocasNativeAlarmEndToEndTests, which rely on the old behaviour — change them to start the host's own driver, then add the revert. 2. An ack dropped while the host is stale (config DB unreachable) is dropped before it is recorded, so it cannot be reverted and the node shows Acknowledged. 3. Keyed sessions without a Galaxy ack identity get Good-then-revert; a synchronous BadUserAccessDenied needs a cached, periodically refreshed set of keys with a Galaxy identity readable without I/O.
dohertj2 added the type:followuppriority:p3 labels 2026-11-09 13:16:21 -05:00
Author
Owner

Fixed on master f54922f9 (items 1–2; item 3 left in the issue): (1) an ack routed to a driver that is disabled, not yet spawned, or stubbed on this node is now reverted like a refused ack; DriverHostActorNativeAlarmTests' client-ack test and the FOCAS respawn theory now start the host's own driver (FOCAS via a factory that builds a real FocasDriver per spawn, respawn via a real config change). (2) A host can only be Stale at boot and then can't route or revert, so while Stale the node manager refuses every native ack synchronously (BadUserAccessDenied); lifted on return to Steady. 3 new tests (disabled, stubbed, Stale refusal) each fail with the fix removed. Docs: AlarmTracking.md, .claude/rules/alarms.md. Item 3 (keyed sessions without a Galaxy identity → synchronous refusal) still needs a cached key→identity set; keep open for that.

Fixed on master f54922f9 (items 1–2; item 3 left in the issue): (1) an ack routed to a driver that is disabled, not yet spawned, or stubbed on this node is now reverted like a refused ack; DriverHostActorNativeAlarmTests' client-ack test and the FOCAS respawn theory now start the host's own driver (FOCAS via a factory that builds a real FocasDriver per spawn, respawn via a real config change). (2) A host can only be Stale at boot and then can't route or revert, so while Stale the node manager refuses every native ack synchronously (BadUserAccessDenied); lifted on return to Steady. 3 new tests (disabled, stubbed, Stale refusal) each fail with the fix removed. Docs: AlarmTracking.md, .claude/rules/alarms.md. Item 3 (keyed sessions without a Galaxy identity → synchronous refusal) still needs a cached key→identity set; keep open for that.
Author
Owner

Item 3 fixed on master 0702b310 (items 1–2 were f54922f9): a keyed session whose API key has no Galaxy ack identity now gets a synchronous BadUserAccessDenied, nothing applied. New GalaxyAckIdentityDirectory caches the key ids that have an otopcua/apikeys/<id>/galaxy-ack-user secret, built from ISecretStore.ListAsync (names only — nothing decrypted); lookups are Present/Absent/Unknown with no I/O. GalaxyDriver.GetAcknowledgeRefusal refuses only when there's no fallback ack account and the cache says Absent (refusal names the key and kicks a refresh), via the #760 IAlarmAcknowledgePreflight path. Fails open (Unknown → today's Good-then-revert) before the first refresh, when stale, between a signalled identity change and its refresh, and for malformed ids. GalaxyAckIdentityRefreshService refreshes on a timer and early on secret changes (ISecretCacheInvalidator wrapped — AdminUI /api-keys, /admin/secrets and replication appliers all signal). New Drivers:Galaxy:AckIdentityCache (RefreshIntervalSeconds 30, 1–3600; StaleAfterSeconds 0 = 3 intervals; bad values fail start). Known gap: an identity written via the secret CLI sends no signal → refused until the next timed refresh (a retry after the kicked refresh succeeds) — documented. 16 Galaxy + 9 Host tests; each of seven removed pieces turns a test red. Runtime 975, OpcUaServer 1026, Galaxy 450, Host 241, full OpcUaServer.IntegrationTests 132 — Host + full integration re-run green after rebase; Release 0 warnings.

Item 3 fixed on master 0702b310 (items 1–2 were f54922f9): a keyed session whose API key has no Galaxy ack identity now gets a synchronous BadUserAccessDenied, nothing applied. New GalaxyAckIdentityDirectory caches the key ids that have an `otopcua/apikeys/<id>/galaxy-ack-user` secret, built from ISecretStore.ListAsync (names only — nothing decrypted); lookups are Present/Absent/Unknown with no I/O. GalaxyDriver.GetAcknowledgeRefusal refuses only when there's no fallback ack account and the cache says Absent (refusal names the key and kicks a refresh), via the #760 IAlarmAcknowledgePreflight path. **Fails open** (Unknown → today's Good-then-revert) before the first refresh, when stale, between a signalled identity change and its refresh, and for malformed ids. GalaxyAckIdentityRefreshService refreshes on a timer and early on secret changes (ISecretCacheInvalidator wrapped — AdminUI /api-keys, /admin/secrets and replication appliers all signal). New Drivers:Galaxy:AckIdentityCache (RefreshIntervalSeconds 30, 1–3600; StaleAfterSeconds 0 = 3 intervals; bad values fail start). Known gap: an identity written via the `secret` CLI sends no signal → refused until the next timed refresh (a retry after the kicked refresh succeeds) — documented. 16 Galaxy + 9 Host tests; each of seven removed pieces turns a test red. Runtime 975, OpcUaServer 1026, Galaxy 450, Host 241, full OpcUaServer.IntegrationTests 132 — Host + full integration re-run green after rebase; Release 0 warnings.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#765