fix(acl): require the live scripted-alarm owner to match the generation's deployed owner (#797)
Review of 3d1b86b4: OpcUaPublishActor installs a new authority generation
before applying its address space, and an apply that throws keeps the old one.
A scripted alarm moved from equipment A to B therefore stayed commandable with
A's grant under B's generation (briefly before the rebuild, or indefinitely
after a failed apply).
The generation now carries ScriptedAlarmOwners (ScriptedAlarmId -> EquipmentId,
decoded by ParseDataPlaneAuthority from the artifact's ScriptedAlarms rows, the
same rows the composition materialises from). AuthorizeScriptedCondition denies
unless the node manager's live binding names the same owner as the generation:
a moved alarm is denied under the old owner's, the new owner's and a Cluster
grant until the address space re-binds it; an alarm the generation no longer
deploys is denied. Install/apply order unchanged.
Tests: window (a) generation moved / binding stale => both owners and Cluster
denied, then rebuild under the new owner => new owner allowed, old denied;
window (b) apply failed after install => denied across clock and further
generations, then a successful rebuild restores the new owner only; undeployed
alarm denied; artifact decode of the owner map.
This commit is contained in:
+5
-1
@@ -571,7 +571,11 @@ and is **never** split into a scope: `OtOpcUaNodeManager` binds each LIVE script
|
||||
path through the CURRENT authority generation's `EquipmentScopePaths` (decoded from the artifact by the same
|
||||
`AclScopePathResolver` call that places an `Equipment` grant). So a grant on the owning equipment or any
|
||||
ancestor (line, area, UNS namespace, cluster) authorizes its scripted alarms; a sibling equipment's grant or a
|
||||
grant on one tag beneath the equipment does not. Fail-closed: an unbound condition (owner folder missing), a
|
||||
grant on one tag beneath the equipment does not. The same generation also carries each scripted alarm's
|
||||
deployed owner (`ScriptedAlarmOwners`, from the artifact's `ScriptedAlarms` rows), and the live binding must
|
||||
**agree** with it: the publish actor installs a generation before applying its address space, and a failed apply
|
||||
keeps the old one, so a moved alarm is denied under its old and new owner's grants alike until the address space
|
||||
re-binds it. Fail-closed: an unbound condition (owner folder missing), a
|
||||
removed/replaced instance, or an owner the generation cannot place is denied for **every** grant, `Cluster`
|
||||
included — there is no realm-root or id-split fallback. The key, grant and generation are re-read on every call
|
||||
(uncached). NodeIds and `AlarmCommand.AlarmId` are unchanged. With the flag **off** none of this is consulted.
|
||||
|
||||
Reference in New Issue
Block a user