Skip to content

revert: TableVirtualKey.Value from SecretVar back to string, dropping env/vault reference support - #4665

Merged
akshaydeo merged 1 commit into
devfrom
06-24-revert_vk_from_secretvar_to_string
Jun 24, 2026
Merged

revert: TableVirtualKey.Value from SecretVar back to string, dropping env/vault reference support#4665
akshaydeo merged 1 commit into
devfrom
06-24-revert_vk_from_secretvar_to_string

Conversation

@BearTS

@BearTS BearTS commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

TableVirtualKey.Value was previously typed as schemas.SecretVar to support env.X and vault.X references that resolve at read time. This abstraction added complexity throughout the codebase without sufficient benefit for virtual keys specifically. This PR simplifies TableVirtualKey.Value to a plain string, with env.X references now resolved explicitly at the config-merge layer before being stored.

Changes

  • TableVirtualKey.Value field changed from schemas.SecretVar to string across the Go backend and TypeScript frontend
  • BeforeSave and AfterFind GORM hooks updated to use encryptString/decryptString instead of encryptSecretVar/decryptSecretVar
  • Vault self-managed interface methods (VaultPathKey, VaultStoreSelfManaged) removed from TableVirtualKey since vault-sourced virtual key values are no longer supported
  • env.X references in config file virtual key values are now resolved explicitly via envutils.ProcessEnvValue during mergeGovernanceConfig, replacing the implicit resolution that SecretVar provided
  • GenerateVirtualKeyHash updated to hash vk.Value directly instead of calling vk.Value.GetValue()
  • CreateVirtualKeyRequest in the HTTP handler no longer accepts a caller-supplied value field; the value is always generated server-side
  • All in-memory governance store operations (rebuildInMemoryStructures, CreateVirtualKeyInMemory, UpdateVirtualKeyInMemory) updated to key on vk.Value directly
  • UI VirtualKey type updated so value is string instead of string | SecretVar; the resolveVirtualKeyValue helper function removed from all call sites and deleted
  • virtualkey_secretvar_test.go deleted as the SecretVar-specific behavior it tested no longer applies

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/...
go test ./plugins/governance/...
go test ./transports/bifrost-http/...

cd ui
pnpm i
pnpm build

Verify that virtual keys created via the API or config file are stored, encrypted, and retrieved correctly. Confirm that env.X values in config files are resolved to their plaintext equivalents before being persisted.

Breaking changes

  • Yes
  • No

The CreateVirtualKeyRequest no longer accepts a value field. Callers that previously supplied a custom literal or env.X value via the API must now set the value through the config file or accept the server-generated value. Config file env.X references for virtual key values continue to work but are resolved at sync time rather than stored as references.

Security considerations

Virtual key values are still encrypted at rest using the existing encryptString/decryptString path and hashed via SHA-256 for lookup. Removing the SecretVar indirection eliminates a code path where a vault reference could be stored in the value column and resolved on every read, reducing the surface area for secret leakage through unresolved references.

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 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@BearTS, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 29 minutes and 33 seconds. Learn how PR review limits work.

To continue reviewing without waiting, enable usage-based billing in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: eaa0cdcf-c7a1-46e7-8443-adde97bf330d

📥 Commits

Reviewing files that changed from the base of the PR and between d536943 and 5284d5e.

📒 Files selected for processing (26)
  • framework/configstore/clientconfig.go
  • framework/configstore/encryption_test.go
  • framework/configstore/migrations_test.go
  • framework/configstore/rdb_deadlock_postgres_test.go
  • framework/configstore/rdb_mcp_sessions_test.go
  • framework/configstore/rdb_test.go
  • framework/configstore/tables/encryption_test.go
  • framework/configstore/tables/virtualkey.go
  • framework/configstore/tables/virtualkey_secretvar_test.go
  • framework/logstore/asyncjob_test.go
  • plugins/governance/store.go
  • plugins/governance/store_test.go
  • plugins/governance/test_utils.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/governance_test.go
  • transports/bifrost-http/handlers/list_models_vk_test.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/server.go
  • ui/app/workspace/mcp-registry/views/mcpUsageGuide/commandBuilders.ts
  • ui/app/workspace/mcp-registry/views/mcpUsageGuide/mcpUsageGuideSheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx
  • ui/components/prompts/components/apiKeySelectorView.tsx
  • ui/components/prompts/fragments/settingsPanel.tsx
  • ui/lib/types/governance.ts
📝 Walkthrough

Walkthrough

TableVirtualKey.Value is changed from schemas.SecretVar to a plain string across the entire codebase. Vault integration methods are removed; GORM hooks, governance store in-memory keying, HTTP handlers, server lifecycle, config reconciliation, and UI types are updated accordingly. resolveVirtualKeyValue is deleted from the UI. All test fixtures are updated to match the new shape.

Changes

SecretVar Removal from VirtualKey.Value

Layer / File(s) Summary
TableVirtualKey model field type and GORM hooks
framework/configstore/tables/virtualkey.go
Value field redefined as string; VaultPathKey and VaultStoreSelfManaged methods deleted; BeforeSave hashes and encrypts using encryptString; AfterFind decrypts via decryptString.
Hash computation and config reconciliation
framework/configstore/clientconfig.go, transports/bifrost-http/lib/config.go
GenerateVirtualKeyHash hashes vk.Value directly; mergeGovernanceConfig update/create paths replaced SecretVar env/vault checks with envutils.ProcessEnvValue and governance.GenerateVirtualKey.
Governance store keying and HTTP handler VK lifecycle
plugins/governance/store.go, transports/bifrost-http/handlers/governance.go
In-memory store keying uses vk.Value directly; create handler assigns GenerateVirtualKey() to vk.Value; rotation handler compares plain strings; CreateVirtualKeyRequest.Value field removed.
Server lifecycle and MCP server cache keying
transports/bifrost-http/server/server.go, transports/bifrost-http/handlers/mcpserver.go
ReloadVirtualKey and RemoveVirtualKey pass vk.Value directly to DeleteVKMCPServer; SyncVKMCPServer uses vk.Value as cache map key.
UI governance types and resolveVirtualKeyValue removal
ui/lib/types/governance.ts, ui/app/workspace/mcp-registry/views/mcpUsageGuide/commandBuilders.ts, ui/app/workspace/mcp-registry/views/mcpUsageGuide/mcpUsageGuideSheet.tsx, ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx, ui/components/prompts/...
VirtualKey.value narrowed to string; resolveVirtualKeyValue helper deleted; all command builders, MCP guide sheet, VK table, API key selector, and settings panel use vk.value directly.
Table-layer encryption and virtualkey_secretvar test removal
framework/configstore/tables/encryption_test.go, framework/configstore/tables/virtualkey_secretvar_test.go
Encryption round-trip tests updated to plain string fixtures; virtualkey_secretvar_test.go deleted (183 lines covering env-sourced, literal, hash stability, JSON marshal, vault rotation tests).
Configstore RDB and migration test fixture updates
framework/configstore/rdb_test.go, framework/configstore/migrations_test.go, framework/configstore/rdb_deadlock_postgres_test.go, framework/configstore/rdb_mcp_sessions_test.go, framework/configstore/encryption_test.go
All VK test fixtures replace *schemas.NewSecretVar(...) with plain strings; assertions replace .GetValue() with direct string comparisons.
Governance, handler, and server test fixture updates
plugins/governance/store_test.go, plugins/governance/test_utils.go, transports/bifrost-http/handlers/governance_test.go, transports/bifrost-http/handlers/list_models_vk_test.go, framework/logstore/asyncjob_test.go
Rotate, create, and seed fixtures across governance store and HTTP handler tests updated to plain string Value fields and direct string comparisons.
Config reconciliation test fixture updates
transports/bifrost-http/lib/config_test.go
makeVirtualKey* helpers and ~100 hash unit, SQLite reconciliation, and lifecycle test fixtures updated to set Value as raw strings.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • maximhq/bifrost#4398: Modifies framework/configstore/tables/virtualkey.go to alter vault-backed behavior in BeforeSave/AfterFind, directly overlapping with this PR's removal of vault integration methods from the same file.
  • maximhq/bifrost#4504: Modifies GenerateVirtualKeyHash in clientconfig.go and TableVirtualKey.Value encryption hooks in virtualkey.go, switching hash input handling between raw Value and SecretVar-resolved plaintext.

Suggested reviewers

  • akshaydeo
  • danpiths
  • roroghost17

Poem

🐇 No more wrappers, no more fuss,
The Value's just a string for us!
SecretVar has hopped away,
Plain strings rule the DB today.
Hash it raw and store it neat —
Simpler code is hard to beat! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description covers the required sections well, including summary, changes, testing, breaking changes, security, and checklist.
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 primary change: reverting TableVirtualKey.Value to a string and removing env/vault reference support.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 06-24-revert_vk_from_secretvar_to_string

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

BearTS commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

@BearTS BearTS changed the title revert: vk from secretVar to string refactor: revert TableVirtualKey.Value from SecretVar back to string, dropping env/vault reference support Jun 24, 2026
@BearTS
BearTS marked this pull request as ready for review June 24, 2026 11:40

@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.

Actionable comments posted: 2

🤖 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.

Inline comments:
In `@transports/bifrost-http/handlers/governance.go`:
- Around line 145-147: The CreateVirtualKeyRequest path is still accepting
legacy "value" input silently, so update the governance handler to reject
requests containing that field instead of proceeding with generated keys; locate
the request decoding and virtual key creation flow in CreateVirtualKeyRequest
and the associated handler, and either switch to strict JSON decoding with
disallowed unknown fields or explicitly detect a provided value and return a 400
before key generation.

In `@transports/bifrost-http/lib/config.go`:
- Around line 2251-2270: Recompute the virtual key hash only after the value
normalization in configData.Governance.VirtualKeys, because fileVKHash is
currently derived before env resolution and fallback key generation, so
ConfigHash can end up reflecting env.FOO or a placeholder instead of the stored
effective value. Update the flow around the virtual key processing in the
existing loop (including the GenerateVirtualKeyHash and ConfigHash assignment
logic) so Value is first resolved via envutils.ProcessEnvValue or generated with
governance.GenerateVirtualKey, then the hash is regenerated from the final Value
before persisting or comparing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 36d8174d-8eeb-4014-88a6-99f85bd6adc9

📥 Commits

Reviewing files that changed from the base of the PR and between e5349f0 and d536943.

📒 Files selected for processing (26)
  • framework/configstore/clientconfig.go
  • framework/configstore/encryption_test.go
  • framework/configstore/migrations_test.go
  • framework/configstore/rdb_deadlock_postgres_test.go
  • framework/configstore/rdb_mcp_sessions_test.go
  • framework/configstore/rdb_test.go
  • framework/configstore/tables/encryption_test.go
  • framework/configstore/tables/virtualkey.go
  • framework/configstore/tables/virtualkey_secretvar_test.go
  • framework/logstore/asyncjob_test.go
  • plugins/governance/store.go
  • plugins/governance/store_test.go
  • plugins/governance/test_utils.go
  • transports/bifrost-http/handlers/governance.go
  • transports/bifrost-http/handlers/governance_test.go
  • transports/bifrost-http/handlers/list_models_vk_test.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/server.go
  • ui/app/workspace/mcp-registry/views/mcpUsageGuide/commandBuilders.ts
  • ui/app/workspace/mcp-registry/views/mcpUsageGuide/mcpUsageGuideSheet.tsx
  • ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx
  • ui/components/prompts/components/apiKeySelectorView.tsx
  • ui/components/prompts/fragments/settingsPanel.tsx
  • ui/lib/types/governance.ts
💤 Files with no reviewable changes (1)
  • framework/configstore/tables/virtualkey_secretvar_test.go

Comment thread transports/bifrost-http/handlers/governance.go
Comment thread transports/bifrost-http/lib/config.go
@BearTS BearTS changed the title refactor: revert TableVirtualKey.Value from SecretVar back to string, dropping env/vault reference support revert: TableVirtualKey.Value from SecretVar back to string, dropping env/vault reference support Jun 24, 2026
@greptile-apps

greptile-apps Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

Safe to merge with awareness of one behavioral change: env-var-sourced VK values are resolved once at first sync and do not update if the env var is later rotated, unless another VK field changes concurrently.

The config hash used for change-detection is computed from the raw config-file entry (env.MY_VK) before env var resolution occurs. On every subsequent sync, the file still contains env.MY_VK, the hash matches, and the re-resolution is skipped. A user who rotates the referenced env var and restarts the server will silently keep the old plaintext value in the DB. The previous SecretVar design resolved on every DB read, so this is a real behavioral regression for that use case. All other changes—string-typed field, simplified encryption hooks, vault removal, UI cleanup—are mechanical and correct.

transports/bifrost-http/lib/config.go — the env var hash/resolution ordering; transports/bifrost-http/lib/config_test.go — no test exercises the new env.X resolution path for virtual keys

Important Files Changed

Filename Overview
framework/configstore/tables/virtualkey.go Cleaned up: Value field changed from SecretVar to string; BeforeSave/AfterFind updated to encryptString/decryptString; VaultPathKey and VaultStoreSelfManaged methods removed. Logic is straightforward and correct.
transports/bifrost-http/lib/config.go Env var resolution for VK values moved here explicitly, but fileVKHash is computed before resolution, causing stale values when env vars change between syncs without other config field changes.
plugins/governance/store.go In-memory store operations simplified to use vk.Value directly instead of vk.Value.GetValue(); logic is correct including the rotation-case Range lookup.
transports/bifrost-http/handlers/governance.go CreateVirtualKeyRequest value field removed; VK creation always uses server-generated value; rotation logic simplified. Correctly handles the breaking change.
ui/lib/types/governance.ts VirtualKey.value typed as plain string; resolveVirtualKeyValue helper and SecretVar union removed; CreateVirtualKeyRequest.value field removed. Clean simplification.
transports/bifrost-http/lib/config_test.go Tests updated for the new string-typed VK value. No coverage for the new env.X resolution path in mergeGovernanceConfig for virtual keys.
framework/configstore/clientconfig.go GenerateVirtualKeyHash updated to hash vk.Value directly; straightforward change with no logic issues.
transports/bifrost-http/server/server.go ReloadVirtualKey and RemoveVirtualKey updated to use vk.Value directly for MCP server key lookup; correct.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CF as Config File
    participant MG as mergeGovernanceConfig
    participant EU as envutils.ProcessEnvValue
    participant DB as Database (GORM)
    participant IM as In-Memory Store

    CF->>MG: "VirtualKey{value: "env.MY_VK"}"
    MG->>MG: "GenerateVirtualKeyHash(rawEntry)<br/>(hashes "env.MY_VK" literal)"
    alt value starts with "env."
        MG->>EU: ProcessEnvValue("env.MY_VK")
        EU-->>MG: "sk-bf-resolved-value"
        MG->>MG: "Value = "sk-bf-resolved-value""
    end
    MG->>MG: Validate VirtualKeyPrefix
    MG->>DB: "CreateVirtualKey / UpdateVirtualKey<br/>(BeforeSave: HashSHA256 + encryptString)"
    DB-->>MG: "stored with EncryptionStatus=encrypted"
    MG->>IM: "Store(vk.Value, &vk)"

    note over MG,DB: On next sync: fileVKHash == storedHash<br/>(both hash "env.MY_VK" literal)<br/>update skipped, DB value stays stale<br/>if env var changes
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant CF as Config File
    participant MG as mergeGovernanceConfig
    participant EU as envutils.ProcessEnvValue
    participant DB as Database (GORM)
    participant IM as In-Memory Store

    CF->>MG: "VirtualKey{value: "env.MY_VK"}"
    MG->>MG: "GenerateVirtualKeyHash(rawEntry)<br/>(hashes "env.MY_VK" literal)"
    alt value starts with "env."
        MG->>EU: ProcessEnvValue("env.MY_VK")
        EU-->>MG: "sk-bf-resolved-value"
        MG->>MG: "Value = "sk-bf-resolved-value""
    end
    MG->>MG: Validate VirtualKeyPrefix
    MG->>DB: "CreateVirtualKey / UpdateVirtualKey<br/>(BeforeSave: HashSHA256 + encryptString)"
    DB-->>MG: "stored with EncryptionStatus=encrypted"
    MG->>IM: "Store(vk.Value, &vk)"

    note over MG,DB: On next sync: fileVKHash == storedHash<br/>(both hash "env.MY_VK" literal)<br/>update skipped, DB value stays stale<br/>if env var changes
Loading

Comments Outside Diff (1)

  1. transports/bifrost-http/lib/config.go, line 2231-2248 (link)

    P1 Env-var changes to VK values silently go stale after first sync

    GenerateVirtualKeyHash is called at line 2231 with the raw config entry, which still holds the literal env.MY_VK string at that point (env resolution happens later in the diff at lines 2256–2263). The stored configHash is therefore the SHA-256 of "env.MY_VK".

    On every subsequent sync the config file still reads env.MY_VK, so fileVKHash == existingVirtualKey.ConfigHash and the if forceFileSync || existingVirtualKey.ConfigHash != fileVKHash branch is skipped entirely. The DB retains the value that was resolved at first-sync time; any change to the MY_VK env var is silently ignored until some other field of that VK is also changed.

    This is a behavioral regression from the old SecretVar path, where the reference was stored verbatim and GetValue() resolved it on every DB read (i.e., on every restart the updated env var was picked up automatically). The PR description notes that values are "resolved at sync time", but the hash mechanism means they are only resolved at first-sync time or when another field changes. A user who rotates MY_VK and restarts the server will keep the old plaintext value in the DB without any warning.

Reviews (2): Last reviewed commit: "revert: vk from secretVar to string" | Re-trigger Greptile

Comment thread framework/configstore/tables/virtualkey.go
Comment thread transports/bifrost-http/lib/config.go
Comment thread framework/configstore/tables/virtualkey.go
@BearTS
BearTS force-pushed the 06-24-revert_vk_from_secretvar_to_string branch from d536943 to 5284d5e Compare June 24, 2026 12:00
@akshaydeo
akshaydeo force-pushed the 06-24-revert_vk_from_secretvar_to_string branch from 5284d5e to d536943 Compare June 24, 2026 12:05

akshaydeo commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • Jun 24, 12:07 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jun 24, 12:08 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo merged commit 6ba8a37 into dev Jun 24, 2026
15 of 19 checks passed
@akshaydeo
akshaydeo deleted the 06-24-revert_vk_from_secretvar_to_string branch June 24, 2026 12:08
@greptile-apps greptile-apps Bot mentioned this pull request Jun 25, 2026
18 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Jul 3, 2026
18 tasks
akhsaul pushed a commit to akhsaul/bifrost that referenced this pull request Aug 27, 2026
…opping env/vault reference support (maximhq#4665)

## Summary

`TableVirtualKey.Value` was previously typed as `schemas.SecretVar` to support `env.X` and `vault.X` references that resolve at read time. This abstraction added complexity throughout the codebase without sufficient benefit for virtual keys specifically. This PR simplifies `TableVirtualKey.Value` to a plain `string`, with `env.X` references now resolved explicitly at the config-merge layer before being stored.

## Changes

- `TableVirtualKey.Value` field changed from `schemas.SecretVar` to `string` across the Go backend and TypeScript frontend
- `BeforeSave` and `AfterFind` GORM hooks updated to use `encryptString`/`decryptString` instead of `encryptSecretVar`/`decryptSecretVar`
- Vault self-managed interface methods (`VaultPathKey`, `VaultStoreSelfManaged`) removed from `TableVirtualKey` since vault-sourced virtual key values are no longer supported
- `env.X` references in config file virtual key values are now resolved explicitly via `envutils.ProcessEnvValue` during `mergeGovernanceConfig`, replacing the implicit resolution that `SecretVar` provided
- `GenerateVirtualKeyHash` updated to hash `vk.Value` directly instead of calling `vk.Value.GetValue()`
- `CreateVirtualKeyRequest` in the HTTP handler no longer accepts a caller-supplied `value` field; the value is always generated server-side
- All in-memory governance store operations (`rebuildInMemoryStructures`, `CreateVirtualKeyInMemory`, `UpdateVirtualKeyInMemory`) updated to key on `vk.Value` directly
- UI `VirtualKey` type updated so `value` is `string` instead of `string | SecretVar`; the `resolveVirtualKeyValue` helper function removed from all call sites and deleted
- `virtualkey_secretvar_test.go` deleted as the `SecretVar`-specific behavior it tested no longer applies

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./framework/configstore/...
go test ./framework/configstore/tables/...
go test ./plugins/governance/...
go test ./transports/bifrost-http/...

cd ui
pnpm i
pnpm build
```

Verify that virtual keys created via the API or config file are stored, encrypted, and retrieved correctly. Confirm that `env.X` values in config files are resolved to their plaintext equivalents before being persisted.

## Breaking changes

- [x] Yes
- [ ] No

The `CreateVirtualKeyRequest` no longer accepts a `value` field. Callers that previously supplied a custom literal or `env.X` value via the API must now set the value through the config file or accept the server-generated value. Config file `env.X` references for virtual key values continue to work but are resolved at sync time rather than stored as references.

## Security considerations

Virtual key values are still encrypted at rest using the existing `encryptString`/`decryptString` path and hashed via SHA-256 for lookup. Removing the `SecretVar` indirection eliminates a code path where a vault reference could be stored in the value column and resolved on every read, reducing the surface area for secret leakage through unresolved references.

## 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
occcat pushed a commit to occcat/bifrost that referenced this pull request Sep 2, 2026
…opping env/vault reference support (maximhq#4665)

## Summary

`TableVirtualKey.Value` was previously typed as `schemas.SecretVar` to support `env.X` and `vault.X` references that resolve at read time. This abstraction added complexity throughout the codebase without sufficient benefit for virtual keys specifically. This PR simplifies `TableVirtualKey.Value` to a plain `string`, with `env.X` references now resolved explicitly at the config-merge layer before being stored.

## Changes

- `TableVirtualKey.Value` field changed from `schemas.SecretVar` to `string` across the Go backend and TypeScript frontend
- `BeforeSave` and `AfterFind` GORM hooks updated to use `encryptString`/`decryptString` instead of `encryptSecretVar`/`decryptSecretVar`
- Vault self-managed interface methods (`VaultPathKey`, `VaultStoreSelfManaged`) removed from `TableVirtualKey` since vault-sourced virtual key values are no longer supported
- `env.X` references in config file virtual key values are now resolved explicitly via `envutils.ProcessEnvValue` during `mergeGovernanceConfig`, replacing the implicit resolution that `SecretVar` provided
- `GenerateVirtualKeyHash` updated to hash `vk.Value` directly instead of calling `vk.Value.GetValue()`
- `CreateVirtualKeyRequest` in the HTTP handler no longer accepts a caller-supplied `value` field; the value is always generated server-side
- All in-memory governance store operations (`rebuildInMemoryStructures`, `CreateVirtualKeyInMemory`, `UpdateVirtualKeyInMemory`) updated to key on `vk.Value` directly
- UI `VirtualKey` type updated so `value` is `string` instead of `string | SecretVar`; the `resolveVirtualKeyValue` helper function removed from all call sites and deleted
- `virtualkey_secretvar_test.go` deleted as the `SecretVar`-specific behavior it tested no longer applies

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./framework/configstore/...
go test ./framework/configstore/tables/...
go test ./plugins/governance/...
go test ./transports/bifrost-http/...

cd ui
pnpm i
pnpm build
```

Verify that virtual keys created via the API or config file are stored, encrypted, and retrieved correctly. Confirm that `env.X` values in config files are resolved to their plaintext equivalents before being persisted.

## Breaking changes

- [x] Yes
- [ ] No

The `CreateVirtualKeyRequest` no longer accepts a `value` field. Callers that previously supplied a custom literal or `env.X` value via the API must now set the value through the config file or accept the server-generated value. Config file `env.X` references for virtual key values continue to work but are resolved at sync time rather than stored as references.

## Security considerations

Virtual key values are still encrypted at rest using the existing `encryptString`/`decryptString` path and hashed via SHA-256 for lookup. Removing the `SecretVar` indirection eliminates a code path where a vault reference could be stored in the value column and resolved on every read, reducing the surface area for secret leakage through unresolved references.

## 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