🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

feat: add synthetic gateway keys - #27170

Merged
ibetitsmike merged 2 commits into
mainfrom
mike/chat-synthetic-keys/synthetic-keys
Jul 18, 2026
Merged

feat: add synthetic gateway keys#27170
ibetitsmike merged 2 commits into
mainfrom
mike/chat-synthetic-keys/synthetic-keys

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Mux is working on behalf of Mike.

Summary

Add a per-user synthetic API key for chatd AI Gateway attribution. Chatd resolves the key from the chat owner, extends it before expiry, and discards the generated bearer token so the key is never a usable credential.

There is no mapping table. The key is resolved from api_keys by a deterministic token name (chatd_<owner_id>_session_token), mirroring the provisionerd session token model, with three deltas that chatd needs:

  • Login type guard: token names are unvalidated user input, so a user can create a bearer token with the colliding name. The lookup excludes login_type = 'token' rows, so chatd never picks up (or extends) a real user token. Synthetic keys are minted with the owner's login type, which is never token.
  • In-place expiry extension instead of delete-and-reinsert: chat generations have no stop boundary, and an in-flight generation may have already delegated the current key ID to aibridged. Extending expires_at keeps the key ID stable forever.
  • Advisory-lock mint: the unique index on token names is partial (WHERE login_type = 'token'), so nothing DB-enforces uniqueness for synthetic keys. A per-user advisory lock serializes concurrent mints.

Keys carry a minimal scope (api_key:read) as defense in depth; the delegated gateway path never evaluates scopes and the secret is discarded at mint.

Migration 000544 removes the foreign keys from the legacy message and queue api_key_id columns while chatd continues stamping them for rolling compatibility. Stale IDs are tolerated because routing uses chats.owner_id. Individual key deletion, delete-all, and password reset remove the key without changing chat history or queue versions, and the next lookup remints it. Suspension does not delete the key; delegated gateway authorization rejects inactive users at request time.

This is the first PR in a three-PR rollout and must be fully deployed before #27171.

Refs https://linear.app/codercom/issue/CODAGT-561/maintain-synthetic-api-key-per-user-per-chat

Copy link
Copy Markdown
Collaborator Author

@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

Mux is working on behalf of Mike.

Dogfood UAT passed for the full three-PR stack.

PR1 coverage:

  • Completed a real Agents UI chat through the configured Anthropic-compatible provider.
  • Verified the owner mapping, 30-day key expiry, owner login type, and AI Gateway interception attribution.
  • Verified create, send, queue, promotion, edit, compaction, and manual-title compatibility writes.
  • Deleted an ordinary session key during an active generation. The chat completed without a fence failure, wedge, lost response, or deletion-time history mutation.
  • Forced renewal inside the 24-hour margin and verified the old key remained valid.
  • Deleted the mapped synthetic key and verified cascade cleanup plus remint on the next turn.
  • Verified a suspended user session is rejected with HTTP 401.

The same preserved database was then migrated through #27171 and #27172 successfully. A full OAuth2 authorization-code refresh was not run manually, but the equivalent active-generation key deletion was exercised deterministically.

@ibetitsmike ibetitsmike changed the title feat(coderd/x/chatd): add synthetic gateway keys feat: add synthetic gateway keys Jul 10, 2026
@linear-code

linear-code Bot commented Jul 10, 2026

Copy link
Copy Markdown

CODAGT-561

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbede83294

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread coderd/x/chatd/chatd.go
@ibetitsmike
ibetitsmike force-pushed the mike/chat-synthetic-keys/synthetic-keys branch from dbede83 to edea7df Compare July 10, 2026 18:21
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: edea7df60f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ibetitsmike
ibetitsmike force-pushed the mike/chat-synthetic-keys/synthetic-keys branch 2 times, most recently from ab1009d to 500b588 Compare July 10, 2026 19:37
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 500b588185

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

Mux is working on behalf of Mike.

Final-stack targeted dogfood passed after the FK-decoupling fix.

  • PR1 head 500b588185: both legacy API-key FKs were absent. Deleting the mapped synthetic key during an active generation left history_version, queue_version, and generation_attempt unchanged at deletion time. The generation completed normally, compatibility text IDs remained, and the next turn reminted a new synthetic key.
  • PR2 head 21f726957a: the preserved PR1 chat loaded, a new FINAL-PR2 chat completed, legacy columns remained nullable and unwritten, and the FKs remained absent.
  • PR3 head 2de350aa78: preserved PR1 and PR2 chats loaded, a new FINAL-PR3 chat completed, and the legacy columns and FKs were absent.

This supplements the earlier full UI/API/database UAT and validates the final rewritten stack heads.

@johnstcn johnstcn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is the additional complexity of the mapping table worth it versus re-using the existing model of one session token per chat?

Provisionerdserver has a similar model but creates a session token per workspace and cleans it up on stop.

Comment thread coderd/database/dbauthz/dbauthz.go
Comment thread coderd/x/chatd/synthetickey_internal_test.go
Comment thread coderd/database/migrations/000543_chat_synthetic_api_keys.up.sql Outdated
Comment thread coderd/x/chatd/synthetickey.go Outdated
Comment thread coderd/x/chatd/synthetickey.go
@ibetitsmike
ibetitsmike requested a review from johnstcn July 13, 2026 19:13
@ibetitsmike
ibetitsmike force-pushed the mike/chat-synthetic-keys/synthetic-keys branch from 98e94a7 to d7e123e Compare July 14, 2026 08:28
@ibetitsmike

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: d7e123e0f1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ibetitsmike
ibetitsmike marked this pull request as ready for review July 14, 2026 19:23
@ibetitsmike
ibetitsmike requested a review from Emyrk as a code owner July 14, 2026 19:23
Resolve the synthetic gateway key by deterministic token name
(chatd_<owner_id>_session_token) instead of a mapping table, mirroring
the provisionerd session token model. The lookup excludes login_type
'token' rows so a user-created token with the colliding name is never
picked up or extended. Near-expiry keys are extended in place under a
per-user advisory lock, keeping the key ID stable for in-flight
generations. New keys carry a minimal scope as defense in depth.
@ibetitsmike
ibetitsmike force-pushed the mike/chat-synthetic-keys/synthetic-keys branch from d7e123e to fa35022 Compare July 18, 2026 17:28
@ibetitsmike
ibetitsmike merged commit 997b5d0 into main Jul 18, 2026
25 of 26 checks passed
@ibetitsmike
ibetitsmike deleted the mike/chat-synthetic-keys/synthetic-keys branch July 18, 2026 18:45
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 18, 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.

2 participants