- Shipped
- August 15, 2026 at 5:52 AM UTC
- Author
- Kamo
- Commit
- 166043b
AiModelController and AiUsageController checked organization ownership and no right. The 403s already in the model controller compare provider.getOrganizationId() to the session's org — real tenant isolation, and a different question from whether the caller may administer models at all. MANAGE_AI_MODELS now gates all four model endpoints and VIEW_AI_USAGE both usage endpoints. Gating the model LIST is safe here, and that was checked rather than assumed. One cluster ago the equivalent-looking mailbox list turned out to feed recipient autocomplete, so gating it would have emptied people's address books. Every caller of /api/ai/models is a settings tab — SecurityModelsTab and ProviderSetupTab — and no chat or composer surface reads it. Identical from the endpoint, opposite once you follow the consumer. AIService's SessionHelper had no hasRight, so one was added, fail-closed from the first line: no session, no rights array, or a rights value of the wrong type all refuse. KBService's equivalent granted everything when the list was empty or absent and silently disabled every gate built on it until that was fixed; there was no reason to repeat it here. No seeding. MANAGE_AI_SETTINGS, MANAGE_AI_MODELS and VIEW_AI_USAGE are held by the same 14 roles and 33 members. exportUsage returns ResponseEntity<byte[]> and streams a file, so its refusal is plain bytes rather than the JSON map every other gate in this pass returns.