fix(management): ParseDeploymentStatus rejects ordinals — Enum.TryParse accepts "2" as InProgress despite the row-88 names-only contract; same LooksNumeric guard as the audit strict parser (found by the Wave 6 rows-98/99 agent survey)
This commit is contained in:
@@ -2745,7 +2745,13 @@ public class ManagementActor : ReceiveActor
|
||||
private static DeploymentStatus? ParseDeploymentStatus(string? status)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(status)) return null;
|
||||
if (Enum.TryParse<DeploymentStatus>(status, ignoreCase: true, out var parsed)
|
||||
var trimmed = status.Trim();
|
||||
// Reject ordinals before TryParse — "2" parses to InProgress, which the
|
||||
// documented names-only contract does not admit. No enum member name can
|
||||
// start with a digit or a sign (same guard as AuditQueryParamParsers).
|
||||
var looksNumeric = char.IsAsciiDigit(trimmed[0]) || trimmed[0] == '+' || trimmed[0] == '-';
|
||||
if (!looksNumeric
|
||||
&& Enum.TryParse<DeploymentStatus>(trimmed, ignoreCase: true, out var parsed)
|
||||
&& Enum.IsDefined(parsed))
|
||||
{
|
||||
return parsed;
|
||||
|
||||
@@ -1678,6 +1678,27 @@ public class ManagementActorTests : TestKit, IDisposable
|
||||
deployRepo.DidNotReceiveWithAnyArgs().QueryDeploymentListPageAsync(default!, default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("2")]
|
||||
[InlineData("+1")]
|
||||
[InlineData("-1")]
|
||||
public void QueryDeployments_OrdinalStatus_IsRejectedLikeAnyUnknownValue(string status)
|
||||
{
|
||||
// Register row 88 postscript (Wave 6): Enum.TryParse accepts ordinals, so
|
||||
// `--status 2` silently resolved to InProgress despite the documented
|
||||
// names-only contract. Same guard as AuditQueryParamParsers.LooksNumeric.
|
||||
var deployRepo = Substitute.For<IDeploymentManagerRepository>();
|
||||
StubDeploymentPageQuery(deployRepo, (1, 1));
|
||||
_services.AddScoped(_ => deployRepo);
|
||||
|
||||
var actor = CreateActor();
|
||||
actor.Tell(Envelope(new QueryDeploymentsCommand(Status: status), "Deployer"));
|
||||
|
||||
var response = ExpectMsg<ManagementError>(TimeSpan.FromSeconds(5));
|
||||
Assert.Contains("Success", response.Error);
|
||||
deployRepo.DidNotReceiveWithAnyArgs().QueryDeploymentListPageAsync(default!, default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("success")]
|
||||
[InlineData("SUCCESS")]
|
||||
|
||||
Reference in New Issue
Block a user