Skip to content

fix: grant AsAIBridged ResourceSystem.ActionCreate for UpsertAISeatState#24603

Merged
mtojek merged 1 commit into
mainfrom
fix/aibridged-rbac-ai-seat-upsert
Apr 22, 2026
Merged

fix: grant AsAIBridged ResourceSystem.ActionCreate for UpsertAISeatState#24603
mtojek merged 1 commit into
mainfrom
fix/aibridged-rbac-ai-seat-upsert

Conversation

@mtojek
Copy link
Copy Markdown
Member

@mtojek mtojek commented Apr 22, 2026

Problem

When a user connects to AI Bridge for the first time, UpsertAISeatState fails with unauthorized: rbac: forbidden because the subjectAibridged RBAC subject is missing ResourceSystem.ActionCreate.

UpsertAISeatState is called from two places via SeatTracker.RecordUsage:

  1. enterprise/aibridgedserver/aibridgedserver.go — uses AsAIBridged context (broken)
  2. coderd/provisionerdserver/provisionerdserver.go — uses AsProvisionerd context (works, because subjectProvisionerd has ResourceSystem: {WildcardSymbol})

The error only surfaces on the first connection per user because the seat tracker throttles retries for 30 minutes after a failure (failedThrottleInterval), silencing subsequent attempts.

Fix

Add rbac.ResourceSystem.Type: {policy.ActionCreate} to subjectAibridged. This is the minimal permission needed (principle of least privilege), matching how subjectDBPurge scopes ResourceSystem to a single action rather than using WildcardSymbol.

A regression test exercises the production call path: dbauthz-wrapped DB with a real authorizer and AsAIBridged context.

Fixes coder/internal#1444

🤖 Generated with Coder Agents

…Create for UpsertAISeatState

The aibridged RBAC subject was missing ResourceSystem.ActionCreate,
causing UpsertAISeatState to fail with 'unauthorized: rbac: forbidden'
on the first AI Bridge connection per user. The seat tracker's throttle
logic then suppressed retries for 30 minutes, making the error appear
one-time.

Add the minimal permission and a regression test that exercises the
production call path (dbauthz-wrapped DB + AsAIBridged context).

Fixes coder/internal#1444
@mtojek mtojek changed the title fix(coderd/database/dbauthz): grant AsAIBridged ResourceSystem.ActionCreate for UpsertAISeatState fix: grant AsAIBridged ResourceSystem.ActionCreate for UpsertAISeatState Apr 22, 2026
@mtojek mtojek marked this pull request as ready for review April 22, 2026 08:22
@mtojek mtojek requested review from jaaydenh and ssncferreira April 22, 2026 08:22
@mtojek mtojek force-pushed the fix/aibridged-rbac-ai-seat-upsert branch from f39b612 to e5cf2a9 Compare April 22, 2026 08:37
@mtojek mtojek marked this pull request as draft April 22, 2026 08:37
@mtojek mtojek force-pushed the fix/aibridged-rbac-ai-seat-upsert branch from e5cf2a9 to f39b612 Compare April 22, 2026 08:38
@mtojek mtojek marked this pull request as ready for review April 22, 2026 08:40
},
rbac.ResourceApiKey.Type: {policy.ActionRead}, // Validate API keys.
rbac.ResourceAibridgeInterception.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
rbac.ResourceSystem.Type: {policy.ActionCreate}, // Required for UpsertAISeatState.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is much too broad of a permission to add to AI Bridge which will have unintended consequences. Something a bit more fine grained is needed instead.

Copy link
Copy Markdown
Member Author

@mtojek mtojek Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically agree with you, but as a quick first for seat calculation, this option is the cheapest 👍

EDIT:

It's still better than its counterpart in provisionerd:
rbac.ResourceSystem.Type: {policy.WildcardSymbol},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully understand AI bridge but I was thinking because of how it proxies LLM requests, its important to be careful about what access is given here for security reasons

Copy link
Copy Markdown
Member Author

@mtojek mtojek Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. ResourceSystem is a catch-all, so granting any action on it feels too broad on the surface. Here's why I think this is safe short-term, plus what I'd suggest long-term.

Short-term safety argument (for the nearest release):

ResourceSystem + ActionCreate unlocks some querier methods (InsertDBCryptKey, InsertDERPMeshKey, InsertReplica, UpsertRuntimeConfig, etc.). However, none of them are reachable from aibridged code paths. The AI Bridge daemon interacts with the DB exclusively through aibridgedserver.Server methods, which only call:

  • ResourceAibridgeInterception operations (CRUD)
  • ResourceUser (read)
  • ResourceApiKey (read)
  • SeatTracker.RecordUsage -> UpsertAISeatState (the broken one)

Long-term: dedicated ResourceAISeat

ResourceSystem is already deprecated (the comment in object_gen.go says so explicitly), and UpsertAISeatState should have its own resource. Happy to do that as a follow-up. For the immediate fix, the blast radius is zero in practice because there's no code path from AI Bridge to any of the other ResourceSystem + ActionCreate operations.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI here is a draft PR for the long-term version: #24613 , but we'll need RBAC subject-matter expert to review it thoroughly.

@mtojek mtojek merged commit ec91ac5 into main Apr 22, 2026
67 of 68 checks passed
@mtojek mtojek deleted the fix/aibridged-rbac-ai-seat-upsert branch April 22, 2026 14:39
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AI seat state upsert fails with RBAC forbidden error on per-user first connection to AI Bridge

2 participants