feat(managementservice): MgmtDeployArea — Deployer-only, scoped by the area's owning site (fail-closed on an unknown area), long-running like MgmtDeploySite (Gitea #40)

This commit is contained in:
Joseph Doherty
2026-10-22 14:10:53 -04:00
parent eb1c9ea7f9
commit f72c72c52f
7 changed files with 154 additions and 5 deletions
@@ -1391,6 +1391,64 @@ public class ManagementActorTests : TestKit, IDisposable
Assert.Equal(envelope.CorrelationId, response.CorrelationId);
}
// ========================================================================
// Gitea #40: MgmtDeployArea is scoped by the area's OWNING site, and an
// unresolvable area fails closed for a scoped caller (register row 98).
// ========================================================================
/// <summary>Verifies that deploy area, when the area is out of scope for a site scoped user, returns unauthorized.</summary>
[Fact]
public void DeployArea_OutOfScopeForSiteScopedUser_ReturnsUnauthorized()
{
// Area 12 belongs to site 2; user is scoped to site 1.
_templateRepo.GetAreaByIdAsync(12, Arg.Any<CancellationToken>())
.Returns(new Area("Line") { Id = 12, SiteId = 2 });
var actor = CreateActor();
var envelope = ScopedEnvelope(new MgmtDeployAreaCommand(12), new[] { "1" }, "Deployer");
actor.Tell(envelope);
var response = ExpectMsg<ManagementUnauthorized>(TimeSpan.FromSeconds(5));
Assert.Equal(envelope.CorrelationId, response.CorrelationId);
}
/// <summary>Verifies that deploy area, when the area does not exist and the caller is site scoped, returns unauthorized without an existence oracle.</summary>
[Fact]
public void DeployArea_NonexistentAreaForSiteScopedUser_ReturnsUnauthorized()
{
var actor = CreateActor();
var envelope = ScopedEnvelope(new MgmtDeployAreaCommand(999), new[] { "1" }, "Deployer");
actor.Tell(envelope);
var response = ExpectMsg<ManagementUnauthorized>(TimeSpan.FromSeconds(5));
Assert.DoesNotContain("not found", response.Message, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("exist", response.Message, StringComparison.OrdinalIgnoreCase);
}
/// <summary>Verifies that deploy area, when the area does not exist and the caller is system wide, returns a clean not-found error.</summary>
[Fact]
public void DeployArea_NonexistentAreaForSystemWideUser_ReturnsNotFoundError()
{
var actor = CreateActor();
var envelope = Envelope(new MgmtDeployAreaCommand(999), "Deployer");
actor.Tell(envelope);
var response = ExpectMsg<ManagementError>(TimeSpan.FromSeconds(5));
Assert.Contains("not found", response.Error, StringComparison.OrdinalIgnoreCase);
}
/// <summary>Verifies that deploy area is refused for a Designer.</summary>
[Fact]
public void DeployArea_WithDesignerRole_ReturnsUnauthorized()
{
var actor = CreateActor();
actor.Tell(Envelope(new MgmtDeployAreaCommand(12), "Designer"));
ExpectMsg<ManagementUnauthorized>(TimeSpan.FromSeconds(5));
}
/// <summary>Verifies that get instance, when in scope for site scoped user, returns success.</summary>
[Fact]
public void GetInstance_InScopeForSiteScopedUser_ReturnsSuccess()