Resolve all 46 low-severity architecture review findings

This commit is contained in:
Joseph Doherty
2026-09-09 22:56:36 -04:00
parent fef3e7675f
commit 9ee402bbcd
139 changed files with 2621 additions and 1082 deletions
@@ -50,6 +50,7 @@ public sealed class FlowDebugServiceTests : IDisposable
};
private readonly ActorSystem _system = ActorSystem.Create("flow-debug-service-tests");
private readonly ISiteRepository _sites = Substitute.For<ISiteRepository>();
private readonly IInboundApiRepository _inboundApi = Substitute.For<IInboundApiRepository>();
private readonly ITemplateEngineRepository _templates = Substitute.For<ITemplateEngineRepository>();
private readonly IFlatteningPipeline _pipeline = Substitute.For<IFlatteningPipeline>();
@@ -66,7 +67,7 @@ public sealed class FlowDebugServiceTests : IDisposable
public void Dispose() => _system.Terminate().Wait(TimeSpan.FromSeconds(5));
private FlowDebugService CreateService(object? reply, string role = "Deployer")
private FlowDebugService CreateService(object? reply, string role = "Deployer", string? permittedSite = null)
{
var holder = new ManagementActorHolder();
if (reply != null)
@@ -77,7 +78,9 @@ public sealed class FlowDebugServiceTests : IDisposable
new Claim(JwtTokenService.UsernameClaimType, "tester"),
new Claim(JwtTokenService.RoleClaimType, role),
};
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, "TestAuth"));
var identity = new ClaimsIdentity(claims, "TestAuth");
if (permittedSite is not null) identity.AddClaim(new Claim(JwtTokenService.SiteIdClaimType, permittedSite));
var principal = new ClaimsPrincipal(identity);
var comms = new CommunicationService(
Options.Create(new CommunicationOptions()),
@@ -85,7 +88,7 @@ public sealed class FlowDebugServiceTests : IDisposable
comms.SetSiteCallAudit(_system.ActorOf(Props.Create(() => new ScriptedSiteCallAuditActor(this))));
comms.SetNotificationOutbox(_system.ActorOf(Props.Create(() => new ScriptedOutboxActor(this))));
return new FlowDebugService(holder, new StubAuth(principal), _inboundApi, _templates, _pipeline, comms, NullLogger<FlowDebugService>.Instance);
return new FlowDebugService(holder, new StubAuth(principal), _inboundApi, _templates, _pipeline, comms, NullLogger<FlowDebugService>.Instance, _sites);
}
/// <summary>
@@ -110,6 +113,33 @@ public sealed class FlowDebugServiceTests : IDisposable
null, null, null, siteId, "node-a", "Sim01", "ERP.GetOrder", null,
Lifecycle: null, CorrelationId: correlationId);
[Theory]
[InlineData(42, true)]
[InlineData(99, false)]
public async Task ResolvedSite_ScopedCallerCanOnlyRelayItsGrant(int siteId, bool expected)
{
_sites.GetAllSitesAsync(Arg.Any<CancellationToken>()).Returns(new[]
{
new ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites.Site("Plant", "plant") { Id = siteId }
});
var svc = CreateService(null, permittedSite: "42");
var result = await svc.RetryOutboundAsync(OutboundStep(FlowStepKind.ApiCall, FlowStepOutcome.Parked, Guid.NewGuid(), "plant"));
Assert.Equal(expected, result.Success);
Assert.Equal(expected ? 1 : 0, _siteCallRequests.Count);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task UnresolvedSite_ScopedCallerCannotRelay(bool retry)
{
var svc = CreateService(null, permittedSite: "42");
var step = OutboundStep(FlowStepKind.ApiCall, FlowStepOutcome.Parked, Guid.NewGuid(), "unknown-site");
var result = retry ? await svc.RetryOutboundAsync(step) : await svc.DiscardOutboundAsync(step);
Assert.False(result.Success);
Assert.Empty(_siteCallRequests);
}
[Fact]
public async Task RetryOutbound_ApiCallParked_RelaysRetrySiteCallWithCorrelationAndSite()
{