GeezerVison is showing github.com — feat: encrypt the webhook secret of a chat automation with dbcrypt by ThomasK33 · Pull Request #32076 · coder/coder
Conversation
ThomasK33
commented
Nov 12, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Part of CODAGT-1135.
Stacked on #32067. Review only this diff. It merges after #32067.
Why
Chat automations store a webhook secret in chat_automations.webhook_secret. dbcrypt encrypts only in the methods it overrides, so a writer without an override would store the secret in plaintext and nothing would encrypt it later. This PR makes the database layer encrypt the secret before any code writes one. As the RFC says, dbcrypt encrypts the column when the deployment sets --external-token-encryption-keys. Without keys the column holds plaintext, as it does for external auth tokens today.
What changed
InsertChatAutomation encrypts the secret and sets webhook_secret_key_id. GetChatAutomationByID decrypts it. This replaces the fail-closed stub that feat: add the chat automations schema and RBAC resource #32067 added. The list query still returns no secret.
dbcrypt rotate, decrypt and delete cover the column. Two new queries serve only these commands (system actor in dbauthz). delete blanks the secret to the empty string and keeps the row, because a webhook row must hold a secret.
- A test fails with the method name when a
database.Store method takes or returns a WebhookSecret, or its query names the column, and dbCrypt has no override of that name. A later update or rotate query cannot forget its override.
- The "malformed encrypted field" decrypt error no longer quotes the stored value. A plaintext secret under a key ID would have ended up in the error text. This is its own commit and touches every encrypted column.
- One line in the docs list of encrypted columns.
Scope
No handler, API type or writer of the secret. A NULL or empty secret is not encrypted: it keeps a NULL key ID and rotation skips it, like AI provider keys.
Tradeoffs
rotate and decrypt handle a user's automations in the existing per-user transaction. If coderd rewrites a secret after the command read the row and before the command writes it, the transaction fails and the command stops with an error. A rerun works. If the command writes first, coderd's write lands after the commit. In both orders the command never writes a stale secret back. The commands never change webhook_secret_version.
dbcrypt delete leaves webhook automations enabled with an empty secret. A request must never verify against an empty secret, so the webhook route has to reject it.
- A replica that was already running without keys when the first key appeared stores new secrets in plaintext with a NULL key ID, as for every dbcrypt column. It cannot read a secret that a keyed replica wrote and returns a decrypt error. A replica that starts without keys while a key is active refuses to start. The plaintext rows stay plaintext until every replica has the keys and
dbcrypt rotate has run.
Live check
On a local Enterprise build with keys set, a webhook row inserted through the dbcrypt store left no plaintext in the raw column. dbcrypt rotate, decrypt and delete then ran against that database and ended as intended. On a database that a running coderd has used, rotate stops at the key revoke because of crypto_keys rows. That gap is older than this PR (#25381).
Generated with xum • Model: anthropic:claude-sonnet-5-5 • Thinking: xhigh
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
chatgpt-codex-connector[bot] reacted with thumbs up emoji
…otation needs
GetChatAutomationsWithWebhookSecretByOwnerID lists the rows that hold a
webhook secret, and UpdateEncryptedChatAutomationWebhookSecret rewrites only
the secret and its key ID. Both are system-only in dbauthz, like the chat MCP
server pair, and nothing outside the dbcrypt commands calls them.
…tion
InsertChatAutomation encrypts the secret and sets its key ID, and
GetChatAutomationByID decrypts it. dbcrypt encrypts only in the methods it
overrides, so a test now fails with the method name when a database.Store
method takes or returns a WebhookSecret and dbCrypt does not override it.
… and delete
Rotate and Decrypt handle a user's chat automations in the same transaction
as the user's other encrypted rows, so a concurrent change of a secret fails
the transaction and never writes a stale secret back. Delete blanks the
secret to the empty string instead of removing the row, because a webhook row
must hold a secret.
…field error
A row with a key ID and data that is not base64 made the decrypt error quote
the stored value. For a column that is plaintext by mistake, such as a webhook
secret, that put the secret into an error message.
…nked row, log the guard set
…de guard
The guard now also finds a secret inside a named field (sqlc.embed) and a
query whose SQL names webhook_secret, so a bare-column query or a parameter
with another name cannot skip its override. A corrupt secret stops rotate and
decrypt with a decrypt error, and a key ID cannot name an empty secret.
…utomations-dbcrypt
Drop A1's fail-closed InsertChatAutomation stub and its test: the real override
and TestChatAutomations replace them.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Codex Review Summary: ✅ Completed
This comment shows the latest Codex review activity on this pull request.
| Review |
Status |
Commit |
Review trigger |
| 📝 Code Review |
✅ Completed 2026-11-12T09:35:38.717375Z |
274ef72 |
Manual request |
| 🔒 Security Review |
✅ Completed 2026-11-12T09:36:46.493483Z |
274ef72 |
Manual request |
ℹ️ 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" or "@codex security review".
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Codex Review: Didn't find any major issues. 👍
Reviewed commit: 274ef72d24
ℹ️ 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".
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
🛡️ Codex Security Review
Security review completed. No security issues were found in this pull request.
Reviewed commit: 274ef72d24
View security finding report
Only the user who started this review can view the report in Codex.
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This branch has not been deployed
No deployments
Reviewers
snagles
Awaiting requested review from snagles
jakehwll
Awaiting requested review from jakehwll
Uh oh!
There was an error while loading. Please reload this page.
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|