Skip to content

chore: remove vault encryption hooks from certain GORM tables in favor of AES-only encryption - #4245

Merged
Pratham-Mishra04 merged 1 commit into
devfrom
06-10-chore_dont_store_temp_tokens_in_vault
Jun 11, 2026
Merged

chore: remove vault encryption hooks from certain GORM tables in favor of AES-only encryption#4245
Pratham-Mishra04 merged 1 commit into
devfrom
06-10-chore_dont_store_temp_tokens_in_vault

Conversation

@BearTS

@BearTS BearTS commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Removes Vault-based secret storage from all sensitive-field GORM hooks and related database operations, leaving only the standard encrypt package path for at-rest encryption. This eliminates the dual-path complexity that existed for MCP client configs, OAuth tokens, sessions, temp tokens, and vector store configs.

Changes

  • Removed all VaultIsEnabled() branches from BeforeSave, AfterFind, and AfterDelete hooks across TableMCPClient, TableMCPPerUserHeaderCredential, TableOauthToken, TableOauthUserSession, TableOauthUserToken, SessionsTable, TempToken, and TableVectorStoreConfig.
  • Removed AfterDelete vault cleanup hooks from all affected table types.
  • Removed DeleteVaultSecrets helper methods from TableOauthUserToken, TableOauthUserSession, and TempToken.
  • Removed pre/post-transaction vault compensation logic (vaultStoredPaths, vaultRemovePaths) from UpdateMCPClientConfig in rdb.go.
  • Removed the pre-transaction vault ID collection and post-transaction goroutine vault cleanup from DeleteMCPClientConfig, moving the record lookup inside the transaction instead.
  • Removed vault ID pre-collection and post-delete goroutine cleanup from DeleteTempTokensByResourceID and DeleteExpiredTempTokens.
  • Bumped cloud.google.com/go/iam, aws-sdk-go-v2, and smithy-go dependency versions in the modelcatalogresolver plugin.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

go test ./framework/configstore/...
go test ./framework/configstore/tables/...

Verify that MCP client configs, OAuth tokens, sessions, and temp tokens are correctly encrypted and decrypted using the encrypt package when encrypt.IsEnabled() is true, and that no vault-related paths are written or read.

Breaking changes

  • Yes
  • No

Any deployments that previously relied on Vault-backed secret storage for these table types will no longer have secrets written to or read from Vault. Rows with encryption_status = 'vault' will not be decrypted correctly after this change. A migration to re-encrypt existing vault-backed rows using the standard encryption path is required before deploying.

Security considerations

Vault integration for field-level secret storage has been removed. All sensitive fields (OAuth tokens, MCP connection strings, headers, session tokens, temp tokens, vector store config) are now exclusively encrypted via the encrypt package. Ensure the encrypt package key material is properly secured in your deployment environment, as Vault is no longer available as an alternative secret backend.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR removes Vault-backed storage integration from the configstore encryption system. All credential tables (MCP, OAuth, sessions, temp tokens) now use only encrypt.IsEnabled() for encryption decisions, eliminating vault-first branching, vault secret resolution, and vault cleanup hooks.

Changes

Vault Integration Removal

Layer / File(s) Summary
Table encryption/decryption simplification
framework/configstore/tables/mcp.go, framework/configstore/tables/mcp_per_user_headers.go, framework/configstore/tables/oauth.go, framework/configstore/tables/sessions.go, framework/configstore/tables/temp_token.go, framework/configstore/tables/vectorstore.go
BeforeSave hooks no longer branch on Vault-enabled paths; they encrypt conditionally on encrypt.IsEnabled() only. AfterFind hooks decrypt only when EncryptionStatusEncrypted is set, removing vault-resolution branches. Context imports removed where no longer needed.
Vault cleanup hook removal
framework/configstore/tables/mcp.go, framework/configstore/tables/oauth.go, framework/configstore/tables/sessions.go, framework/configstore/tables/temp_token.go
AfterDelete GORM hooks and exported DeleteVaultSecrets batch-cleanup functions were removed; best-effort async Vault secret deletion on row/batch deletes is gone.
RDB update and delete operations refactoring
framework/configstore/rdb.go
UpdateMCPClientConfig now encrypts headers/connection strings only when encrypt.IsEnabled(); DeleteMCPClientConfig was refactored to lock/fetch rows in-transaction and no longer pre-fetches Vault row IDs or performs post-commit async Vault deletions. DeleteTempTokensByResourceID and DeleteExpiredTempTokens now hard-delete tables.TempToken rows directly without Vault bookkeeping.
Dependency version updates
plugins/modelcatalogresolver/go.mod
Bumped indirect dependencies: cloud.google.com/go/iam to v1.7.0, AWS SDK v2 internal modules (configsources, endpoints/v2) to newer patch versions, and github.com/aws/smithy-go to v1.27.1.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • maximhq/bifrost#4157: Directly reverses vault-backed storage and vault cleanup integration introduced in this earlier PR across the same configstore tables and encryption paths.
  • maximhq/bifrost#3703: Overlaps with MCP client delete/update changes in framework/configstore/rdb.go; both PRs touch DeleteMCPClientConfig and related flows.

Suggested reviewers

  • danpiths
  • roroghost17
  • akshaydeo

Poem

🐰 I hopped through code where vaults once hid,

I nudged encrypt.IsEnabled — now clear and rid.
No async cleanup trails or dual-path song,
One bright encryption lane, simple and strong. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description covers summary, changes, type of change, affected areas, testing instructions, breaking changes, and security considerations, matching the template structure.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main change: removing vault encryption hooks and transitioning to AES-only encryption across multiple GORM tables. It is concise, specific, and reflects the primary objective of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 06-10-chore_dont_store_temp_tokens_in_vault

Comment @coderabbitai help to get the list of available commands and usage tips.

BearTS commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

@BearTS BearTS changed the title chore: dont store temp tokens in vault chore: remove vault encryption backend in favor of AES-only encryption across MCP, OAuth, session, and token tables Jun 10, 2026
@BearTS
BearTS marked this pull request as ready for review June 10, 2026 08:49
@BearTS

BearTS commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

Safe to merge only after verifying that all vault-backed rows have been migrated or that this is being deployed to an environment that never used vault storage; deploying without that migration will cause silent read failures on any existing vault-status rows.

The vault removal and AES-only consolidation are clean across most tables, and the DeleteMCPClientConfig transaction improvement is a genuine correctness win. The gap is that every AfterFind hook now silently passes raw vault-path strings back to callers for any row whose encryption_status is still 'vault' — no error is surfaced, so OAuth tokens, connection strings, and session tokens become silently unusable for those rows. The required migration is explicitly called out in the PR description but is not present in the diff.

framework/configstore/tables/oauth.go and the parallel AfterFind hooks in mcp.go, sessions.go, temp_token.go, and vectorstore.go all share the silent-pass-through behavior for vault-status rows; mcp_per_user_headers.go still has orphaned AfterDelete and DeleteVaultSecrets vault code that was removed from every other table.

Important Files Changed

Filename Overview
framework/configstore/rdb.go Removes vault pre-collection and post-delete goroutines from UpdateMCPClientConfig, DeleteMCPClientConfig, DeleteTempTokensByResourceID, and DeleteExpiredTempTokens; DeleteMCPClientConfig lookup is now correctly inside the transaction with a FOR UPDATE lock
framework/configstore/tables/mcp.go Vault branches removed from BeforeSave and AfterFind, AfterDelete hook removed; AfterFind now only handles EncryptionStatusEncrypted, silently ignoring vault-status rows
framework/configstore/tables/mcp_per_user_headers.go Vault branches removed from BeforeSave/AfterFind; AfterDelete and DeleteVaultSecrets still reference VaultHooks and were not removed (unlike all other affected tables)
framework/configstore/tables/oauth.go Vault branches, AfterDelete hooks, and DeleteVaultSecrets helpers removed from TableOauthToken, TableOauthUserSession, and TableOauthUserToken; AfterFind now silently no-ops for vault-status rows
framework/configstore/tables/sessions.go Vault branches and AfterDelete hook cleanly removed; BeforeSave and AfterFind simplified to AES-only path
framework/configstore/tables/temp_token.go Vault branches, AfterDelete, and DeleteVaultSecrets cleanly removed; AES-only path retained correctly
framework/configstore/tables/vectorstore.go Vault branches and AfterDelete hook cleanly removed; AfterFind simplified to check EncryptionStatusEncrypted only
plugins/modelcatalogresolver/go.mod Routine dependency bumps for cloud.google.com/go/iam, aws-sdk-go-v2, and smithy-go

Reviews (2): Last reviewed commit: "chore: dont store temp tokens in vault" | Re-trigger Greptile

Comment thread framework/configstore/tables/mcp.go Outdated

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
framework/configstore/tables/mcp.go (1)

223-239: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Root cause: legacy EncryptionStatusVault data is no longer readable anywhere these hooks changed.

Across these AfterFind paths, the vault branch was removed without a compatibility gate. Deployments with pre-existing Vault-backed rows will either fail immediately (JSON-bearing rows) or surface vault references as secrets, and any later save can permanently AES-encrypt that reference instead of the real value. Please block release on a migration-safe path: either keep legacy reads until the migration has completed, or make startup/read fail explicitly when any vault row remains.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/configstore/tables/mcp.go` around lines 223 - 239, The AfterFind
hook on TableMCPClient currently only handles "encrypted" rows and drops support
for legacy "vault" rows; restore compatibility by handling the legacy
EncryptionStatusVault case in TableMCPClient.AfterFind (or fail fast if you
choose the migration-enforce route). Specifically, update the AfterFind method
to detect when c.EncryptionStatus equals the legacy vault value (e.g.,
EncryptionStatusVault or "vault") and either (A) perform the legacy Vault
read/decrypt for HeadersJSON and ConnectionString (the same fields currently
handled for "encrypted") before returning, or (B) return a clear, non-ambiguous
error from AfterFind indicating a migration is required so startup/read will
fail fast; ensure you reference and use the same fields (c.HeadersJSON and
c.ConnectionString.Val / c.ConnectionString.IsFromEnv()) and preserve existing
error wrapping behavior when decrypt/read fails.
framework/configstore/rdb.go (1)

1721-1910: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Block update/delete on unmigrated Vault-backed MCP rows.

The PR notes that encryption_status='vault' rows must be migrated before rollout, but these paths now operate on them silently. In UpdateMCPClientConfig, Line 1854 can relabel a Vault-backed row as AES-encrypted even when the read-only connection_string was never rewritten (for example, a normal UI edit with empty ConfigHash). In DeleteMCPClientConfig, Lines 1915-1960 now remove the DB row without the old Vault cleanup, which leaves the external secret orphaned. Please fail fast when existingClient.EncryptionStatus == "vault" so operators get a migration-required error instead of silent state corruption / secret retention.

Suggested guard
 func (s *RDBConfigStore) UpdateMCPClientConfig(ctx context.Context, id string, clientConfig *tables.TableMCPClient) error {
 	return s.DB().Transaction(func(tx *gorm.DB) error {
 		// Find existing client
 		var existingClient tables.TableMCPClient
 		if err := dbForUpdate(tx.WithContext(ctx)).Where("client_id = ?", id).First(&existingClient).Error; err != nil {
 			if errors.Is(err, gorm.ErrRecordNotFound) {
 				return fmt.Errorf("MCP client with id '%s' not found", id)
 			}
 			return err
 		}
+		if existingClient.EncryptionStatus == "vault" {
+			return fmt.Errorf("mcp client %q still uses vault-backed encryption; migrate it before updating", id)
+		}
 
 		// Create a deep copy to avoid modifying the original
 		clientConfigCopy, err := deepCopy(clientConfig)
 		if err != nil {
 			return err
@@
 func (s *RDBConfigStore) DeleteMCPClientConfig(ctx context.Context, id string) error {
 	return s.DB().Transaction(func(tx *gorm.DB) error {
 		// Find existing client
 		var existingClient tables.TableMCPClient
 		if err := dbForUpdate(tx.WithContext(ctx)).Where("client_id = ?", id).First(&existingClient).Error; err != nil {
 			if errors.Is(err, gorm.ErrRecordNotFound) {
 				return fmt.Errorf("MCP client with id '%s' not found", id)
 			}
 			return err
 		}
+		if existingClient.EncryptionStatus == "vault" {
+			return fmt.Errorf("mcp client %q still uses vault-backed encryption; migrate it before deleting", id)
+		}

Also applies to: 1913-1960

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/configstore/rdb.go` around lines 1721 - 1910, The code must fail
fast for Vault-backed rows to avoid relabeling or orphaning secrets: in
UpdateMCPClientConfig (inside the transaction after loading existingClient)
check existingClient.EncryptionStatus == "vault" and return an explicit
migration-required error before any serialization/encryption or before setting
updates so the row is never relabeled; do the same early in
DeleteMCPClientConfig (after loading existingClient) and abort the transaction
with the same migration-required error instead of deleting; ensure these checks
run before any call sites that mutate encryption_status, connection_string, or
call encrypt.Encrypt so Vault rows are preserved for the migration path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@framework/configstore/rdb.go`:
- Around line 1721-1910: The code must fail fast for Vault-backed rows to avoid
relabeling or orphaning secrets: in UpdateMCPClientConfig (inside the
transaction after loading existingClient) check existingClient.EncryptionStatus
== "vault" and return an explicit migration-required error before any
serialization/encryption or before setting updates so the row is never
relabeled; do the same early in DeleteMCPClientConfig (after loading
existingClient) and abort the transaction with the same migration-required error
instead of deleting; ensure these checks run before any call sites that mutate
encryption_status, connection_string, or call encrypt.Encrypt so Vault rows are
preserved for the migration path.

In `@framework/configstore/tables/mcp.go`:
- Around line 223-239: The AfterFind hook on TableMCPClient currently only
handles "encrypted" rows and drops support for legacy "vault" rows; restore
compatibility by handling the legacy EncryptionStatusVault case in
TableMCPClient.AfterFind (or fail fast if you choose the migration-enforce
route). Specifically, update the AfterFind method to detect when
c.EncryptionStatus equals the legacy vault value (e.g., EncryptionStatusVault or
"vault") and either (A) perform the legacy Vault read/decrypt for HeadersJSON
and ConnectionString (the same fields currently handled for "encrypted") before
returning, or (B) return a clear, non-ambiguous error from AfterFind indicating
a migration is required so startup/read will fail fast; ensure you reference and
use the same fields (c.HeadersJSON and c.ConnectionString.Val /
c.ConnectionString.IsFromEnv()) and preserve existing error wrapping behavior
when decrypt/read fails.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 030805cf-9f52-49bc-9cff-97331ed4bc29

📥 Commits

Reviewing files that changed from the base of the PR and between 2b81969 and 4f89a48.

⛔ Files ignored due to path filters (1)
  • plugins/modelcatalogresolver/go.sum is excluded by !**/*.sum
📒 Files selected for processing (8)
  • framework/configstore/rdb.go
  • framework/configstore/tables/mcp.go
  • framework/configstore/tables/mcp_per_user_headers.go
  • framework/configstore/tables/oauth.go
  • framework/configstore/tables/sessions.go
  • framework/configstore/tables/temp_token.go
  • framework/configstore/tables/vectorstore.go
  • plugins/modelcatalogresolver/go.mod

@BearTS
BearTS force-pushed the 06-10-chore_dont_store_temp_tokens_in_vault branch from 4f89a48 to cd6685d Compare June 10, 2026 09:48

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
framework/configstore/tables/mcp.go (1)

223-239: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Backfill legacy vault rows before shipping this read-path change.

Removing the EncryptionStatusVault branch here makes existing config_mcp_clients rows unreadable on rollout. For those rows, HeadersJSON now stays as the vault locator, so the later unmarshal on Line 265 fails, and non-env ConnectionString never resolves either. The PR description already calls out the required migration, but it is not part of this cohort; ship the backfill/re-encryption in the same release (or keep a temporary vault-read fallback) before merging. The same rollout blocker applies to the other table hooks in this PR.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/configstore/tables/mcp.go` around lines 223 - 239, The AfterFind
hook on TableMCPClient currently only handles EncryptionStatusEncrypted and will
break existing rows that still have EncryptionStatusVault; restore a fallback
branch for EncryptionStatusVault or perform an inline vault-read-and-reencrypt
in AfterFind so legacy rows remain readable. Specifically, update AfterFind (the
function name) to detect EncryptionStatusVault, resolve HeadersJSON and
ConnectionString by reading the vault locator (using your vault client) and then
re-encrypt or replace those fields with decrypted values before returning, or
alternatively ensure a migration/backfill job runs in the same release to move
rows from EncryptionStatusVault to EncryptionStatusEncrypted; touch the
HeadersJSON, ConnectionString.Val, and switch the EncryptionStatus flag so later
JSON unmarshal and ConnectionString.IsFromEnv/GetValue logic work as expected.
framework/configstore/rdb.go (2)

1915-1959: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Deleting an MCP client still races concurrent session/token/header inserts.

This transaction deletes existing dependent rows by mcp_client_id, but the create/upsert paths for oauth_user_tokens, oauth_user_sessions, mcp_per_user_header_credentials, and mcp_per_user_header_flows insert by that same string key without first locking or validating the client row. A concurrent auth flow can commit after these DELETEs and leave fresh orphan rows for a client that was just removed.

To close the gap, this needs a cross-file contract: either reference config_mcp_clients.id with FK/cascade, or add a tombstone/disabled state that the create paths check under the same client-row lock before inserting.

As per coding guidelines, framework changes should preserve race-safe behavior and atomic cleanup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/configstore/rdb.go` around lines 1915 - 1959, The delete
transaction still races with concurrent inserts because dependent rows use the
client string key and creators don't lock/validate the client row; fix by either
(A) changing dependent tables to reference tables.TableMCPClient.ID with a
proper FK+cascade (add migration, update models for TableOauthUserToken,
TableOauthUserSession, TableMCPPerUserHeaderCredential,
TableMCPPerUserHeaderFlow and TableVirtualKeyMCPConfig to use mcp_client_id uint
FK) or (B) add a tombstone/disabled boolean on tables.TableMCPClient and make
all create/upsert paths (the code paths that insert into TableOauthUserToken,
TableOauthUserSession, TableMCPPerUserHeaderCredential,
TableMCPPerUserHeaderFlow and TableVirtualKeyMCPConfig) perform a
dbForUpdate(tx.WithContext(ctx)).Where("client_id = ?").First(&client) FOR
UPDATE and check client.Disabled (or return error) before inserting; ensure the
Delete code still locks the client row (use dbForUpdate as shown) and sets
Disabled (or deletes) inside the same transaction so concurrent creators cannot
commit orphan rows.

Source: Coding guidelines


1831-1856: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't rewrite MCP secrets to plaintext while leaving encryption_status stale.

Line 1846 and Line 1892 always persist headers_json / connection_string, but Line 1854 only updates encryption_status when encrypt.IsEnabled(). If an already-encrypted client is edited while encryption is off, this path writes plaintext and preserves the old encrypted marker, so the next AfterFind decryption runs against plaintext and the row becomes unreadable.

Suggested guard
-		if encrypt.IsEnabled() {
+		if encrypt.IsEnabled() {
 			updates["encryption_status"] = encryptionStatusEncrypted
+		} else if existingClient.EncryptionStatus == encryptionStatusEncrypted {
+			return fmt.Errorf("cannot update MCP client %q while encryption is disabled because stored secrets are still marked encrypted", id)
 		}

Based on learnings, framework/configstore/rdb.go and framework/configstore/tables/mcp.go must keep encryption_status aligned with whether MCP fields are actually encrypted, and AfterFind uses that status to decide decryption.

Also applies to: 1878-1893

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/configstore/rdb.go` around lines 1831 - 1856, The code writes
headers_json/connection_string but only sets updates["encryption_status"] when
encrypt.IsEnabled(), which can leave the DB marker stale; change the updates map
logic so encryption_status is explicitly set to encrypted when
encrypt.IsEnabled() and explicitly set to the non-encrypted state when
encrypt.IsEnabled() is false (e.g. updates["encryption_status"] =
encrypt.IsEnabled() ? encryptionStatusEncrypted :
<unencrypted-status-constant>), and apply the same change to the other block
that updates "connection_string" so encryption_status always reflects whether
the stored fields are actually encrypted (use the existing encrypt.IsEnabled(),
the updates map, "headers_json"/"connection_string", and the
encryptionStatusEncrypted constant as references).

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@framework/configstore/rdb.go`:
- Around line 1915-1959: The delete transaction still races with concurrent
inserts because dependent rows use the client string key and creators don't
lock/validate the client row; fix by either (A) changing dependent tables to
reference tables.TableMCPClient.ID with a proper FK+cascade (add migration,
update models for TableOauthUserToken, TableOauthUserSession,
TableMCPPerUserHeaderCredential, TableMCPPerUserHeaderFlow and
TableVirtualKeyMCPConfig to use mcp_client_id uint FK) or (B) add a
tombstone/disabled boolean on tables.TableMCPClient and make all create/upsert
paths (the code paths that insert into TableOauthUserToken,
TableOauthUserSession, TableMCPPerUserHeaderCredential,
TableMCPPerUserHeaderFlow and TableVirtualKeyMCPConfig) perform a
dbForUpdate(tx.WithContext(ctx)).Where("client_id = ?").First(&client) FOR
UPDATE and check client.Disabled (or return error) before inserting; ensure the
Delete code still locks the client row (use dbForUpdate as shown) and sets
Disabled (or deletes) inside the same transaction so concurrent creators cannot
commit orphan rows.
- Around line 1831-1856: The code writes headers_json/connection_string but only
sets updates["encryption_status"] when encrypt.IsEnabled(), which can leave the
DB marker stale; change the updates map logic so encryption_status is explicitly
set to encrypted when encrypt.IsEnabled() and explicitly set to the
non-encrypted state when encrypt.IsEnabled() is false (e.g.
updates["encryption_status"] = encrypt.IsEnabled() ? encryptionStatusEncrypted :
<unencrypted-status-constant>), and apply the same change to the other block
that updates "connection_string" so encryption_status always reflects whether
the stored fields are actually encrypted (use the existing encrypt.IsEnabled(),
the updates map, "headers_json"/"connection_string", and the
encryptionStatusEncrypted constant as references).

In `@framework/configstore/tables/mcp.go`:
- Around line 223-239: The AfterFind hook on TableMCPClient currently only
handles EncryptionStatusEncrypted and will break existing rows that still have
EncryptionStatusVault; restore a fallback branch for EncryptionStatusVault or
perform an inline vault-read-and-reencrypt in AfterFind so legacy rows remain
readable. Specifically, update AfterFind (the function name) to detect
EncryptionStatusVault, resolve HeadersJSON and ConnectionString by reading the
vault locator (using your vault client) and then re-encrypt or replace those
fields with decrypted values before returning, or alternatively ensure a
migration/backfill job runs in the same release to move rows from
EncryptionStatusVault to EncryptionStatusEncrypted; touch the HeadersJSON,
ConnectionString.Val, and switch the EncryptionStatus flag so later JSON
unmarshal and ConnectionString.IsFromEnv/GetValue logic work as expected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: dc6cdb93-8fa5-4a8a-bf2a-92f841daf37a

📥 Commits

Reviewing files that changed from the base of the PR and between 4f89a48 and cd6685d.

⛔ Files ignored due to path filters (1)
  • plugins/modelcatalogresolver/go.sum is excluded by !**/*.sum
📒 Files selected for processing (8)
  • framework/configstore/rdb.go
  • framework/configstore/tables/mcp.go
  • framework/configstore/tables/mcp_per_user_headers.go
  • framework/configstore/tables/oauth.go
  • framework/configstore/tables/sessions.go
  • framework/configstore/tables/temp_token.go
  • framework/configstore/tables/vectorstore.go
  • plugins/modelcatalogresolver/go.mod

@BearTS BearTS changed the title chore: remove vault encryption backend in favor of AES-only encryption across MCP, OAuth, session, and token tables chore: remove vault encryption hooks from all table GORM hooks in favor of AES-only encryption Jun 10, 2026
@BearTS BearTS changed the title chore: remove vault encryption hooks from all table GORM hooks in favor of AES-only encryption chore: remove vault encryption hooks from certain GORM tables in favor of AES-only encryption Jun 10, 2026

Pratham-Mishra04 commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Merge activity

  • Jun 11, 7:41 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jun 11, 7:41 AM UTC: @Pratham-Mishra04 merged this pull request with Graphite.

@Pratham-Mishra04
Pratham-Mishra04 merged commit a68e9df into dev Jun 11, 2026
15 checks passed
@Pratham-Mishra04
Pratham-Mishra04 deleted the 06-10-chore_dont_store_temp_tokens_in_vault branch June 11, 2026 07:41
akshaydeo pushed a commit that referenced this pull request Jun 12, 2026
…r of AES-only encryption (#4245)

## Summary

Removes Vault-based secret storage from all sensitive-field GORM hooks and related database operations, leaving only the standard `encrypt` package path for at-rest encryption. This eliminates the dual-path complexity that existed for MCP client configs, OAuth tokens, sessions, temp tokens, and vector store configs.

## Changes

- Removed all `VaultIsEnabled()` branches from `BeforeSave`, `AfterFind`, and `AfterDelete` hooks across `TableMCPClient`, `TableMCPPerUserHeaderCredential`, `TableOauthToken`, `TableOauthUserSession`, `TableOauthUserToken`, `SessionsTable`, `TempToken`, and `TableVectorStoreConfig`.
- Removed `AfterDelete` vault cleanup hooks from all affected table types.
- Removed `DeleteVaultSecrets` helper methods from `TableOauthUserToken`, `TableOauthUserSession`, and `TempToken`.
- Removed pre/post-transaction vault compensation logic (`vaultStoredPaths`, `vaultRemovePaths`) from `UpdateMCPClientConfig` in `rdb.go`.
- Removed the pre-transaction vault ID collection and post-transaction goroutine vault cleanup from `DeleteMCPClientConfig`, moving the record lookup inside the transaction instead.
- Removed vault ID pre-collection and post-delete goroutine cleanup from `DeleteTempTokensByResourceID` and `DeleteExpiredTempTokens`.
- Bumped `cloud.google.com/go/iam`, `aws-sdk-go-v2`, and `smithy-go` dependency versions in the `modelcatalogresolver` plugin.

## Type of change

- [ ] Bug fix
- [ ] Feature
- [x] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [x] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./framework/configstore/...
go test ./framework/configstore/tables/...
```

Verify that MCP client configs, OAuth tokens, sessions, and temp tokens are correctly encrypted and decrypted using the `encrypt` package when `encrypt.IsEnabled()` is true, and that no vault-related paths are written or read.

## Breaking changes

- [x] Yes
- [ ] No

Any deployments that previously relied on Vault-backed secret storage for these table types will no longer have secrets written to or read from Vault. Rows with `encryption_status = 'vault'` will not be decrypted correctly after this change. A migration to re-encrypt existing vault-backed rows using the standard encryption path is required before deploying.

## Security considerations

Vault integration for field-level secret storage has been removed. All sensitive fields (OAuth tokens, MCP connection strings, headers, session tokens, temp tokens, vector store config) are now exclusively encrypted via the `encrypt` package. Ensure the `encrypt` package key material is properly secured in your deployment environment, as Vault is no longer available as an alternative secret backend.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants