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
@@ -21,6 +21,13 @@ public class InboundScriptExecutor
// not safe for concurrent read/write, so a ConcurrentDictionary is used throughout.
private readonly ConcurrentDictionary<string, Func<InboundScriptContext, Task<object?>>> _scriptHandlers = new();
// InboundAPI-009: a script that fails to compile (or violates the trust model)
// is recorded here so it is compiled at most once. Without this, every subsequent
// request for a broken method re-runs the expensive Roslyn compilation — a CPU
// amplification vector since the inbound API has no rate limiting. The entry is
// cleared whenever the method is (re)compiled via CompileAndRegister.
private readonly ConcurrentDictionary<string, byte> _knownBadMethods = new();
private readonly IServiceProvider _serviceProvider;
public InboundScriptExecutor(ILogger<InboundScriptExecutor> logger, IServiceProvider serviceProvider)
@@ -50,7 +57,21 @@ public class InboundScriptExecutor
/// script is empty, fails Roslyn compilation, or violates the script trust model.
/// </summary>
public bool CompileAndRegister(ApiMethod method)
=> Compile(method) is { } handler && Register(method.Name, handler);
{
var handler = Compile(method);
if (handler == null)
{
// InboundAPI-009: record the failure so the lazy-compile path does not
// keep recompiling a broken script on every request.
_knownBadMethods[method.Name] = 0;
return false;
}
// The method definition was (re)compiled successfully — drop any stale
// failure record so a fixed script is no longer treated as bad.
_knownBadMethods.TryRemove(method.Name, out _);
return Register(method.Name, handler);
}
private bool Register(string methodName, Func<InboundScriptContext, Task<object?>> handler)
{
@@ -157,12 +178,21 @@ public class InboundScriptExecutor
if (!_scriptHandlers.TryGetValue(method.Name, out var handler))
{
// InboundAPI-009: a method already known to fail compilation must not
// be recompiled on every request — short-circuit before Roslyn runs.
if (_knownBadMethods.ContainsKey(method.Name))
return new InboundScriptResult(false, null, "Script compilation failed for this method");
// Lazy compile on first request (handles methods created after startup).
// Compile outside the cache so a failed compile is not stored, then add
// atomically so concurrent first-callers share a single handler instance.
var compiled = Compile(method);
if (compiled == null)
{
// Cache the failure so the next request short-circuits above.
_knownBadMethods[method.Name] = 0;
return new InboundScriptResult(false, null, "Script compilation failed for this method");
}
handler = _scriptHandlers.GetOrAdd(method.Name, compiled);
}