Merge branch 'master' into fix/r3-02-stale-good-family
# Conflicts: # src/Server/ZB.MOM.WW.OtOpcUa.Runtime/Drivers/DriverHostActor.cs # tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Harness/V3ArtifactSeeder.cs
This commit is contained in:
@@ -317,12 +317,21 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
/// Re-authorizes live subscriptions when a deployment installs a new authorization generation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ⚠️ <b>This is the only trigger, and the pass's memo depends on that.</b>
|
||||
/// <see cref="IsSubscriptionStillPermitted"/> memoizes key revocation and expiry for the span of one
|
||||
/// pass — safe only while revalidation is deploy-triggered, because a pass is then a momentary
|
||||
/// event whose verdicts cannot go stale within it. A future periodic trigger must give each tick a
|
||||
/// fresh memo (it already does — the dictionary is pass-local) and must not be tempted to reuse one
|
||||
/// across ticks, or an expiry landing between ticks would be served the previous tick's allow.
|
||||
/// <para>
|
||||
/// <b>There are TWO triggers</b> (arch-review 03/S19): this one, the deployment axis; and the
|
||||
/// host's low-frequency <c>AclRevalidationTimer</c>, the clock axis — a key's
|
||||
/// <c>ExpiresUtc</c> passes with the clock, not with a deployment, so a deploy-only trigger
|
||||
/// left an expired key streaming to a live subscription indefinitely on a fleet that had been
|
||||
/// deployed once and left running.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// ⚠️ <b>The second trigger is safe only because the memo is pass-local.</b>
|
||||
/// <see cref="IsSubscriptionStillPermitted"/> memoizes key revocation and expiry for the span
|
||||
/// of one pass, which is sound because a pass is a momentary event whose verdicts cannot go
|
||||
/// stale within it — its dictionary is constructed per call. Hoisting it across ticks, to save
|
||||
/// the walk, would serve an expiry that landed between two ticks the earlier tick's allow, and
|
||||
/// re-open exactly the gap the timer closes.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="snapshot">The newly published snapshot; unused — the current state is re-read per item.</param>
|
||||
private void OnAuthorityChanged(DataPlaneAuthoritySnapshot snapshot) => RevalidateMonitoredItems();
|
||||
@@ -3414,9 +3423,10 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This memo does cover the key expiry check that the authorizer's own cache excludes, but only
|
||||
/// for the duration of one pass — and a subscription is re-checked at a deployment, never on a
|
||||
/// timer, so an expiry that lands inside a single pass was already going to be caught by the
|
||||
/// next deployment rather than by this one.
|
||||
/// for the duration of one pass. Since arch-review 03/S19 a subscription is re-checked on the
|
||||
/// host's low-frequency timer as well as at a deployment, so an expiry that lands inside a
|
||||
/// single pass is caught by the next TICK — one interval later, not one deployment later. What
|
||||
/// makes that hold is that the memo is constructed per call and never reused across passes.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
private bool IsSubscriptionStillPermitted(
|
||||
|
||||
@@ -108,6 +108,15 @@ public sealed class DataPlaneAuthorizer
|
||||
/// </summary>
|
||||
public bool Enabled { get; }
|
||||
|
||||
/// <summary>The clock this gate evaluates key expiry against.</summary>
|
||||
/// <remarks>
|
||||
/// Exposed so the composition root's wiring can be asserted by reference. The remarks on
|
||||
/// <c>UserAuthorizationState</c> record what a second, diverging clock costs: every request denied,
|
||||
/// with a verdict indistinguishable from "no grant matched". One registered singleton threaded into
|
||||
/// every consumer is the fix, and a test that cannot see which instance landed here cannot pin it.
|
||||
/// </remarks>
|
||||
public TimeProvider Clock => _time;
|
||||
|
||||
/// <summary>
|
||||
/// Memoized grant walks for the request-rate seams (#520 stage 6). See
|
||||
/// <see cref="SessionAclDecisionCache"/> for what it is and is not allowed to cache.
|
||||
|
||||
Reference in New Issue
Block a user