fix(auth): ScadaBridge inbound auth review fixes — scope-before-DB, pinned 403 body, pepper fail-fast, log category

This commit is contained in:
Joseph Doherty
2026-06-02 02:50:10 -04:00
parent a94558c289
commit 1fcc4f5c2b
4 changed files with 79 additions and 10 deletions
@@ -58,6 +58,14 @@ public sealed class EndpointExtensionsTests : IDisposable
private const string TokenPrefix = "sbk";
private const string ApiKeyStoreSection = "ScadaBridge:InboundApi:ApiKeyStore";
// Review #1: the EXACT canonical 403 body shared by the "method not found" and
// "key not in scope" branches. Asserting against this literal (not just that the
// two bodies are equal-to-each-other) catches a single-branch divergence where
// BOTH branches change in lockstep but away from the agreed enumeration-safe
// body — the equal-to-each-other check alone would still pass in that case.
// Pinned to EndpointExtensions.NotApprovedMessage's JSON shape.
private const string NotApprovedBodyJson = """{"error":"API key not approved for this method"}""";
// Each test gets its own throwaway SQLite database so seeded keys never leak
// between tests; the file is deleted on Dispose.
private readonly string _sqlitePath =
@@ -178,8 +186,13 @@ public sealed class EndpointExtensionsTests : IDisposable
var request = BuildPost("secured", "{}", token);
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
// Review #1: pin the not-in-scope body to the exact canonical literal so a
// single-branch divergence is caught here too (not only in the
// identical-bodies comparison test).
Assert.Equal(NotApprovedBodyJson, body);
}
[Fact]
@@ -211,6 +224,12 @@ public sealed class EndpointExtensionsTests : IDisposable
Assert.Equal(HttpStatusCode.Forbidden, notInScopeResponse.StatusCode);
// The crux of the enumeration-safety invariant: identical bodies.
Assert.Equal(notInScopeBody, unknownBody);
// Review #1: pin BOTH bodies to the exact canonical literal, so a future
// change that diverges either branch from the agreed body is caught even if
// the two branches change together (the equal-to-each-other check above
// would not catch that on its own).
Assert.Equal(NotApprovedBodyJson, unknownBody);
Assert.Equal(NotApprovedBodyJson, notInScopeBody);
}
[Fact]