test(acl): pin the fail-closed rule for non-condition events on folder items (#838 item 3)
v2-ci / unit-tests (push) Waiting to run
v2-ci / unit-tests (push) Waiting to run
A folder event item under enforcement withholds an event that names no live condition; flag off, the SDK's own type + SourceNode check applies. Positive controls: the same event reaches the item flag-off and a condition event reaches it flag-on. Mutation-checked: IsNotifierEventVisibleTo returning true for a non-condition event fails the test. Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi
This commit is contained in:
+49
@@ -167,6 +167,55 @@ public sealed class FolderEventVerdictInvalidationTests
|
||||
"MonitoredNode2.InvalidatePermissionCaches() is gone — re-check InvalidateFolderEventVerdicts against the new SDK");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gitea #838 item 3: an event on a folder that names no live condition (none is produced today — model-change and
|
||||
/// rejected-write audits go to the Server object) is WITHHELD under enforcement, fail closed, and delivered with
|
||||
/// the flag off (the SDK's own type + SourceNode check only). Positive controls: the same event reaches the same
|
||||
/// item with enforcement off, and a condition event reaches it with enforcement on.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task A_non_condition_event_on_a_folder_is_withheld_under_enforcement_and_delivered_without_it()
|
||||
{
|
||||
var ct = TestContext.Current.CancellationToken;
|
||||
await using var rig = await ServerEventRig.StartAsync("Folder838NonCondition", encrypted: false, ct);
|
||||
rig.KeyRoles = [];
|
||||
rig.MaterialiseNative();
|
||||
rig.Enforce(false, [], ServerEventRig.EquipmentGrant(EqA, NodePermissions.ReadOnly));
|
||||
|
||||
using var session = await rig.ConnectAsync(anonymous: true, ct);
|
||||
var events = new RecordedEvents();
|
||||
var subscription = await RecordedEvents.SubscribeAsync(session, events, ct);
|
||||
var onA = RecordedEvents.AddEventItem(subscription, ServerEventRig.UnsNodeId(session, EqA));
|
||||
await subscription.ApplyChangesAsync(ct);
|
||||
onA.Status.Error.ShouldBeNull();
|
||||
|
||||
var folder = rig.Nm.FindPredefinedNode<FolderState>(ServerEventRig.UnsNodeId(session, EqA)).ShouldNotBeNull();
|
||||
void ReportPlainEvent(string message)
|
||||
{
|
||||
var e = new BaseEventState(null);
|
||||
lock (rig.Nm.Lock)
|
||||
{
|
||||
e.Initialize(rig.Nm.SystemContext, folder, EventSeverity.Low, new LocalizedText(message));
|
||||
folder.ReportEvent(rig.Nm.SystemContext, e);
|
||||
}
|
||||
}
|
||||
|
||||
ReportPlainEvent("plain-off");
|
||||
await RecordedEvents.WaitUntilAsync(() => events.Has(onA, "plain-off"));
|
||||
|
||||
rig.Enforce(true, [], ServerEventRig.EquipmentGrant(EqA, NodePermissions.ReadOnly));
|
||||
rig.Project(native: true, State("cond-on"));
|
||||
await RecordedEvents.WaitUntilAsync(() => events.Has(onA, "cond-on"));
|
||||
|
||||
ReportPlainEvent("plain-on");
|
||||
rig.Project(native: true, State("cond-on-2"));
|
||||
await RecordedEvents.WaitUntilAsync(() => events.Has(onA, "cond-on-2"));
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(700), ct);
|
||||
events.Has(onA, "plain-on").ShouldBeFalse("a non-condition event on a folder fails closed under enforcement");
|
||||
|
||||
await session.CloseAsync(ct);
|
||||
}
|
||||
|
||||
private static AlarmConditionSnapshot State(string message) =>
|
||||
new(true, false, false, true, AlarmShelvingKind.Unshelved, 700, message);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user