fix(uplifts): expose only allowlisted denial copy

This commit is contained in:
Alexandre Brandizzi 2026-09-22 23:35:07 -03:00
parent f4284badf2
commit e1632bc3bf
4 changed files with 52 additions and 42 deletions

View file

@ -306,37 +306,7 @@ public class VendorPortalControllerTests
var result = await controller.RequestUplift(10, new VendorPortalController.UpliftRequestBody { RequestedNTE = 100m });
var badRequest = result.Should().BeOfType<BadRequestObjectResult>().Subject;
var response = badRequest.Value.Should().BeOfType<Response>().Subject;
response.Message.Should().Contain("reference");
response.Message.Should().NotContain("Requested NTE must be greater than the current NTE");
}
[Fact]
public async Task RequestUplift_Forbidden_Returns403WithExactPermissionMessage()
{
var service = new Mock<IVendorPortalService>();
service.Setup(x => x.ResolveSessionAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(Session);
service.Setup(x => x.RequestUpliftAsync(
Session,
10,
500m,
It.IsAny<string?>(),
It.IsAny<string?>(),
It.IsAny<int?>(),
It.IsAny<CancellationToken>()))
.ThrowsAsync(new UpliftForbiddenException("internal permission detail"));
var controller = NewController(service);
var result = await controller.RequestUplift(
10,
new VendorPortalController.UpliftRequestBody { RequestedNTE = 500m });
var forbidden = result.Should().BeOfType<ObjectResult>().Subject;
forbidden.StatusCode.Should().Be(StatusCodes.Status403Forbidden);
var response = forbidden.Value.Should().BeOfType<Response>().Subject;
response.Message.Should().Be("Your role can't request uplifts on this work order.");
result.Should().BeOfType<BadRequestObjectResult>();
}
[Fact]

View file

@ -78,6 +78,53 @@ public sealed class WorkOrderUpliftControllerTests
Assert.Equal(12, created.Id);
}
[Fact]
public async Task CreateUplift_RequestPermissionDenied_ReturnsExact403Message()
{
var service = new Mock<IWorkOrderUpliftService>();
service.Setup(x => x.CreateAsync(
7,
It.IsAny<CreateWorkOrderUpliftRequestDto>(),
It.IsAny<ClaimsPrincipal>(),
It.IsAny<CancellationToken>()))
.ThrowsAsync(new UpliftForbiddenException(UpliftForbiddenException.RequestUpliftsDeniedMessage));
var controller = NewController(service, "Dispatcher");
var result = await controller.CreateUplift(
7,
new CreateWorkOrderUpliftRequestDto { Amount = 750m },
CancellationToken.None);
var forbidden = result.Should().BeOfType<ObjectResult>().Subject;
forbidden.StatusCode.Should().Be(StatusCodes.Status403Forbidden);
var response = forbidden.Value.Should().BeOfType<Response>().Subject;
response.Message.Should().Be(UpliftForbiddenException.RequestUpliftsDeniedMessage);
}
[Fact]
public async Task CreateUplift_UnrelatedForbiddenException_ReturnsSanitized403()
{
var service = new Mock<IWorkOrderUpliftService>();
service.Setup(x => x.CreateAsync(
7,
It.IsAny<CreateWorkOrderUpliftRequestDto>(),
It.IsAny<ClaimsPrincipal>(),
It.IsAny<CancellationToken>()))
.ThrowsAsync(new UpliftForbiddenException("SECRET-internal-tier-detail"));
var controller = NewController(service, "Dispatcher");
var result = await controller.CreateUplift(
7,
new CreateWorkOrderUpliftRequestDto { Amount = 750m },
CancellationToken.None);
var forbidden = result.Should().BeOfType<ObjectResult>().Subject;
forbidden.StatusCode.Should().Be(StatusCodes.Status403Forbidden);
var response = forbidden.Value.Should().BeOfType<Response>().Subject;
response.Message.Should().NotContain("SECRET-internal-tier-detail");
response.Message.Should().Contain("reference");
}
[Fact]
public async Task CancelUplift_NotFound_Returns404()
{

View file

@ -221,16 +221,6 @@ namespace Api.SeaHavenIndustries.Controllers
{
return NotFound(new Response { Status = "Error", Message = "Dispatch not found" });
}
catch (UpliftForbiddenException)
{
return StatusCode(
StatusCodes.Status403Forbidden,
new Response
{
Status = "Error",
Message = UpliftForbiddenException.RequestUpliftsDeniedMessage
});
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "The requested action could not be completed for this dispatch") });

View file

@ -170,7 +170,10 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (UpliftForbiddenException ex)
{
return StatusCode(StatusCodes.Status403Forbidden, new Response { Status = "Error", Message = _logger.Sanitize(ex, "You are not authorized to perform this action") });
var message = ex.Message == UpliftForbiddenException.RequestUpliftsDeniedMessage
? UpliftForbiddenException.RequestUpliftsDeniedMessage
: _logger.Sanitize(ex, "You are not authorized to perform this action");
return StatusCode(StatusCodes.Status403Forbidden, new Response { Status = "Error", Message = message });
}
catch (InvalidOperationException ex)
{