feat(inbound-api): method-script exception detail on the inbound audit row, never on the HTTP body (D3)

This commit is contained in:
Joseph Doherty
2026-09-09 12:15:00 -04:00
parent a45857ddd6
commit 98c6809a66
6 changed files with 188 additions and 4 deletions
@@ -432,7 +432,23 @@ public sealed class EndpointExtensionsTests : IDisposable
var method = SeedMethod(1, "boom",
"""throw new System.InvalidOperationException("boom-msg");""");
using var host = await BuildHostAsync(method);
// Flow Debugger step logs (design 2026-09-09 D3): the detail the body must NOT carry
// is nonetheless stashed for AuditWriteMiddleware, so the inbound audit row (and the
// Flow Debugger's inbound node) can say why the run failed. A capture middleware reads
// the slot once the endpoint has finished, proving both halves in one request.
string? capturedDetail = null;
using var host = await BuildHostAsync(method, customize: builder =>
{
builder.Use(async (ctx, next) =>
{
await next();
if (ctx.Items.TryGetValue(
AuditWriteMiddleware.ErrorDetailItemKey, out var stashed))
{
capturedDetail = stashed as string;
}
});
});
var token = await SeedKeyAsync(host, "key1", "caller", new[] { "boom" });
var client = host.GetTestClient();
@@ -445,6 +461,10 @@ public sealed class EndpointExtensionsTests : IDisposable
// message is not leaked (the executor sanitises before this point).
Assert.Contains("error", body);
Assert.DoesNotContain("boom-msg", body);
// …while the audit-only slot carries the real cause.
Assert.NotNull(capturedDetail);
Assert.Contains("boom-msg", capturedDetail);
}
[Fact]