mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-26 05:29:43 +00:00
479247cdae
Device and anonymous routes published the "anonymous" placeholder as RequestContext.UserPrincipalName. UserRateLimitMiddleware skips only on an EMPTY UPN, so every agent of every tenant was bucketed under user_ratelimit_anonymous and throttled against the 120/min per-user limit. On 2026-07-21 21:00-21:30 UTC that rejected 1821 agent requests with 429 (/api/agent/telemetry, config, register-session, error); the 7-day trend shows it recurring and growing with fleet size. - PolicyEnforcementMiddleware: RequestContext.UserPrincipalName carries a genuine JWT UPN or nothing. decision.UserIdentifier keeps the placeholder for log lines. - Device/bootstrap routes already hold their own limit in SecurityValidator (per cert thumbprint / per bootstrap token), so they lose nothing. - stats/platform and diagnostics/download had NO limiter of their own and were riding on the accidental shared bucket. Both now limit per trusted client IP (60/min and 30/min) via ClientIpExtractor, matching the HealthCheck pattern. - 13 new tests pin the empty-UPN contract across all 12 device/anonymous routes, plus a guard that an authenticated caller still surfaces its real UPN. Solution suite 5552 tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>