Skip to content

feat: add AllowAllKeys flag and fix virtual key config semantics#2008

Closed
Pratham-Mishra04 wants to merge 1 commit intographite-base/2008from
03-10-fix_backwards_compact_with_config.json_loading_for_vk_changes
Closed

feat: add AllowAllKeys flag and fix virtual key config semantics#2008
Pratham-Mishra04 wants to merge 1 commit intographite-base/2008from
03-10-fix_backwards_compact_with_config.json_loading_for_vk_changes

Conversation

@Pratham-Mishra04
Copy link
Copy Markdown
Collaborator

Summary

Implements explicit allow/deny semantics for virtual key configurations to replace implicit behaviors. Previously, absent configuration fields had inconsistent behavior - some defaulted to allow-all, others to deny-all. This change establishes clear semantics where explicit empty arrays mean deny-all, while absent fields temporarily default to allow-all with deprecation warnings.

Changes

  • Breaking change: Empty arrays ([]) for provider_configs, mcp_configs, and allowed_keys now explicitly deny access instead of allowing all
  • Semantic fix: Absent allowed_keys and tools_to_execute fields now allow all (previously buggy deny-all) with deprecation warnings
  • Added AllowAllKeys boolean field to VirtualKeyProviderConfigHashInput and related hash generation logic
  • Enhanced JSON unmarshaling to distinguish between absent fields (nil pointers) and explicit empty arrays
  • Updated governance resolver to explicitly clear key filters when AllowAllKeys is true
  • Added automatic expansion of absent top-level configs (provider_configs/mcp_configs) to all configured providers/clients during config merge
  • Added comprehensive deprecation warnings for implicit allow-all behaviors

Type of change

  • Feature
  • Bug fix (fixes inconsistent absent field behavior)

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Plugins
  • UI (Next.js)

How to test

Test the new explicit semantics with various virtual key configurations:

# Test core functionality
go test ./framework/configstore/...
go test ./plugins/governance/...
go test ./transports/bifrost-http/lib/...

# Test with config variations:
# 1. provider_configs: [] (should deny all providers)
# 2. provider_configs absent (should allow all with warning)
# 3. allowed_keys: [] (should deny all keys)
# 4. allowed_keys absent (should allow all with warning)
# 5. allowed_keys: ["*"] (should allow all explicitly)

# UI tests
cd ui
pnpm test
pnpm build

Verify deprecation warnings appear in logs when using absent fields, and that explicit empty arrays properly deny access.

Breaking changes

  • Yes

Migration required for configurations using explicit empty arrays:

Configuration Old Behavior New Behavior Migration
provider_configs: [] Allow all providers Deny all providers List providers explicitly or remove field
allowed_keys: [] Allow all keys Deny all keys Use ["*"] for allow-all or list specific keys
mcp_configs: [] Allow all MCP clients Deny all MCP clients List clients explicitly or remove field

Absent fields now consistently allow-all with deprecation warnings. In the next major version, both absent and [] will mean deny-all.

Security considerations

This change improves security by making access controls explicit and preventing accidental over-permissioning through empty arrays. The temporary allow-all behavior for absent fields maintains backward compatibility while encouraging explicit configuration through deprecation warnings.

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

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Copy Markdown
Collaborator Author

Pratham-Mishra04 commented Mar 10, 2026

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 10, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Explicit allow-all vs deny-all semantics for virtual-key provider and MCP configs; absent entries are auto-expanded with deprecation warnings during governance config loading.
  • Bug Fixes

    • Deterministic hashing now includes the allow-all flag to improve change detection.
    • Corrected handling of absent vs empty lists for keys and tools (wildcard, empty-list and precedence behaviors clarified).
  • Documentation

    • Added migration guide, breaking-change notes, and deprecation warnings.
  • Style/Chores

    • Logging initialization adjusted and UI text clarified for "Allow All Tools".

Walkthrough

Adds explicit allow-vs-deny semantics for virtual key provider and MCP configs, persists an AllowAllKeys flag into provider config hashing, expands governance virtual key entries during config load with deprecation warnings, wires a package logger for DB tables, and includes minor UI and test import tweaks.

Changes

Cohort / File(s) Summary
Virtual key hashing
framework/configstore/clientconfig.go
Adds AllowAllKeys bool to VirtualKeyProviderConfigHashInput and includes it when generating virtual key provider config hashes.
DB/API config parsing & defaults
framework/configstore/tables/virtualkey.go
UnmarshalJSON updated to distinguish absent vs present for provider allowed_keys and MCP tools_to_execute (*[]string, *bool), support wildcard "*", treat explicit empty arrays as deny-all, emit deprecation warnings, and map config-file vs DB/API formats to internal Keys.
Governance preprocess & merge logic
transports/bifrost-http/lib/config.go
Adds preprocessGovernanceVirtualKeys(ctx, config, configData) to expand absent provider_configs/mcp_configs during governance load/merge with deprecation warnings; removes automatic MCPConfigs→ID resolution in merge path; propagates AllowAllKeys on reconcile updates.
Changelog / migration docs
transports/changelog.md
Adds BREAKING CHANGES section documenting absent vs explicit-empty semantics for virtual_keys provider_configs and mcp_configs, migration guidance, and deprecation notice.
UI text tweak
ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
Minor copy change: "Allow all current and future tools".
Logger wiring for tables package
framework/configstore/tables/init.go, transports/bifrost-http/main.go
Adds package-scoped var logger schemas.Logger and SetLogger(l schemas.Logger) in tables package; main registers the tables logger at startup.
Test imports / formatting
framework/configstore/tables/encryption_test.go
Replaced gorm logger import with aliased gormLogger and updated uses; minor test formatting adjustments.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant CFG as Config File Loader
    participant PRE as preprocessGovernanceVirtualKeys
    participant MERGE as Governance Merger
    participant STORE as Governance Store
    participant HASH as GenerateVirtualKeyHash

    CFG->>PRE: provide configData (virtual_keys)
    PRE->>PRE: expand absent provider_configs -> full provider list (emit deprecation warning)
    PRE->>PRE: expand absent mcp_configs -> full MCP list (emit deprecation warning)
    PRE->>MERGE: return processed configData
    MERGE->>STORE: compare/merge governance entries
    STORE->>HASH: compute provider config hashes (includes AllowAllKeys)
    HASH-->>STORE: return deterministic hashes
    MERGE->>STORE: apply updates (propagate AllowAllKeys to existing entries)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

"I hop through configs, nibbling old defaults,
I stamp a flag where ambivalence halts.
Allow or deny, I tidy the fence —
a tiny deprecation hop for common sense.
Carrots and keys, all in tidy vaults! 🥕"

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding an AllowAllKeys flag and fixing virtual key configuration semantics.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering all required template sections including summary, changes, type of change, affected areas, testing instructions, breaking changes with migration guidance, and security considerations.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 03-10-fix_backwards_compact_with_config.json_loading_for_vk_changes
📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
transports/changelog.md (2)

3-3: Consider clarifying the MCP tools permission mechanism.

The phrase "tools not permitted by the VK" could be more specific. Consider explicitly mentioning that this refers to the tools_to_execute configuration in the virtual key's MCP config, e.g., "tools not listed in the VK's mcp_configs[*].tools_to_execute".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/changelog.md` at line 3, Update the changelog entry to explicitly
state which configuration controls allowed tools: replace "tools not permitted
by the VK" with a precise reference to the virtual key's MCP config (e.g., the
mcp_configs[*].tools_to_execute field) so it reads that tools not listed in the
VK's mcp_configs[*].tools_to_execute are blocked at inference and MCP tool
execution, ensuring readers know the exact symbol/name controlling permissions.

22-23: Clarify the migration guidance for empty provider_configs/mcp_configs.

The instruction "list entries explicitly instead of using an empty array" could be more specific. Does this mean:

  1. Enumerate each provider/MCP client you want to allow (e.g., provider_configs: [{provider_id: "openai", ...}, {provider_id: "anthropic", ...}])?
  2. Or is there wildcard support like with allowed_keys?

Based on the feature description in line 1 (wildcard support mentioned only for key_ids), it appears wildcards are not supported for top-level provider_configs/mcp_configs. If that's correct, consider clarifying: "list all providers/MCP clients you want to allow by including an explicit entry for each one" or similar wording.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/changelog.md` around lines 22 - 23, Update the changelog text to
explicitly state that wildcards are not supported for top-level provider_configs
and mcp_configs and instruct users to enumerate each allowed entry; e.g.,
clarify that you must list all providers or MCP clients you want to permit by
adding an explicit entry for each (such as a provider_configs entry with
provider_id "openai" and its config), rather than using an empty array or a
wildcard like allowed_keys supports for key_ids.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@framework/configstore/tables/virtualkey.go`:
- Around line 229-245: The deprecation log uses mc.MCPClientName before it is
assigned, so it prints empty; fix by either assigning mc.MCPClientName =
temp.MCPClientName before the log or change the log to reference
temp.MCPClientName (instead of mc.MCPClientName) when logging the absent
tools_to_execute deprecation; ensure you still set mc.ToolsToExecute from
temp.ToolsToExecute and keep the MCPClientName capture (temp.MCPClientName ->
mc.MCPClientName) after the tools handling.

In `@transports/bifrost-http/lib/config.go`:
- Around line 1073-1129: Move the implicit expansion loop (the block that
expands absent vk.ProviderConfigs and vk.MCPConfigs) out of
mergeGovernanceConfig and run it earlier, before the codepath that branches for
creating vs merging DB state (i.e., call it from loadGovernanceConfigFromFile /
createGovernanceConfigInStore paths). In that helper, build provider expansions
from the runtime config that includes store-backed providers (use
config.Providers rather than configData.Providers), and for provider entries
resolve to stable DB identifiers the same way MCP configs are resolved (mirror
the resolveMCPConfigClientIDs approach for provider entries or call the existing
provider-ID resolver if present) so vk.ProviderConfigs and vk.MCPConfigs are
normalized (with resolved IDs) before either DB branch runs. Ensure the helper
is invoked prior to any persistence so the persisted VirtualKeys never contain a
nil/empty ambiguity.

---

Nitpick comments:
In `@transports/changelog.md`:
- Line 3: Update the changelog entry to explicitly state which configuration
controls allowed tools: replace "tools not permitted by the VK" with a precise
reference to the virtual key's MCP config (e.g., the
mcp_configs[*].tools_to_execute field) so it reads that tools not listed in the
VK's mcp_configs[*].tools_to_execute are blocked at inference and MCP tool
execution, ensuring readers know the exact symbol/name controlling permissions.
- Around line 22-23: Update the changelog text to explicitly state that
wildcards are not supported for top-level provider_configs and mcp_configs and
instruct users to enumerate each allowed entry; e.g., clarify that you must list
all providers or MCP clients you want to permit by adding an explicit entry for
each (such as a provider_configs entry with provider_id "openai" and its
config), rather than using an empty array or a wildcard like allowed_keys
supports for key_ids.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 87d83a58-eaf4-4aa1-9596-5fa87e38da97

📥 Commits

Reviewing files that changed from the base of the PR and between 5a214b3 and 8569ce1.

📒 Files selected for processing (6)
  • framework/configstore/clientconfig.go
  • framework/configstore/tables/virtualkey.go
  • plugins/governance/resolver.go
  • transports/bifrost-http/lib/config.go
  • transports/changelog.md
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx

Comment thread framework/configstore/tables/virtualkey.go
Comment thread transports/bifrost-http/lib/config.go Outdated
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-fix_backwards_compact_with_config.json_loading_for_vk_changes branch from 8569ce1 to 6a9f904 Compare March 10, 2026 11:30
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@framework/configstore/tables/virtualkey.go`:
- Around line 89-92: The logger.Warn calls in virtualkey.go use printf verbs but
the Logger interface treats args as structured fields, so replace the two calls
that pass format strings (the one referencing pc.Provider and the one
referencing temp.MCPClientName) with calls that pass a fully formatted string
created via fmt.Sprintf; update imports to include fmt if missing and change the
calls that currently read logger.Warn("[DEPRECATED] ... %q ...", pc.Provider)
and logger.Warn("[DEPRECATED] ... %q ...", temp.MCPClientName) to
logger.Warn(fmt.Sprintf("...%q...", pc.Provider)) and
logger.Warn(fmt.Sprintf("...%q...", temp.MCPClientName)) respectively.

In `@transports/bifrost-http/lib/config.go`:
- Around line 986-1004: The GenerateVirtualKeyHash is only stable when
vk.MCPConfigs contains resolved MCPClientID values, but currently only the
synthetic allow-all branch calls resolveMCPConfigClientIDs; fix by resolving
explicit vk.MCPConfigs as well (call resolveMCPConfigClientIDs(ctx,
config.ConfigStore, vk.MCPConfigs, vk.ID) whenever vk.MCPConfigs is non-nil or
has entries) before invoking GenerateVirtualKeyHash so that MCPClientName
entries are converted to MCPClientID and the resulting ConfigHash will change
when the target MCP client changes.

In `@transports/changelog.md`:
- Around line 22-30: Update the changelog wording to clarify that the
"allow-all" behavior is a startup snapshot produced by
preprocessGovernanceVirtualKeys: when provider_configs or mcp_configs (and their
nested allowed_keys or tools_to_execute) are omitted,
preprocessGovernanceVirtualKeys expands them only to the set of providers and
MCP clients present at boot time, not to any providers/clients added later; make
this explicit and mention that the implicit allow-all is not a live wildcard and
will not include subsequent runtime additions so users must explicitly list
entries to cover future providers/clients.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7ec4986a-9e0b-4c04-aedf-db45b10302e7

📥 Commits

Reviewing files that changed from the base of the PR and between 8569ce1 and 6a9f904.

📒 Files selected for processing (9)
  • framework/configstore/clientconfig.go
  • framework/configstore/tables/encryption_test.go
  • framework/configstore/tables/init.go
  • framework/configstore/tables/virtualkey.go
  • plugins/governance/resolver.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/main.go
  • transports/changelog.md
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
  • plugins/governance/resolver.go

Comment thread framework/configstore/tables/virtualkey.go Outdated
Comment thread transports/bifrost-http/lib/config.go
Comment thread transports/changelog.md Outdated
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-feat_vk_provider_config_key_ids_now_supports_wildcard_to_allow_all_keys_empty_key_ids_denies_all branch from 5a214b3 to e68b8cf Compare March 10, 2026 14:00
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-fix_backwards_compact_with_config.json_loading_for_vk_changes branch from 6a9f904 to 3632e84 Compare March 10, 2026 14:00
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 (1)
framework/configstore/clientconfig.go (1)

655-673: ⚠️ Potential issue | 🟠 Major

Ignore KeyIDs when AllowAllKeys is true.

framework/configstore/tables/virtualkey.go already treats Keys as inactive once AllowAllKeys is set, but this hash still includes every key ID. That makes reconciliation depend on stale/preloaded associations instead of the effective policy, so wildcard configs can keep hashing differently after migration.

💡 Suggested fix
-			keyIDs := make([]string, len(pc.Keys))
-			for j, k := range pc.Keys {
-				keyIDs[j] = k.KeyID
-			}
-			sort.Strings(keyIDs)
+			keyIDs := []string{}
+			if !pc.AllowAllKeys {
+				keyIDs = make([]string, len(pc.Keys))
+				for j, k := range pc.Keys {
+					keyIDs[j] = k.KeyID
+				}
+				sort.Strings(keyIDs)
+			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/clientconfig.go` around lines 655 - 673, The hash input
currently includes every KeyID even when pc.AllowAllKeys is true; change the
logic in the VirtualKeyProviderConfigHashInput construction so KeyIDs is
omitted/empty when pc.AllowAllKeys is true (e.g., after collecting/sorting
keyIDs, if pc.AllowAllKeys then set keyIDs = nil or an empty slice) so
providerConfigsForHash entries reflect the effective policy rather than stale
key associations; ensure this uses the pc.AllowAllKeys check and assigns the
adjusted keyIDs to the KeyIDs field.
♻️ Duplicate comments (3)
framework/configstore/tables/virtualkey.go (1)

89-92: ⚠️ Potential issue | 🟡 Minor

Pre-format these deprecation warnings before calling Warn.

Both call sites still pass %q as though logger.Warn were printf-style. If Warn treats extra args as structured fields, the provider/client name will not be interpolated and the warning text will be misleading.

💡 Suggested fix
-			logger.Warn("[DEPRECATED] virtual key provider config for provider %q has no allowed_keys in config.json — "+
-				"defaulting to allow all keys. This implicit allow-all will be removed in the next major version. "+
-				"Use allowed_keys: [\"*\"] to allow all keys explicitly, or list specific key names.",
-				pc.Provider)
+			logger.Warn(fmt.Sprintf("[DEPRECATED] virtual key provider config for provider %q has no allowed_keys in config.json — "+
+				"defaulting to allow all keys. This implicit allow-all will be removed in the next major version. "+
+				"Use allowed_keys: [\"*\"] to allow all keys explicitly, or list specific key names.",
+				pc.Provider))
...
-		logger.Warn("[DEPRECATED] virtual key MCP config for client %q has no tools_to_execute in config.json — "+
-			"defaulting to allow all tools. This implicit allow-all will be removed in the next major version. "+
-			"Use tools_to_execute: [\"*\"] to allow all tools explicitly, or list specific tool names.",
-			temp.MCPClientName)
+		logger.Warn(fmt.Sprintf("[DEPRECATED] virtual key MCP config for client %q has no tools_to_execute in config.json — "+
+			"defaulting to allow all tools. This implicit allow-all will be removed in the next major version. "+
+			"Use tools_to_execute: [\"*\"] to allow all tools explicitly, or list specific tool names.",
+			temp.MCPClientName))
#!/bin/bash
set -euo pipefail

echo "Logger interface:"
sed -n '/type Logger interface/,/}/p' core/schemas/logger.go

echo
echo "Warn call in provider config unmarshal:"
sed -n '84,96p' framework/configstore/tables/virtualkey.go

echo
echo "Warn call in MCP config unmarshal:"
sed -n '228,240p' framework/configstore/tables/virtualkey.go

Also applies to: 233-236

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/tables/virtualkey.go` around lines 89 - 92, The
deprecation warnings pass a printf-style format and extra args to logger.Warn
(e.g., logger.Warn("...%q...", pc.Provider)), but Warn treats extra args as
structured fields; pre-format the message before calling Warn by using
fmt.Sprintf to interpolate pc.Provider (and the other similar call site that
interpolates the MCP/provider name) so the final call is
logger.Warn(fmt.Sprintf("...%q...", pc.Provider)) (do the same for the second
Warn at the MCP config unmarshal that currently passes its provider/client name
as a separate arg).
transports/changelog.md (1)

22-30: ⚠️ Potential issue | 🟡 Minor

Clarify that omitted top-level configs expand to a startup snapshot, not a live wildcard.

The migration note still reads like absent provider_configs / mcp_configs automatically cover later additions. In preprocessGovernanceVirtualKeys, they expand only to the providers and MCP clients present during boot, so runtime additions are not implicitly included.

📝 Suggested wording
-**`provider_configs: []` / `mcp_configs: []`** — previously allowed all; now deny all. To keep allow-all behaviour, list entries explicitly instead of using an empty array.
+**`provider_configs: []` / `mcp_configs: []`** — previously allowed all; now deny all. To keep the current implicit behaviour, list the providers / MCP clients explicitly instead of using an empty array. Omitting the field today expands only to whatever is configured at startup; it is not a live wildcard for providers or MCP clients added later.
@@
-Omitting `provider_configs`, `mcp_configs`, `allowed_keys`, or `tools_to_execute` entirely (absent key) currently defaults to allow-all and emits a startup warning. **This implicit allow-all will be removed in the next major version** — absent and `[]` will both mean deny-all (deny-by-default). Migrate by always specifying these fields explicitly in config.json.
+Omitting `provider_configs`, `mcp_configs`, `allowed_keys`, or `tools_to_execute` entirely (absent key) currently defaults to an allow-all startup snapshot and emits a startup warning. **This implicit allow-all will be removed in the next major version** — absent and `[]` will both mean deny-all (deny-by-default). Migrate by always specifying these fields explicitly in config.json.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/changelog.md` around lines 22 - 30, Update the changelog text to
clarify that omitting top-level provider_configs or mcp_configs is expanded as a
startup snapshot (not a live wildcard): change wording to state that
preprocessGovernanceVirtualKeys expands absent configs only to providers and MCP
clients present at boot time and will not automatically include
providers/clients added at runtime; ensure the deprecation notice and the
migration guidance reflect this boot-time snapshot behavior and reference
preprocessGovernanceVirtualKeys so readers know where expansion happens.
transports/bifrost-http/lib/config.go (1)

988-1004: ⚠️ Potential issue | 🟠 Major

Resolve explicit mcp_configs before generating ConfigHash.

preprocessGovernanceVirtualKeys only resolves client names for the synthetic allow-all branch. Explicit mcp_configs from config.json still hit Line 1139 and Line 1480 with MCPClientID == 0, so changing mcp_client_name can leave ConfigHash unchanged and skip reconciliation.

💡 Proposed fix
 		if vk.MCPConfigs == nil && config.MCPConfig != nil && len(config.MCPConfig.ClientConfigs) > 0 {
 			logger.Warn(
 				"virtual key %q has no mcp_configs in config.json — expanding to all %d configured MCP client(s). "+
 					"This implicit allow-all behaviour is DEPRECATED and will be removed in the next major version. "+
 					"Please add an explicit mcp_configs list to your config.json.",
 				vk.ID, len(config.MCPConfig.ClientConfigs),
 			)
 			unresolved := make([]configstoreTables.TableVirtualKeyMCPConfig, 0, len(config.MCPConfig.ClientConfigs))
 			for _, client := range config.MCPConfig.ClientConfigs {
 				unresolved = append(unresolved, configstoreTables.TableVirtualKeyMCPConfig{
 					MCPClientName:  client.Name,
 					ToolsToExecute: []string{"*"},
 				})
 			}
-			// Resolve client names → DB IDs now so the hash is stable (MCPClientID is in the hash)
-			vk.MCPConfigs = resolveMCPConfigClientIDs(ctx, config.ConfigStore, unresolved, vk.ID)
+			vk.MCPConfigs = unresolved
+		}
+
+		if len(vk.MCPConfigs) > 0 {
+			// Resolve client names → DB IDs now so the hash is stable (MCPClientID is in the hash)
+			vk.MCPConfigs = resolveMCPConfigClientIDs(ctx, config.ConfigStore, vk.MCPConfigs, vk.ID)
 		}
 	}
 }

Also applies to: 1138-1176, 1477-1507

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/lib/config.go` around lines 988 - 1004,
preprocessGovernanceVirtualKeys currently only calls resolveMCPConfigClientIDs
for the synthetic "allow-all" branch, leaving explicit vk.MCPConfigs from
config.json unresolved (MCPClientID==0) which makes ConfigHash insensitive to
mcp_client_name changes; fix by ensuring explicit vk.MCPConfigs are resolved to
DB IDs before computing ConfigHash — i.e., in preprocessGovernanceVirtualKeys
(and the other mentioned branches) call resolveMCPConfigClientIDs with the
explicit vk.MCPConfigs (or convert them to unresolved TableVirtualKeyMCPConfig
if needed) and assign the result back to vk.MCPConfigs so MCPClientID is
populated prior to ConfigHash computation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@framework/configstore/clientconfig.go`:
- Around line 655-673: The hash input currently includes every KeyID even when
pc.AllowAllKeys is true; change the logic in the
VirtualKeyProviderConfigHashInput construction so KeyIDs is omitted/empty when
pc.AllowAllKeys is true (e.g., after collecting/sorting keyIDs, if
pc.AllowAllKeys then set keyIDs = nil or an empty slice) so
providerConfigsForHash entries reflect the effective policy rather than stale
key associations; ensure this uses the pc.AllowAllKeys check and assigns the
adjusted keyIDs to the KeyIDs field.

---

Duplicate comments:
In `@framework/configstore/tables/virtualkey.go`:
- Around line 89-92: The deprecation warnings pass a printf-style format and
extra args to logger.Warn (e.g., logger.Warn("...%q...", pc.Provider)), but Warn
treats extra args as structured fields; pre-format the message before calling
Warn by using fmt.Sprintf to interpolate pc.Provider (and the other similar call
site that interpolates the MCP/provider name) so the final call is
logger.Warn(fmt.Sprintf("...%q...", pc.Provider)) (do the same for the second
Warn at the MCP config unmarshal that currently passes its provider/client name
as a separate arg).

In `@transports/bifrost-http/lib/config.go`:
- Around line 988-1004: preprocessGovernanceVirtualKeys currently only calls
resolveMCPConfigClientIDs for the synthetic "allow-all" branch, leaving explicit
vk.MCPConfigs from config.json unresolved (MCPClientID==0) which makes
ConfigHash insensitive to mcp_client_name changes; fix by ensuring explicit
vk.MCPConfigs are resolved to DB IDs before computing ConfigHash — i.e., in
preprocessGovernanceVirtualKeys (and the other mentioned branches) call
resolveMCPConfigClientIDs with the explicit vk.MCPConfigs (or convert them to
unresolved TableVirtualKeyMCPConfig if needed) and assign the result back to
vk.MCPConfigs so MCPClientID is populated prior to ConfigHash computation.

In `@transports/changelog.md`:
- Around line 22-30: Update the changelog text to clarify that omitting
top-level provider_configs or mcp_configs is expanded as a startup snapshot (not
a live wildcard): change wording to state that preprocessGovernanceVirtualKeys
expands absent configs only to providers and MCP clients present at boot time
and will not automatically include providers/clients added at runtime; ensure
the deprecation notice and the migration guidance reflect this boot-time
snapshot behavior and reference preprocessGovernanceVirtualKeys so readers know
where expansion happens.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0e92bae4-fdca-4264-ac55-ee10f10b7c99

📥 Commits

Reviewing files that changed from the base of the PR and between 6a9f904 and 3632e84.

📒 Files selected for processing (8)
  • framework/configstore/clientconfig.go
  • framework/configstore/tables/encryption_test.go
  • framework/configstore/tables/init.go
  • framework/configstore/tables/virtualkey.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/main.go
  • transports/changelog.md
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • transports/bifrost-http/main.go
  • framework/configstore/tables/init.go

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-feat_vk_provider_config_key_ids_now_supports_wildcard_to_allow_all_keys_empty_key_ids_denies_all branch from e68b8cf to ad76bf0 Compare March 10, 2026 18:08
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-fix_backwards_compact_with_config.json_loading_for_vk_changes branch from 3632e84 to d69f60c Compare March 10, 2026 18:08
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 (1)
framework/configstore/clientconfig.go (1)

653-673: ⚠️ Potential issue | 🟠 Major

Hash specific allowed_keys by name until IDs are resolved.

AllowAllKeys fixes the allow-all/deny-all ambiguity, but this loop still hashes only k.KeyID. In the new config-file path, framework/configstore/tables/virtualkey.go materializes specific allowed_keys as TableKey{Name: ...} first, so ["key-a"] and ["key-b"] both collapse to the same empty-ID hash here. That means mergeGovernanceConfig can miss a real key-permission change and leave stale VK associations in store.

Suggested fix
-			keyIDs := make([]string, len(pc.Keys))
+			keyRefs := make([]string, len(pc.Keys))
 			for j, k := range pc.Keys {
-				keyIDs[j] = k.KeyID
+				switch {
+				case k.KeyID != "":
+					keyRefs[j] = "id:" + k.KeyID
+				case k.Name != "":
+					keyRefs[j] = "name:" + k.Name
+				}
 			}
-			sort.Strings(keyIDs)
+			sort.Strings(keyRefs)
@@
-				KeyIDs:        keyIDs,
+				KeyIDs:        keyRefs,

Based on learnings: "In framework/configstore/clientconfig.go, when implementing GenerateKeyHash, prefix hashed keys with distinct identifiers: use 'env:' for environment-sourced values and 'val:' for literal values, mirroring the existing 'GenerateMCPClientHash' pattern to prevent hash collisions."


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 10d2e4ab-2887-4f8b-a8c0-bfd11cb2b231

📥 Commits

Reviewing files that changed from the base of the PR and between 3632e84 and d69f60c.

📒 Files selected for processing (8)
  • framework/configstore/clientconfig.go
  • framework/configstore/tables/encryption_test.go
  • framework/configstore/tables/init.go
  • framework/configstore/tables/virtualkey.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/main.go
  • transports/changelog.md
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • framework/configstore/tables/init.go
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
  • framework/configstore/tables/encryption_test.go

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-feat_vk_provider_config_key_ids_now_supports_wildcard_to_allow_all_keys_empty_key_ids_denies_all branch from ad76bf0 to f5103e6 Compare March 11, 2026 13:34
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-fix_backwards_compact_with_config.json_loading_for_vk_changes branch from d69f60c to 4af0fb2 Compare March 11, 2026 13:34
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@framework/configstore/tables/init.go`:
- Around line 5-9: The package-global logger variable is nil and UnmarshalJSON
in virtualkey.go calls logger.Warn() unguarded; initialize logger to a safe
no-op default that implements schemas.Logger (so logging calls are safe before
SetLogger) and keep SetLogger(l schemas.Logger) to replace that default;
alternatively, add nil checks around logger usage in UnmarshalJSON (functions
named UnmarshalJSON at virtualkey.go lines ~89 and ~231) to call logger only if
non-nil. Ensure the no-op implements the same methods as schemas.Logger so all
existing logger.Warn/info/error calls remain valid.

In `@framework/configstore/tables/virtualkey.go`:
- Around line 79-107: The code is using len(pc.Keys) == 0 to detect the
"config-file format" which causes an API/DB payload that explicitly set keys: []
to be treated as absent and default to allow-all; fix by detecting presence of
the keys field explicitly instead of relying on its length. Modify the
parsing/temp struct used here (the struct with temp.DBAllowAllKeys and
temp.AllowedKeys) to capture whether "keys" was present (e.g., make Keys a
pointer or add a KeysPresent bool populated during unmarshalling), then replace
the len(pc.Keys) == 0 check with a presence check (e.g., if !temp.KeysPresent)
so the branch that applies absent-vs-empty semantics for AllowedKeys only runs
when the config-file shape is actually parsed; keep the existing handling of
temp.DBAllowAllKeys, temp.AllowedKeys, pc.AllowAllKeys and pc.Keys otherwise.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3e451ea0-06e2-41f7-9325-183c2b66c5c5

📥 Commits

Reviewing files that changed from the base of the PR and between d69f60c and 4af0fb2.

📒 Files selected for processing (8)
  • framework/configstore/clientconfig.go
  • framework/configstore/tables/encryption_test.go
  • framework/configstore/tables/init.go
  • framework/configstore/tables/virtualkey.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/main.go
  • transports/changelog.md
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • framework/configstore/clientconfig.go
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx

Comment on lines +5 to +9
var logger schemas.Logger

// SetLogger sets the logger for the tables package.
func SetLogger(l schemas.Logger) {
logger = l
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "tables package logger initialization:"
sed -n '1,40p' framework/configstore/tables/init.go

echo
echo "tables package logger call sites:"
rg -n 'logger\.(Warn|Info|Debug|Error|Fatal)\(' framework/configstore/tables -g '*.go'

Repository: maximhq/bifrost

Length of output: 1008


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Context around virtualkey.go logger calls (line 89) ==="
sed -n '85,95p' framework/configstore/tables/virtualkey.go

echo
echo "=== Context around virtualkey.go logger calls (line 231) ==="
sed -n '225,235p' framework/configstore/tables/virtualkey.go

echo
echo "=== Check for nil guards before logger usage ==="
rg -B5 'logger\.Warn' framework/configstore/tables/virtualkey.go | head -30

echo
echo "=== Search for SetLogger call sites ==="
rg -n 'SetLogger' --type go

echo
echo "=== Check if logger interface has a noop/nil-safe implementation ==="
rg -n 'type Logger' core/schemas -A10 --type go

Repository: maximhq/bifrost

Length of output: 6880


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Full Logger interface definition ==="
sed -n '28,60p' core/schemas/logger.go

echo
echo "=== Search for noop or default logger implementations ==="
rg -n 'type.*Logger' core/schemas --type go -A3 | grep -A3 'struct'

echo
echo "=== Check where virtualkey.go is used (imported/loaded) ==="
rg -n 'virtualkey' --type go | head -20

echo
echo "=== Check for any config loading outside main.go ==="
rg -n 'LoadConfig\|configstore\|tables' core/bifrost.go --type go -B2 -A2

echo
echo "=== Check if there are other entry points or transports ==="
fd -t f 'main.go' --type go | grep -v test

Repository: maximhq/bifrost

Length of output: 1501


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check if there are other entry points or transports ==="
find . -name 'main.go' -type f | grep -v test | grep -v '.git'

echo
echo "=== Where is virtualkey.go imported from? ==="
rg -n 'import.*virtualkey\|from.*virtualkey' --type go

echo
echo "=== Who imports tables package? ==="
rg -n 'configstore/tables' --type go | grep import

echo
echo "=== Check core/bifrost.go around line 183 (providerUtils.SetLogger) ==="
sed -n '175,195p' core/bifrost.go

echo
echo "=== Check core/bifrost.go for tables initialization/usage ==="
rg -n 'tables\.' core/bifrost.go --type go -B2 -A2

Repository: maximhq/bifrost

Length of output: 913


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Who imports tables package? ==="
rg -n 'configstore/tables' --type go | grep -E '(import|from)' | head -20

echo
echo "=== Check core/bifrost.go for tables or configstore usage ==="
rg -n 'tables\|configstore' core/bifrost.go --type go -B1 -A1

echo
echo "=== Check cli/main.go for logger and config initialization ==="
sed -n '1,80p' cli/main.go

echo
echo "=== Check if there are integration tests that load configs before SetLogger ==="
rg -n 'tables\.' --type go | grep -E 'test|_test' | head -10

Repository: maximhq/bifrost

Length of output: 245


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Find where virtualkey.go is actually used/called ==="
rg -n 'VirtualKey\|UnmarshalJSON' framework/configstore/tables --type go | head -20

echo
echo "=== Check what loads config and calls virtualkey unmarshal ==="
rg -n 'json.Unmarshal\|json.Decoder' framework/configstore --type go -B2 -A2

echo
echo "=== Check if there's an init() function in tables package that might initialize logger ==="
rg -n 'func init' framework/configstore/tables --type go

echo
echo "=== Full search for where UnmarshalJSON is triggered ==="
rg -n 'UnmarshalJSON' framework/configstore/tables -A15 --type go | head -40

echo
echo "=== Check if virtualkey package is only used during HTTP server startup ==="
grep -r 'virtualkey\|tables\.' transports/bifrost-http --include='*.go' | grep -v test | head -20

Repository: maximhq/bifrost

Length of output: 115


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== List all files in framework/configstore/tables ==="
ls -la framework/configstore/tables/

echo
echo "=== Check content of virtualkey.go ==="
head -100 framework/configstore/tables/virtualkey.go

echo
echo "=== Search for json.Unmarshal calls in framework/configstore ==="
rg -n 'json\.' framework/configstore --type go -A3 | head -50

echo
echo "=== Check how tables package is initialized in transports/bifrost-http/main.go ==="
sed -n '140,160p' transports/bifrost-http/main.go

Repository: maximhq/bifrost

Length of output: 10559


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check for any nil checks before logger.Warn calls in virtualkey.go ==="
sed -n '70,100p' framework/configstore/tables/virtualkey.go

echo
echo "=== Check around line 231 as well ==="
sed -n '215,245p' framework/configstore/tables/virtualkey.go

echo
echo "=== Check all files in CLI that might load configs ==="
head -50 cli/main.go

echo
echo "=== Check if logger interface could be nil-safe (checking Warn signature) ==="
grep -A3 'Warn(' core/schemas/logger.go

Repository: maximhq/bifrost

Length of output: 3996


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check if CLI loads/unmarshals configs before bootstrap ==="
rg -n 'config\|Config\|Unmarshal' cli/internal/app --type go -B2 -A2 | head -100

echo
echo "=== Check if any other main binaries (oauth2, plugins) set logger ==="
for f in framework/oauth2/main.go plugins/*/main.go; do
  if [ -f "$f" ]; then
    echo "=== $f ==="
    grep -n 'SetLogger\|tables\.' "$f" || echo "  (no SetLogger or tables refs)"
  fi
done

Repository: maximhq/bifrost

Length of output: 121


🏁 Script executed:

#!/bin/bash
set -euoripefail

echo "=== List files in cli/internal/app ==="
ls -la cli/internal/app/

echo
echo "=== Check main app file ==="
head -100 cli/internal/app/app.go

echo
echo "=== Search for where configstore or tables are used in CLI ==="
rg -n 'configstore\|tables' cli/ --type go

echo
echo "=== Search broadly for JSON unmarshalling in cli ==="
rg -n 'json\|Unmarshal' cli/ --type go | head -30

Repository: maximhq/bifrost

Length of output: 733


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== List files in cli/internal/app ==="
ls -la cli/internal/app/

echo
echo "=== Check main app file ==="
head -100 cli/internal/app/app.go

echo
echo "=== Search for where configstore or tables are used in CLI ==="
rg -n 'configstore\|tables' cli/ --type go

echo
echo "=== Search broadly for JSON unmarshalling in cli ==="
rg -n 'json\|Unmarshal' cli/ --type go | head -30

Repository: maximhq/bifrost

Length of output: 3072


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check all main.go files to see which ones might use configstore/tables ==="
for mainfile in $(find . -name 'main.go' -type f | grep -v test | grep -v '.git'); do
  echo "=== $mainfile ==="
  grep -l 'configstore\|tables\|SetLogger' "$mainfile" && echo "USES CONFIGSTORE/TABLES" || echo "does not use configstore"
done

echo
echo "=== Check framework/oauth2/main.go ==="
cat framework/oauth2/main.go

echo
echo "=== Check core/bifrost.go for tables/configstore usage (around line 183) ==="
sed -n '150,200p' core/bifrost.go

Repository: maximhq/bifrost

Length of output: 27179


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check plugins/governance/main.go for SetLogger call ==="
grep -n 'SetLogger\|tables\.' plugins/governance/main.go

echo
echo "=== Check plugins/logging/main.go for SetLogger call ==="
grep -n 'SetLogger\|tables\.' plugins/logging/main.go

echo
echo "=== Check framework/modelcatalog/main.go for SetLogger call ==="
grep -n 'SetLogger\|tables\.' framework/modelcatalog/main.go

echo
echo "=== Check the actual imports in these files to see what configstore they use ==="
head -50 plugins/governance/main.go | grep -A5 'import'

echo
echo "=== Check if any plugin loads virtualkey configs during init/main ==="
rg -n 'virtual.*key\|Virtual.*Key' plugins/ framework/modelcatalog/ --type go | head -20

Repository: maximhq/bifrost

Length of output: 118


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== List what's in plugins/governance ==="
ls -la plugins/governance/

echo
echo "=== Check plugins/governance/main.go ==="
cat plugins/governance/main.go

echo
echo "=== Check plugins/logging/main.go ==="
cat plugins/logging/main.go

Repository: maximhq/bifrost

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check if governance plugin calls tables.SetLogger ==="
grep -n 'tables\.SetLogger\|configstoreTables\.SetLogger' plugins/governance/main.go

echo
echo "=== Check framework/modelcatalog/main.go ==="
head -100 framework/modelcatalog/main.go

echo
echo "=== Check if modelcatalog calls tables.SetLogger ==="
grep -n 'tables\.SetLogger\|SetLogger' framework/modelcatalog/main.go

echo
echo "=== Search for all SetLogger calls to tables package across the codebase ==="
rg -n 'tables\.SetLogger' --type go

Repository: maximhq/bifrost

Length of output: 116


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== ALL places where tables.SetLogger is actually called ==="
rg -n 'tables\.SetLogger' --type go

echo
echo "=== Check if governance plugin loads virtual key configs in Init ==="
grep -n 'VirtualKey\|UnmarshalJSON\|configstore' plugins/governance/main.go | head -20

echo
echo "=== Check what tables are loaded by governance in NewLocalGovernanceStore ==="
sed -n '1,100p' plugins/governance/store.go | grep -A10 'NewLocalGovernanceStore\|configStore'

echo
echo "=== Confirm: does governance plugin's store load virtual keys? ==="
rg -n 'GetVirtualKey\|TableVirtualKey' plugins/governance/store.go --type go | head -10

Repository: maximhq/bifrost

Length of output: 1824


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check transports/bifrost-http/main.go initialization order ==="
sed -n '130,160p' transports/bifrost-http/main.go

echo
echo "=== Check where governance plugin Init is called in the HTTP transport ==="
rg -n 'governance\.Init\|NewGovernancePlugin' transports/bifrost-http --type go -B3 -A3

echo
echo "=== Check server.go or server initialization for governance setup ==="
grep -n 'governance\|GovernancePlugin' transports/bifrost-http/server/server.go | head -20

Repository: maximhq/bifrost

Length of output: 1167


Initialize the tables logger to a safe default or add nil checks before logging calls.

logger is an uninitialized package-global variable. The UnmarshalJSON methods in virtualkey.go (lines 89, 231) call logger.Warn() unconditionally without nil guards. Any code that unmarshals virtual key configs before tables.SetLogger() runs will panic on a nil interface method call. While the HTTP transport calls tables.SetLogger() before bootstrap, other entry points (governance plugin, oauth2 framework, modelcatalog) may load configs without wiring the logger. Initialize this package logger to a no-op default implementation, or guard all logger calls with nil checks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/tables/init.go` around lines 5 - 9, The package-global
logger variable is nil and UnmarshalJSON in virtualkey.go calls logger.Warn()
unguarded; initialize logger to a safe no-op default that implements
schemas.Logger (so logging calls are safe before SetLogger) and keep SetLogger(l
schemas.Logger) to replace that default; alternatively, add nil checks around
logger usage in UnmarshalJSON (functions named UnmarshalJSON at virtualkey.go
lines ~89 and ~231) to call logger only if non-nil. Ensure the no-op implements
the same methods as schemas.Logger so all existing logger.Warn/info/error calls
remain valid.

Comment thread framework/configstore/tables/virtualkey.go
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-feat_vk_provider_config_key_ids_now_supports_wildcard_to_allow_all_keys_empty_key_ids_denies_all branch from f5103e6 to 2a794d7 Compare March 16, 2026 08:20
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-fix_backwards_compact_with_config.json_loading_for_vk_changes branch from 4af0fb2 to 695fc49 Compare March 16, 2026 08:20
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
framework/configstore/tables/virtualkey.go (2)

89-90: ⚠️ Potential issue | 🟡 Minor

Deprecation warnings still use printf verbs directly in logger.Warn

Both warnings pass %q format strings directly to logger.Warn. If Warn(msg string, args ...any) is structured-logging style, %q is logged literally instead of interpolated.

💡 Suggested fix
-logger.Warn("[DEPRECATED] virtual key provider config for provider %q has no allowed_keys in config.json — defaulting to allow all keys. This implicit allow-all will be removed in the next major version. Use allowed_keys: [\"*\"] to allow all keys explicitly, or list specific key names.",
-	pc.Provider)
+logger.Warn(fmt.Sprintf("[DEPRECATED] virtual key provider config for provider %q has no allowed_keys in config.json — defaulting to allow all keys. This implicit allow-all will be removed in the next major version. Use allowed_keys: [\"*\"] to allow all keys explicitly, or list specific key names.",
+	pc.Provider))

-logger.Warn("[DEPRECATED] virtual key MCP config for client %q has no tools_to_execute in config.json — defaulting to allow all tools. This implicit allow-all will be removed in the next major version. Use tools_to_execute: [\"*\"] to allow all tools explicitly, or list specific tool names.",
-	temp.MCPClientName)
+logger.Warn(fmt.Sprintf("[DEPRECATED] virtual key MCP config for client %q has no tools_to_execute in config.json — defaulting to allow all tools. This implicit allow-all will be removed in the next major version. Use tools_to_execute: [\"*\"] to allow all tools explicitly, or list specific tool names.",
+	temp.MCPClientName))

Also applies to: 231-232

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/tables/virtualkey.go` around lines 89 - 90, The warning
uses printf verbs directly in logger.Warn which causes the `%q` to be logged
literally; update the call that references pc.Provider in the virtual key
provider deprecation message so the provider value is interpolated—either
pre-format the message with fmt.Sprintf(...) and pass the resulting string to
logger.Warn, or switch to structured logging by supplying the provider as a
field (e.g., logger.With("provider", pc.Provider).Warn(...)). Apply the same fix
to the other identical warning occurrence referenced in the file.

79-107: ⚠️ Potential issue | 🟠 Major

keys: [] is still misclassified as “absent”, causing unintended allow-all

At Line 82, len(pc.Keys) == 0 is used to detect config-file format. That makes an explicit DB/API payload with keys: [] fall into the deprecated absent-allowed_keys path and sets AllowAllKeys = true, which violates the new explicit deny semantics.

💡 Suggested fix
 type Alias TableVirtualKeyProviderConfig
 type TempProviderConfig struct {
 	Alias
+	DBKeys         *[]TableKey `json:"keys"`           // DB/API format; nil = absent
 	AllowedKeys    *[]string   `json:"allowed_keys"`   // Config file format; nil = absent
 	DBAllowAllKeys *bool       `json:"allow_all_keys"` // DB/API format; nil = absent
 }

 var temp TempProviderConfig
 if err := json.Unmarshal(data, &temp); err != nil {
 	return err
 }

 *pc = TableVirtualKeyProviderConfig(temp.Alias)
+if temp.DBKeys != nil {
+	pc.Keys = *temp.DBKeys
+}

 if temp.DBAllowAllKeys != nil {
 	pc.AllowAllKeys = *temp.DBAllowAllKeys
-} else if len(pc.Keys) == 0 {
+} else if temp.DBKeys == nil {
 	// Config file format semantics for allowed_keys
 	...
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/tables/virtualkey.go` around lines 79 - 107, The code
incorrectly uses len(pc.Keys) == 0 to detect whether the config-file
"allowed_keys" field was present, causing an explicit DB/API payload with keys:
[] to be treated as "absent" and default to allow-all; change the detection to
check the parsed temp.AllowedKeys presence instead (i.e., replace the else if
len(pc.Keys) == 0 branch condition with else if temp.AllowedKeys != nil and
adjust the block to treat nil vs empty slice correctly), keeping the existing
handling of temp.DBAllowAllKeys, pc.AllowAllKeys, pc.Keys, and the special ["*"]
wildcard behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@framework/configstore/tables/virtualkey.go`:
- Around line 89-90: The warning uses printf verbs directly in logger.Warn which
causes the `%q` to be logged literally; update the call that references
pc.Provider in the virtual key provider deprecation message so the provider
value is interpolated—either pre-format the message with fmt.Sprintf(...) and
pass the resulting string to logger.Warn, or switch to structured logging by
supplying the provider as a field (e.g., logger.With("provider",
pc.Provider).Warn(...)). Apply the same fix to the other identical warning
occurrence referenced in the file.
- Around line 79-107: The code incorrectly uses len(pc.Keys) == 0 to detect
whether the config-file "allowed_keys" field was present, causing an explicit
DB/API payload with keys: [] to be treated as "absent" and default to allow-all;
change the detection to check the parsed temp.AllowedKeys presence instead
(i.e., replace the else if len(pc.Keys) == 0 branch condition with else if
temp.AllowedKeys != nil and adjust the block to treat nil vs empty slice
correctly), keeping the existing handling of temp.DBAllowAllKeys,
pc.AllowAllKeys, pc.Keys, and the special ["*"] wildcard behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ae2187e1-3277-4d7f-b805-08bb27dcfd2d

📥 Commits

Reviewing files that changed from the base of the PR and between 4af0fb2 and 695fc49.

📒 Files selected for processing (4)
  • framework/configstore/clientconfig.go
  • framework/configstore/tables/encryption_test.go
  • framework/configstore/tables/init.go
  • framework/configstore/tables/virtualkey.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • framework/configstore/tables/init.go
  • framework/configstore/clientconfig.go
  • framework/configstore/tables/encryption_test.go

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-feat_vk_provider_config_key_ids_now_supports_wildcard_to_allow_all_keys_empty_key_ids_denies_all branch from 2a794d7 to a237ad1 Compare March 16, 2026 12:20
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-10-fix_backwards_compact_with_config.json_loading_for_vk_changes branch from 695fc49 to 736cc1f Compare March 16, 2026 12:20
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
framework/configstore/tables/init.go (1)

5-9: ⚠️ Potential issue | 🟠 Major

Initialize logger to a no-op default to prevent nil pointer panics.

The package-level logger variable is nil by default. UnmarshalJSON methods in virtualkey.go (Lines 89 and 231) call logger.Warn() unconditionally. If any code path unmarshals virtual key configs before tables.SetLogger() is called (e.g., governance plugin, CLI tools, or tests), this will panic on a nil interface method call.

Initialize the logger to a safe no-op default:

,

🛡️ Proposed fix
 package tables

-import "github.com/maximhq/bifrost/core/schemas"
+import (
+	bifrost "github.com/maximhq/bifrost/core"
+	"github.com/maximhq/bifrost/core/schemas"
+)

-var logger schemas.Logger
+// logger defaults to a no-op logger to prevent nil panics if SetLogger is not called
+// before config unmarshalling occurs.
+var logger schemas.Logger = bifrost.NewDefaultLogger(schemas.LogLevelWarn)

 // SetLogger sets the logger for the tables package.
 func SetLogger(l schemas.Logger) {
 	logger = l
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/tables/init.go` around lines 5 - 9, The package-level
variable logger is nil by default which causes panics when virtualkey.go's
UnmarshalJSON methods call logger.Warn() before SetLogger() runs; initialize
logger to a safe no-op implementation at declaration (e.g., assign a
schemas.Logger no-op instance or a local noop struct that implements
Warn/Info/Error) and keep SetLogger(l schemas.Logger) to replace it, ensuring
UnmarshalJSON in virtualkey.go (the methods that call logger.Warn) can always
call logger safely.
🧹 Nitpick comments (1)
transports/bifrost-http/lib/config.go (1)

1006-1013: Consider sorting expanded providers for deterministic ordering.

Map iteration order in Go is non-deterministic. While this doesn't affect correctness (each provider config is independent), it may cause non-deterministic ordering in logs and serialized output. For consistency:

♻️ Optional: Sort providers for deterministic expansion order
+import "sort"
+
 		expanded := make([]configstoreTables.TableVirtualKeyProviderConfig, 0, len(config.Providers))
+		providerNames := make([]string, 0, len(config.Providers))
 		for providerName := range config.Providers {
+			providerNames = append(providerNames, string(providerName))
+		}
+		sort.Strings(providerNames)
+		for _, providerName := range providerNames {
 			expanded = append(expanded, configstoreTables.TableVirtualKeyProviderConfig{
-				Provider:     string(providerName),
+				Provider:     providerName,
 				AllowAllKeys: true,
 			})
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/lib/config.go` around lines 1006 - 1013, The
expansion of provider configs uses map iteration over config.Providers which is
non-deterministic; before building expanded (used to set vk.ProviderConfigs)
collect the provider names into a slice, sort that slice, then iterate the
sorted names to append TableVirtualKeyProviderConfig entries (Provider and
AllowAllKeys) so the resulting expanded slice and any logs/serialization are
deterministic; update the loop that currently ranges over config.Providers to
use the sorted names.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@framework/configstore/tables/init.go`:
- Around line 5-9: The package-level variable logger is nil by default which
causes panics when virtualkey.go's UnmarshalJSON methods call logger.Warn()
before SetLogger() runs; initialize logger to a safe no-op implementation at
declaration (e.g., assign a schemas.Logger no-op instance or a local noop struct
that implements Warn/Info/Error) and keep SetLogger(l schemas.Logger) to replace
it, ensuring UnmarshalJSON in virtualkey.go (the methods that call logger.Warn)
can always call logger safely.

---

Nitpick comments:
In `@transports/bifrost-http/lib/config.go`:
- Around line 1006-1013: The expansion of provider configs uses map iteration
over config.Providers which is non-deterministic; before building expanded (used
to set vk.ProviderConfigs) collect the provider names into a slice, sort that
slice, then iterate the sorted names to append TableVirtualKeyProviderConfig
entries (Provider and AllowAllKeys) so the resulting expanded slice and any
logs/serialization are deterministic; update the loop that currently ranges over
config.Providers to use the sorted names.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 48dd7c90-4ea5-4c97-a4bd-653c7441ea79

📥 Commits

Reviewing files that changed from the base of the PR and between 695fc49 and 736cc1f.

📒 Files selected for processing (8)
  • framework/configstore/clientconfig.go
  • framework/configstore/tables/encryption_test.go
  • framework/configstore/tables/init.go
  • framework/configstore/tables/virtualkey.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/main.go
  • transports/changelog.md
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • framework/configstore/clientconfig.go
  • ui/app/workspace/virtual-keys/views/virtualKeySheet.tsx
  • framework/configstore/tables/encryption_test.go

@Pratham-Mishra04 Pratham-Mishra04 changed the base branch from 03-10-feat_vk_provider_config_key_ids_now_supports_wildcard_to_allow_all_keys_empty_key_ids_denies_all to graphite-base/2008 March 16, 2026 17:27
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