fix(inbound-api): resolve InboundAPI-009,010,011,013 — cache failed compiles, reject unknown body fields, close enumeration oracle, drop misnamed factory; InboundAPI-007,012 flagged

This commit is contained in:
Joseph Doherty
2026-05-16 22:24:03 -04:00
parent 8664cdf940
commit 858fe24add
7 changed files with 255 additions and 19 deletions
+11 -5
View File
@@ -13,6 +13,10 @@ public class ApiKeyValidator
{
private readonly IInboundApiRepository _repository;
// InboundAPI-011: the single message used for both "method not found" and
// "key not approved" so the two outcomes are indistinguishable to the caller.
private const string NotApprovedMessage = "API key not approved for this method";
public ApiKeyValidator(IInboundApiRepository repository)
{
_repository = repository;
@@ -45,10 +49,15 @@ public class ApiKeyValidator
return ApiKeyValidationResult.Unauthorized("Invalid or disabled API key");
}
// InboundAPI-011: "method not found" and "key not approved" must produce an
// indistinguishable response. Otherwise a caller holding any valid key could
// enumerate which method names exist by observing the status/message
// difference. Both cases return 403 with the identical message below, and the
// caller-supplied method name is never echoed back into the response.
var method = await _repository.GetMethodByNameAsync(methodName, cancellationToken);
if (method == null)
{
return ApiKeyValidationResult.NotFound($"Method '{methodName}' not found");
return ApiKeyValidationResult.Forbidden(NotApprovedMessage);
}
// Check if this key is approved for the method
@@ -57,7 +66,7 @@ public class ApiKeyValidator
if (!isApproved)
{
return ApiKeyValidationResult.Forbidden("API key not approved for this method");
return ApiKeyValidationResult.Forbidden(NotApprovedMessage);
}
return ApiKeyValidationResult.Valid(apiKey, method);
@@ -108,7 +117,4 @@ public class ApiKeyValidationResult
public static ApiKeyValidationResult Forbidden(string message) =>
new() { IsValid = false, StatusCode = 403, ErrorMessage = message };
public static ApiKeyValidationResult NotFound(string message) =>
new() { IsValid = false, StatusCode = 400, ErrorMessage = message };
}