perf(backend): read-bound delegated config/all to point-reads [Phase 2b follow-up]

Addresses a Codex review finding: the Phase 2b delegated config/all path loaded
EVERY tenant config via GetAllConfigurationsAsync() (an O(all tenants) table scan
+ full-config materialization) and then filtered in memory. Because Phase 2b
opened this endpoint to delegated MSP users, a caller scoped to a few tenants
could trigger an all-tenants scan per request — response-bounded, not read-bounded.

Now point-read ONLY the caller's managed tenants via the non-creating
TryGetConfigurationAsync (cached; never writes a phantom default row), dropping
ids with no config row (exists==false). A delegated MSP scoped to k tenants does
k point reads instead of scanning n. The response is still filtered+redacted as
defense in depth; the set fed to it is now itself bounded.

Full Functions suite green (2464).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Oliver Kieselbach
2026-06-25 20:53:38 +02:00
parent 87711e1261
commit 43a87ff747
@@ -52,10 +52,13 @@ namespace AutopilotMonitor.Functions.Functions.Config
var requestCtx = req.GetRequestContext();
if (requestCtx.AllowedTenantIds != null)
{
var allowed = new System.Collections.Generic.HashSet<string>(
requestCtx.AllowedTenantIds, StringComparer.OrdinalIgnoreCase);
var all = await _configService.GetAllConfigurationsAsync();
var subset = all.Where(c => allowed.Contains(c.TenantId)).ToList();
// READ-bounded, not just response-bounded: point-read ONLY the caller's managed tenants
// instead of scanning every tenant config and filtering in memory. A delegated MSP scoped
// to k tenants triggers k point reads (cached, non-creating — TryGetConfigurationAsync
// never writes a default row). exists==false drops any id with no config row.
var reads = await Task.WhenAll(requestCtx.AllowedTenantIds.Select(async tid =>
await _configService.TryGetConfigurationAsync(tid)));
var subset = reads.Where(r => r.exists).Select(r => r.config).ToList();
_logger.LogInformation("GetAllTenantConfigurations (delegated subset, {Count} tenants) by {User}",
subset.Count, userIdentifier);