fix(security): scope-filter secured-write listing + align spec with enforced site scoping (plan R2-07 T6)
This commit is contained in:
@@ -145,7 +145,7 @@ public class ManagementActorTests : TestKit, IDisposable
|
||||
var securedWriteRepo = Substitute.For<ISecuredWriteRepository>();
|
||||
securedWriteRepo.QueryAsync(
|
||||
Arg.Any<string?>(), Arg.Any<string?>(), Arg.Any<int>(), Arg.Any<int>(),
|
||||
Arg.Any<CancellationToken>())
|
||||
Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>())
|
||||
.Returns(Task.FromResult<IReadOnlyList<PendingSecuredWrite>>(
|
||||
Array.Empty<PendingSecuredWrite>()));
|
||||
_services.AddScoped(_ => securedWriteRepo);
|
||||
|
||||
@@ -349,7 +349,7 @@ public class SecuredWriteHandlerTests : TestKit, IDisposable
|
||||
[Fact]
|
||||
public void List_FiltersByStatusAndSite()
|
||||
{
|
||||
_securedWriteRepo.QueryAsync("Pending", "SITE1", 0, 200, Arg.Any<CancellationToken>())
|
||||
_securedWriteRepo.QueryAsync("Pending", "SITE1", 0, 200, Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>())
|
||||
.Returns(new List<PendingSecuredWrite>
|
||||
{
|
||||
new()
|
||||
@@ -372,13 +372,13 @@ public class SecuredWriteHandlerTests : TestKit, IDisposable
|
||||
Assert.Equal(envelope.CorrelationId, response.CorrelationId);
|
||||
Assert.Contains("\"id\":3", response.JsonData);
|
||||
Assert.Contains("alice", response.JsonData);
|
||||
_securedWriteRepo.Received(1).QueryAsync("Pending", "SITE1", 0, 200, Arg.Any<CancellationToken>());
|
||||
_securedWriteRepo.Received(1).QueryAsync("Pending", "SITE1", 0, 200, Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void List_NoFilters_PassesNullsToRepository()
|
||||
{
|
||||
_securedWriteRepo.QueryAsync(null, null, 0, 200, Arg.Any<CancellationToken>())
|
||||
_securedWriteRepo.QueryAsync(null, null, 0, 200, Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>())
|
||||
.Returns(new List<PendingSecuredWrite>());
|
||||
|
||||
var actor = CreateActor();
|
||||
@@ -388,7 +388,49 @@ public class SecuredWriteHandlerTests : TestKit, IDisposable
|
||||
actor.Tell(envelope);
|
||||
|
||||
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||
_securedWriteRepo.Received(1).QueryAsync(null, null, 0, 200, Arg.Any<CancellationToken>());
|
||||
_securedWriteRepo.Received(1).QueryAsync(null, null, 0, 200, Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void List_SiteScopedReader_ExplicitOutOfScopeSiteFilter_Unauthorized()
|
||||
{
|
||||
SeedSiteWithConnection(1, "SITE1", "Gw1", "MxGateway");
|
||||
var actor = CreateActor();
|
||||
actor.Tell(ScopedEnvelope(new ListSecuredWritesCommand(null, "SITE1"), "bob", ["3"], "Verifier"));
|
||||
ExpectMsg<ManagementUnauthorized>(TimeSpan.FromSeconds(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void List_SiteScopedReader_Unfiltered_QueriesOnlyPermittedIdentifiers()
|
||||
{
|
||||
_siteRepo.GetAllSitesAsync(Arg.Any<CancellationToken>()).Returns(new List<Site>
|
||||
{
|
||||
new("Site1", "SITE1") { Id = 1 },
|
||||
new("Site3", "SITE3") { Id = 3 },
|
||||
});
|
||||
_securedWriteRepo.QueryAsync(null, null, 0, 200,
|
||||
Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>())
|
||||
.Returns(new List<PendingSecuredWrite>());
|
||||
var actor = CreateActor();
|
||||
actor.Tell(ScopedEnvelope(new ListSecuredWritesCommand(null, null), "bob", ["3"], "Verifier"));
|
||||
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||
_securedWriteRepo.Received(1).QueryAsync(null, null, 0, 200,
|
||||
Arg.Is<IReadOnlyCollection<string>?>(s => s != null && s.Single() == "SITE3"),
|
||||
Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void List_SystemWideReader_PassesNullPermittedFilter()
|
||||
{
|
||||
_securedWriteRepo.QueryAsync(null, null, 0, 200,
|
||||
Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>())
|
||||
.Returns(new List<PendingSecuredWrite>());
|
||||
var actor = CreateActor();
|
||||
actor.Tell(Envelope(new ListSecuredWritesCommand(null, null), "carol", "Operator"));
|
||||
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||
_securedWriteRepo.Received(1).QueryAsync(null, null, 0, 200,
|
||||
Arg.Is<IReadOnlyCollection<string>?>(s => s == null),
|
||||
Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -623,16 +665,16 @@ public class SecuredWriteHandlerTests : TestKit, IDisposable
|
||||
[Fact]
|
||||
public void List_WithSkipTake_ForwardsPagingAndReturnsTotalCount()
|
||||
{
|
||||
_securedWriteRepo.QueryAsync(null, null, 10, 25, Arg.Any<CancellationToken>())
|
||||
_securedWriteRepo.QueryAsync(null, null, 10, 25, Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>())
|
||||
.Returns(new List<PendingSecuredWrite>());
|
||||
_securedWriteRepo.CountAsync(null, null, Arg.Any<CancellationToken>()).Returns(87);
|
||||
_securedWriteRepo.CountAsync(null, null, Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>()).Returns(87);
|
||||
|
||||
var actor = CreateActor();
|
||||
actor.Tell(Envelope(new ListSecuredWritesCommand(null, null, Skip: 10, Take: 25), "carol", "Operator"));
|
||||
|
||||
var resp = ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
||||
_securedWriteRepo.Received(1).QueryAsync(null, null, 10, 25, Arg.Any<CancellationToken>());
|
||||
_securedWriteRepo.Received(1).CountAsync(null, null, Arg.Any<CancellationToken>());
|
||||
_securedWriteRepo.Received(1).QueryAsync(null, null, 10, 25, Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>());
|
||||
_securedWriteRepo.Received(1).CountAsync(null, null, Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>());
|
||||
Assert.Contains("\"totalCount\":87", resp.JsonData);
|
||||
}
|
||||
|
||||
@@ -655,7 +697,7 @@ public class SecuredWriteHandlerTests : TestKit, IDisposable
|
||||
ValueJson = "false", ValueType = "Boolean", Status = "Pending",
|
||||
OperatorUser = "alice", SubmittedAtUtc = DateTime.UtcNow.AddHours(-25) // TTL default 24h
|
||||
};
|
||||
_securedWriteRepo.QueryAsync(null, null, 0, 200, Arg.Any<CancellationToken>())
|
||||
_securedWriteRepo.QueryAsync(null, null, 0, 200, Arg.Any<IReadOnlyCollection<string>?>(), Arg.Any<CancellationToken>())
|
||||
.Returns(new List<PendingSecuredWrite> { fresh, stale });
|
||||
_securedWriteRepo.TryMarkExpiredAsync(2, Arg.Any<DateTime>(), Arg.Any<CancellationToken>())
|
||||
.Returns(true);
|
||||
|
||||
Reference in New Issue
Block a user