Folder-event verdict invalidation is untested and its orphan test is non-discriminating since #855 #878
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while closing #838 item 1.
FolderEventVerdictInvalidationTests.An_orphaned_folder_item_does_not_keep_a_stale_allow_across_a_deploy_and_a_transferno longer discriminates. Mutation check on mastere5a03e3c: withInvalidateFolderEventVerdictsskipping every node (neither the private-SDK route nor the per-session/detach-reattach fallback), the test still passes. Since #855 a condition's own events are decided per item at report time, uncached, so the SDK's memoized verdict only matters for events that travel the SDK per-notifier channel. A condition's method audits are the documented candidate, but a probe (auditing on, encrypted channel, AddComment by a cluster-granted caller, observer on an equipment folder) showed none reach a folder item at all: the SDK's type-levelReceiveEventscheck denies audit types for ordinary sessions (seeAclServerObjectModelChangeTests). So todayInvalidateFolderEventVerdicts, its reflection and its fallback guard a path no producible event exercises.Consequence: the fallback route (detach/re-attach of session-less items, which can lose an event) is untested, and the orphan test gives false assurance for the invalidation.
Action (pick one):
InvalidateNodePermissionCachesper instance is a ~5-line change); orOption 2 is the better fit if option 1's search comes up empty, because it removes the SDK-bump hazard rather than guarding it. Refs #838, #826, #855.
Decision: option 2. No event the product raises reaches a folder item through the SDK's cached per-item verdict with an allow that depends on a grant. The invalidation, the reflection into
MonitoredNode2.InvalidatePermissionCaches, the detach/re-attach fallback, theFolderEventVerdictInvalidationscounter and the guard test are deleted. Under enforcement, the SDK channel's verdict for items on our nodes is now a flat deny, so nothing it caches depends on a grant.Search evidence (SDK 2.0.1, decompiled with ilspycmd: Opc.Ua.Server, Opc.Ua.Core.Types)
MonitoredNode2.GetOrAddEventPermissionAsyncis the only reader ofm_eventPermissionCache. It is called only fromProcessEventForItemAsync, which is fed by theOnReportEventAsyncchannel. In 2.0.1 the only caller of the re-implementedINodeManager3.ValidateEventRolePermissionsis that method, throughAsyncNodeManagerAdapter. The baseCustomNodeManager2.ConditionRefresh(line 5378) calls the non-virtual base method, andAsyncCustomNodeManager.ConditionRefreshdoes not cache.ReportConditionEvent→ReportEventWithoutBlocking→DeliverConditionEventAsync. That code serves our notifiers itself (DeliverToNotifierItems, uncached, #855) and never writes to the channel.grep ReportEventoversrc/turns up no other caller.ReportStateChange)ConditionState.ReportStateChangeis gated onAutoReportStateChanges, which we set tofalse(OtOpcUaNodeManager.cs~2802).NodeState.ReportEventon the condition)ProcessEventForItemAsyncdrops them unlessServer.Auditingis on (ServerConfiguration.AuditingEnabledis never set; the only route would be anOpcUa:ApplicationConfigPathXML file) and the session uses SignAndEncrypt or https. After that, the SDK's type-levelReceiveEventscheck decides. Probe ofValidateRolePermissions(ctx, type, ReceiveEvents)for all nine well-known roles:AuditEventType,AuditConditionEventType,…Comment,…Acknowledge,…Confirm,…Enable,…Shelving,AuditWriteUpdateEventTypeare DENY for every role except SecurityAdmin. BaseEventType, AlarmConditionType, GeneralModelChangeEventType and SystemStatusChangeEventType are OK for all. Nothing grantsSecurityAdmin: the defaultRoleManagermaps identities only to Anonymous, AuthenticatedUser and TrustedApplication. OtOpcUa does not use the DIConfigureRolespath or a custom role manager,RoleCarryingUserIdentityadds no SDK roles, and the RoleSetAddIdentitymethods themselves requireSecurityAdmin(RoleAuthorizationGate.CheckAdmin).src/callsReportEventon a folder. Model-change and audit-write events go throughReportToServerObject, which uses the core Server object and not ourMonitoredNodes.OnReportEventoverride is empty). Server-object items are decided per event inOnConditionReportEvent/ReportToServerObject. The Server node'sMonitoredNode2belongs to the core node manager, and our invalidation never touched it.ConditionRefreshoverride →RefreshDirectItemsdecides per item, uncached (IsNotifierEventVisibleTo).m_permissionCache)ValidateRolePermissionsAsync, the SDK role check, which no deploy changes. Invalidation was skipped with enforcement off anyway, and never ran on variables.Mutation on the pre-change tip: with
InvalidateFolderEventVerdictsreturning immediately, 2 of 347 OpcUaServer integration tests failed. One was its own counter test. The other was the plain-event test, which reports a hand-madeBaseEventon a folder and then flips enforcement off→on. That is a test-only producer crossing a mode flip.What changed
INodeManager3.ValidateEventRolePermissions: under enforcement, items on our nodes getBadUserAccessDeniedfor everything on the channel. In effect, condition method audits are now withheld from folder items under enforcement; this is stricter than Part 3, which allows it. They still reach Server-object items, decided per event. With the flag off, behaviour is unchanged.docs/security.md: a verdict cached while enforcement was off survives the switch to on. The switch happens once, when the host wires the authorizer just after the server starts listening. The only allow it could carry is a method audit to aSecurityAdminsession.FolderEventVerdictInvalidationTests→FolderEventVerdictFreshnessTests):A_revoked_grant_stops_condition_events_to_that_session_while_a_granted_session_keeps_them(new). The positive control is a still-granted session on the same folder and the Server object. The folder leg fails only when both the #562 stand-down and the per-event grant check are removed. The Server-object leg fails whenOnConditionReportEventskips its grant check.A_condition_method_audit_reaches_a_folder_item_only_with_enforcement_off(true/false)(new).SecurityAdminis mapped in the test only. Positive controls: the Server-object item gets the audit, and with the flag off the folder item gets it, so the channel really carries it. It fails if the oldIsNotifierEventVisibleTodecision or no decision is put back on the channel.DeliverToNotifierItemsis skipped, so it pins the per-item decision.Folder_verdicts_are_not_invalidated_while_enforcement_is_offandThe_sdks_node_wide_permission_cache_invalidation_is_still_resolvable.docs/security.md(folder event ACL + "Which permissions an event on a folder follows" + #855 note),.claude/rules/data-plane-auth.md.Commit:
fa811febon master (rebased over #886's3a312ffd, which merged without conflicts). Suites on that tip: OpcUaServer.Tests 1275 passed / 1 skipped / 0 failed; OpcUaServer.IntegrationTests 320 passed / 35 skipped / 0 failed.Closing. This also retires #838 item 1 (the private-SDK reflection watch item): there is no private-SDK dependency left on this path.