Skip to content

[fix]: Helm chart - wire up MCP OAuth config and token_exchange auth - #6060

Closed
CallumWayve wants to merge 119 commits into
maximhq:devfrom
CallumWayve:helm-mcp-oauth-token-exchange
Closed

[fix]: Helm chart - wire up MCP OAuth config and token_exchange auth#6060
CallumWayve wants to merge 119 commits into
maximhq:devfrom
CallumWayve:helm-mcp-oauth-token-exchange

Conversation

@CallumWayve

@CallumWayve CallumWayve commented Aug 11, 2026

Copy link
Copy Markdown

Summary

transports/config.schema.json already supports an inline oauth_config bootstrap block and a token_exchange auth type for MCP clients (mcp.client_configs[]), but the Helm chart only exposed oauthConfigId — a field config.schema.json no longer even accepts (it referenced an API-created OAuth config row, not a static-config field), so any chart deployment that set it would silently fail schema validation. This wires up both auth modes so they can be defined declaratively in values.yaml.

Changes

  • Added mcp.clientConfigs[].oauthConfig (clientId, clientSecret, authorizeUrl, tokenUrl, registrationUrl, scopes) for authType: oauth / per_user_oauth, rendered into oauth_config. All fields are optional — missing URLs are discovered via RFC 8414, and a missing clientId triggers RFC 7591 dynamic client registration.
  • Added authType: token_exchange plus mcp.clientConfigs[].tokenExchange (audience, clientId, clientSecret, scopes) for delegated token-exchange auth, rendered into token_exchange.
  • Mirrored config.schema.json's conditional enforcement in values.schema.json: oauthConfig forbidden unless authType is oauth/per_user_oauth; tokenExchange required iff authType is token_exchange, forbidden otherwise.
  • Removed the stale oauthConfigId field/mapping since it's no longer valid against config.schema.json. This is technically a breaking change for any chart user who had set it (see Breaking changes below).
  • Updated values.yaml examples, .github/workflows/scripts/validate-helm-config-fields.sh fixtures/assertions, and the Helm README changelog (### 2.1.35 — unreleased; version bump/docs mdx/nav update happen separately at release time per this repo's convention).

Type of change

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

Affected areas

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

(Helm chart under helm-charts/bifrost/ — not listed as its own category above.)

How to test

# Full helm config field validation suite (364 assertions)
bash .github/workflows/scripts/validate-helm-config-fields.sh

# Valid oauthConfig / tokenExchange configs render successfully
helm template test helm-charts/bifrost -f values-good-oauth.yaml

# oauthConfig set under a non-oauth authType is correctly rejected
helm template test helm-charts/bifrost -f values-bad-oauth.yaml
# => Error: bifrost.mcp.clientConfigs.0: Must not validate the schema (not)

# authType: token_exchange without a tokenExchange block is correctly rejected
helm template test helm-charts/bifrost -f values-bad-token-exchange.yaml
# => Error: bifrost.mcp.clientConfigs.0: tokenExchange is required

Also validated the rendered config.json output against the real transports/config.schema.json via Python's jsonschema library — passes cleanly.

If adding new configs or environment variables, document them here.

New values.yaml fields: bifrost.mcp.clientConfigs[].oauthConfig.{clientId,clientSecret,authorizeUrl,tokenUrl,registrationUrl,scopes} and bifrost.mcp.clientConfigs[].tokenExchange.{audience,clientId,clientSecret,scopes}. No new environment variables — clientId/clientSecret values can reference env.VAR_NAME or vault.path as with existing secret-bearing fields.

Screenshots/Recordings

N/A — no UI changes.

Breaking changes

  • Yes
  • No

oauthConfigId is removed from the Helm values schema, but it was already non-functional: config.schema.json dropped oauth_config_id from mcp_client_config before this PR, so any chart deployment setting it would already fail schema validation upstream. No working deployment depended on it.

Related issues

N/A

Security considerations

oauthConfig.clientSecret and tokenExchange.clientSecret are secret-bearing fields, consistent with existing MCP client fields (e.g. headers, TLS config) — documented to support env.VAR_NAME / vault.path indirection rather than being hardcoded into values.yaml.

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

🤖 Generated with Claude Code

jeremym-tanium and others added 30 commits August 10, 2026 15:10
…iew maintenance (maximhq#5693)

* feat: support matview_refresh_interval "off" to disable logstore matview maintenance

The materialized views back only the dashboard UI. Deployments that run
Bifrost headless behind their own observability stack pay the REFRESH
MATERIALIZED VIEW CONCURRENTLY cost for views nothing reads, and the 5s
floor means the interval alone cannot turn maintenance off.

With "off" (or a non-positive duration) the logs store skips view
creation, the initial refresh, and the periodic refresher entirely.
matViewsReady stays false, so dashboard queries fall back to the raw
tables, and the runtime self-heal path cannot re-arm maintenance since
it only triggers from matview-path queries.

* fix: guard matview self-heal when maintenance is disabled

Review follow-up: carry the resolved disabled state onto the store so
triggerMatViewSelfHeal cannot recreate views the configuration says must
not exist, and make the schema/docs explicit that a zero duration also
disables (positive sub-5s values still clamp up).
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

* **Bug Fixes**
  * Improved token parameter compatibility handling to preserve alternative formats when the primary option is unsupported.

* **Chores**
  * Version updated to 2.0.0.
  * Enhanced load testing configuration for more reliable builds.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Briefly explain the purpose of this PR and the problem it solves.

- What was changed and why
- Any notable design decisions or trade-offs

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

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

Describe the steps to validate this change. Include commands and expected outcomes.

```sh
go version
go test ./...

cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

If adding new configs or environment variables, document them here.

If UI changes, add before/after screenshots or short clips.

- [ ] Yes
- [ ] No

If yes, describe impact and migration instructions.

Link related issues and discussions. Example: Closes maximhq#123

Note any security implications (auth, secrets, PII, sandboxing, etc.).

- [ ] 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
## Summary

Adds a `THIRD_PARTY_NOTICES.md` file to formally document third-party components used in Bifrost that carry license terms requiring explicit attribution — specifically MPL-2.0 licensed dependencies and embedded source code derived from external projects.

## Changes

- Introduces `THIRD_PARTY_NOTICES.md` to attribute:
  - Embedded source code in `framework/migrator/migrator.go` derived from `go-gormigrate/gormigrate` (MIT)
  - Go binary dependencies carrying MPL-2.0 terms: `github.com/cyphar/filepath-securejoin` and `github.com/hashicorp/go-version`
  - npm build-time devDependencies carrying MPL-2.0 terms: `lightningcss` (never shipped to end users) and `dompurify` (Apache-2.0 option elected)
- All MPL-2.0 components are used unmodified and combined as a "Larger Work" per MPL-2.0 Section 3.3; no Bifrost source files are themselves MPL-licensed.

## Type of change

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

## Affected areas

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

## How to test

No functional changes — review the file contents to confirm accuracy of license attributions against the listed upstream repositories.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

This change has no security implications. It is a legal/compliance attribution document only.

## Checklist

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

Briefly explain the purpose of this PR and the problem it solves.

## Changes

- What was changed and why
- Any notable design decisions or trade-offs

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

Describe the steps to validate this change. Include commands and expected outcomes.

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

If adding new configs or environment variables, document them here.

## Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

## Breaking changes

- [ ] Yes
- [ ] No

If yes, describe impact and migration instructions.

## Related issues

Link related issues and discussions. Example: Closes maximhq#123

## Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

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

Briefly explain the purpose of this PR and the problem it solves.

## Changes

- What was changed and why
- Any notable design decisions or trade-offs

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

Describe the steps to validate this change. Include commands and expected outcomes.

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

If adding new configs or environment variables, document them here.

## Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

## Breaking changes

- [ ] Yes
- [ ] No

If yes, describe impact and migration instructions.

## Related issues

Link related issues and discussions. Example: Closes maximhq#123

## Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

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

Briefly explain the purpose of this PR and the problem it solves.

## Changes

- What was changed and why
- Any notable design decisions or trade-offs

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

Describe the steps to validate this change. Include commands and expected outcomes.

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

If adding new configs or environment variables, document them here.

## Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

## Breaking changes

- [ ] Yes
- [ ] No

If yes, describe impact and migration instructions.

## Related issues

Link related issues and discussions. Example: Closes maximhq#123

## Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

## 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
…aximhq#5759)

## Summary

Closes a race-condition security gap where an unauthenticated network caller could reach a freshly deployed, not-yet-configured Bifrost instance and create the first admin account before the real operator does. Previously, `PUT /api/config` was intentionally open when no admin account existed (zero-config UX), but this left a window of exposure on any publicly reachable host.

The fix introduces a one-time **setup token** — generated in-memory at startup when no admin account is configured, printed to the server's startup logs, and required alongside the username/password when creating the first admin account. The token is never persisted, is regenerated on every restart until an admin account exists, and is permanently invalidated once the first admin account is created.

## Changes

- **Bootstrap token generation (`middlewares.go`):** `InitAuthMiddleware` generates a UUID setup token via `atomic.Pointer[string]` when no admin account is configured, logs it prominently to stdout, and exposes `CheckBootstrapToken` (constant-time comparison) and `ClearBootstrapToken` methods.
- **Token validation in the config handler (`config.go`):** `updateConfig` now calls `ValidateSetupToken` before allowing the first admin account to be created. Returns HTTP 403 if the token is missing or wrong.
- **Token cleared on first admin account creation (`server.go`):** `UpdateAuthConfig` calls `ClearBootstrapToken` after successfully persisting the first admin account, permanently closing the gate.
- **`setup_token`** **field added to** **`UpdateConfigRequest`:** The field is accepted in the request body but never persisted or returned by `GET /api/config`.
- **UI (`securityView.tsx`):** When no `auth_config` exists server-side (`isFirstTimeSetup`), a **Setup token** input field is shown below the password field. The token is validated client-side before submission and cleared from state after a successful save.
- **TypeScript types (`config.ts`):** `setup_token?: string` added to `BifrostConfig`.
- **OpenAPI schema (`config.yaml`):** `setup_token` documented on `UpdateConfigRequest`.
- **Docs:** A `<Warning>` block added to `security-best-practices.mdx` and a `<Note>` added to `setting-up-auth.mdx` explaining the setup token flow, where to find it, and that it only applies once.
- **Tests (`middlewares_test.go`):** Two new test cases cover the no-token-generated (pass-through) case and the validate-then-clear lifecycle.

## Type of change

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

## Affected areas

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

## How to test

**Manual flow:**

1. Start a fresh Bifrost instance with no existing admin account.
2. Check startup logs for the block beginning `No admin account is configured for this Bifrost instance yet.` and copy the setup token.
3. Open the dashboard → Security Settings. Confirm the **Setup token** field appears below the password field.
4. Attempt to save with auth enabled but without the setup token — expect a toast error.
5. Paste the correct token and save — expect success and the Setup token field to disappear on reload.
6. Confirm that `PUT /api/config` without the token returns HTTP 403 while no admin account exists.
7. Restart the server before completing setup and confirm a new token is printed.

```sh
# Core/Transports
go test ./transports/bifrost-http/handlers/...

# UI
cd ui
pnpm i
pnpm build
```

## Breaking changes

- [x] Yes
- [ ] No

Any automation or scripts that call `PUT /api/config` to create the first admin account on a fresh instance must now include `setup_token` in the request body. The token is available in the server's startup logs. Instances that already have an admin account configured are unaffected — the field is ignored once an admin account exists.

## Security considerations

- The setup token is generated with `uuid.NewString()` (crypto-random UUID), stored only in process memory, and compared with `crypto/subtle.ConstantTimeCompare` to prevent timing attacks.
- The token is never written to disk, never returned by any API endpoint, and is permanently invalidated after first use.
- Operators must have access to the process's stdout/log stream (`docker logs`, `kubectl logs`, or terminal) to retrieve the token, which is the same access level required to operate the host — this is the intended trust boundary.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicablecg
## Summary

Briefly explain the purpose of this PR and the problem it solves.

## Changes

- What was changed and why
- Any notable design decisions or trade-offs

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

Describe the steps to validate this change. Include commands and expected outcomes.

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

If adding new configs or environment variables, document them here.

## Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

## Breaking changes

- [ ] Yes
- [ ] No

If yes, describe impact and migration instructions.

## Related issues

Link related issues and discussions. Example: Closes maximhq#123

## Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

## 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
Loading a custom plugin `path` causes native code (a `.so`) to be `dlopen()`'d directly into the gateway process. Previously, this was allowed even when dashboard authentication was disabled or unconfigured — meaning any caller who could reach the management API could inject arbitrary native code. This PR closes that gap by requiring a genuinely authenticated admin session for any create or update operation that sets a non-builtin plugin `path`, and separately hardens the plugin downloader against SSRF.

- Added `BifrostContextKeyAuthBypassed` context key, set by the auth middleware exclusively when a request is let through because dashboard auth is disabled/unconfigured (distinct from `IsLocalAdminContextKey`, which is also set on real authenticated sessions).
- `createPlugin` and `updatePlugin` handlers now check `BifrostContextKeyAuthBypassed` and return `403` before any DB write when a non-builtin `path` is supplied without genuine authentication.
- Replaced the `fasthttp`-based plugin downloader with a `net/http` client backed by `network.SSRFSafeDialContext`, matching the SSRF hardening already applied to `core/providers/utils.FetchAndEncodeURL`. The new client: rejects non-`http`/`https` schemes before any network call, refuses connections to loopback, private, CGNAT, link-local, and unspecified addresses (including IPv4-in-IPv6 transition addresses) at dial time (not just DNS lookup time, so DNS rebinding doesn't bypass it), applies the same IP check to redirect targets, caps redirect depth at 5, and limits response body reads to 200 MB.
- Tests for `DownloadPlugin` now use a `useNonSSRFGuardedClient` helper that swaps in a plain dialer for the duration of each test (since `httptest` servers bind to loopback, which the production dialer correctly blocks). A new `TestDownloadPlugin_BlocksSSRFToLoopback` test verifies the production guard is active by default, and `TestDownloadPlugin_RejectsNonHTTPScheme` verifies `file://` and similar schemes are rejected before any network call.
- New handler tests cover all four cases: create with bypassed auth (expect 403, no DB write), create with real auth (expect 201, path stored), update with bypassed auth (expect 403, no DB write), and the existing config-merge behaviour.
- OpenAPI docs and the plugin sequencing guide updated to document the 403 response and the authentication requirement for `path`.
- Dependency bumps: `aws-sdk-go-v2/config` → v1.32.14, `aws-sdk-go-v2/service/s3` → v1.99.0, `aws-sdk-go-v2/internal/ini` → v1.8.6, `buger/jsonparser` → v1.2.0.

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

> This is primarily a security hardening change.

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

```sh
go test ./...

go test ./transports/bifrost-http/handlers/... -run TestCreatePlugin_RejectsCustomPathWhenAuthBypassed
go test ./transports/bifrost-http/handlers/... -run TestCreatePlugin_AllowsCustomPathWhenNotBypassed
go test ./transports/bifrost-http/handlers/... -run TestUpdatePlugin_RejectsCustomPathWhenAuthBypassed

go test ./framework/plugins/... -run TestDownloadPlugin_BlocksSSRFToLoopback
go test ./framework/plugins/... -run TestDownloadPlugin_RejectsNonHTTPScheme
```

To manually verify the 403 behaviour: start the gateway with no dashboard auth configured, then attempt `POST /api/plugins` with a `path` field pointing to a `.so`. The response should be `403` with a message instructing the operator to enable dashboard authentication first.

- [x] Yes
- [ ] No

Operators running with dashboard authentication disabled who were previously able to create or update custom plugin paths via the API will now receive a `403`. To restore the capability, enable dashboard authentication and authenticate before calling those endpoints.

- Closes an unauthenticated native code injection vector: without this change, any network-reachable caller could `dlopen()` an attacker-controlled `.so` into the gateway process when dashboard auth was off.
- The SSRF fix on the plugin downloader prevents a crafted plugin URL from causing the gateway to fetch from internal/metadata endpoints (e.g. cloud IMDS). The guard runs at dial time, not DNS resolution time, so DNS rebinding attacks do not bypass it.
- `BifrostContextKeyAuthBypassed` is intentionally separate from `IsLocalAdminContextKey` so that future handlers gating other high-risk operations can use the same signal without ambiguity.

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

Resolves merge conflicts in `core/go.sum` that were left over from merging the path normalization auth bypass fix (maximhq#5763).

## Changes

- Removed leftover `<<<<<<< HEAD`, `=======`, and `>>>>>>> e0057ff` conflict markers from `core/go.sum`
- Retained the correct `go.mod` hash lines for `aws-sdk-go-v2/config`, `aws-sdk-go-v2/internal/ini`, and `aws-sdk-go-v2/service/s3` that were dropped during the conflict

## Type of change

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

## Affected areas

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

## How to test

```sh
cd core
go mod verify
go test ./...
```

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

Closes maximhq#5763

## Security considerations

No security implications. This is a cleanup of unresolved merge conflict markers in the dependency lockfile.

## Checklist

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

Adds a dedicated **MCP Guardrails** section to the guardrails documentation, explaining how guardrails apply at the tool-execution boundary for MCP targets, including phase behavior, UI field descriptions, and provider compatibility notes.

## Changes

- Replaced the brief inline mention of MCP rule behavior in the Architecture section with a cross-reference link to the new dedicated section.
- Added a new `## MCP Guardrails` section covering:
  - How `input`, `output`, and `both` phases apply at the tool-execution boundary.
  - A table describing the flow and block behavior for each phase.
  - Guidance on selecting MCP clients, tools, and tool arguments when creating rules.
  - A note clarifying that all supported guardrail providers work with MCP rules and that redaction support follows the same provider constraints as LLM rules.
  - Cross-references to existing sections for rule configuration and CEL expression examples.
- Added a screenshot (`ui-mcp-guardrail-rule.png`) showing the MCP guardrail rule editor in the UI.

## Type of change

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

## Affected areas

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

## How to test

Navigate to the rendered guardrails documentation page and verify:
- The Architecture section links to `#mcp-guardrails` instead of containing inline MCP text.
- The new MCP Guardrails section renders correctly with the phase table, screenshot, and note.
- The screenshot image loads without errors.

## Screenshots/Recordings

The new section includes a screenshot of the MCP guardrail rule editor (`ui-mcp-guardrail-rule.png`).

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

None. Documentation-only change.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
…#5962)

Fix the budget override **Valid until** preview for calendar-aligned budgets.
The UI now calculates expiry from the current UTC calendar-period boundary
instead of directly from a preserved, mid-period `last_reset` timestamp.

For example, a monthly calendar-aligned budget with `last_reset = Aug 3` should
expire at the next monthly boundary on Sep 1, not Sep 3:

```text
Aug 1 00:00 UTC                 Aug 3                 Sep 1 00:00 UTC
       |--------------------------|--------------------------|
       calendar period start      last_reset                 valid until

Old UI: Aug 3 + 1 month  -> Sep 3 08:59 UTC
New UI: Aug 1 + 1 month  -> Sep 1 00:00 UTC
```

The backend override cycle was already correct; this only fixes the date
displayed by the UI.

- Added a helper that snaps calendar-aligned reset timestamps to their current
  UTC period boundary:
  - Day: 00:00 UTC on the current day
  - Week: Monday at 00:00 UTC
  - Month: first day of the month at 00:00 UTC
  - Year: January 1 at 00:00 UTC
- Applied that boundary before adding override cycles in
  `getBudgetOverrideValidUntil`.
- Kept rolling and sub-day calculations unchanged.
- Added regression coverage for daily, weekly, monthly, and yearly
  calendar-aligned overrides.

The calculation now follows this flow:

```text
preserved last_reset
   Aug 3 08:59
        |
        v
snap to calendar period
   Aug 1 00:00
        |
        v
add one monthly cycle
   Sep 1 00:00
```

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

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

Run the focused utility tests:

```sh
cd ui
npx vitest run lib/utils/governance.test.ts
```

Expected outcome:

```text
Test Files  1 passed
Tests       5 passed
```

Run the TypeScript typecheck:

```sh
cd ui
npm run typecheck
```

Expected outcome: the command completes without TypeScript errors.

The regression test verifies these representative cases:

```text
Monthly: Aug 3 08:59 + 1 cycle -> Sep 1 00:00 UTC
Weekly:  Wed Aug 5 + 1 cycle    -> Mon Aug 10 00:00 UTC
Daily:   Aug 3 08:59 + 1 cycle -> Aug 4 00:00 UTC
Yearly:  Aug 3 2026 + 1 cycle  -> Jan 1 2027 00:00 UTC
```

No new configuration or environment variables are introduced.

Not included. This changes the date calculation behind the existing **Valid
until** field without changing the UI layout.

Before:

```text
Valid until: Sep 3, 2026
```

After:

```text
Valid until: Sep 1, 2026
```

- [ ] Yes
- [x] No

No linked issue.

No security implications. This change only adjusts a client-side date preview
and does not affect authentication, authorization, secrets, PII, or backend
enforcement.

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable
…ootstrap cleanup failure

- initiateMCPClientVerification now checks h.store.ConfigStore for nil
  before dereferencing, matching every other handler in this file.
- pendingOAuthConfigToRequest now carries the config.json oauth_config's
  Resource (RFC 8707) into the OAuth initiation request instead of
  silently dropping it.
- completeMCPClientOAuth now reports failure (mirroring the existing
  [PARTIAL SUCCESS] pattern used for the VK-assignment case) when
  clearing a config.json client's pending-bootstrap stash fails, instead
  of returning success while DB state can regress the client to
  pending_verification after a restart.
…r-safe bootstrap authorize flow, handle OAuth 409 conflict
…r-user-header fields on OAuth-completion updates
…_type

The Authorize/Verify label ternary keyed off auth_type === 'oauth', but
handleStartBootstrap's OAuth-based path is the same one-time admin
verification step for every pending_verification client — oauth and
per_user_oauth alike. Drop the ternary and always show "Authorize".
…en perf fixtures so the migration's join is exercised, not just its miss path
…losed on missing tool annotations, dedupe background reconnect
Per-user auth types now show the same connection-state badge as every
other client instead of a session-list link, keeping the edit sheet's
header consistent across auth types.
… on the actions trigger

Reauthorize appeared for every client whose state wasn't
pending_verification/disabled, including non-OAuth and per-user OAuth
clients — but reauthorizeMCPClient 400s on any auth_type other than
'oauth'. Gate the menu item on auth_type === 'oauth' as well, keeping
the existing state condition (the endpoint has no state precondition
of its own, and a later per_user_oauth extension of this same block
relies on that state condition staying broad).

isReauthorizing already disabled the menu item, but onSelect closes
the menu immediately, so the trigger kept showing MoreHorizontal with
no visible feedback while the request ran. The trigger now also
spins and disables during reauthorization, matching the existing
isReconnecting behavior.
impoiler and others added 11 commits August 11, 2026 00:05
## Summary

Briefly explain the purpose of this PR and the problem it solves.

## Changes

- What was changed and why
- Any notable design decisions or trade-offs

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

Describe the steps to validate this change. Include commands and expected outcomes.

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

If adding new configs or environment variables, document them here.

## Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

## Breaking changes

- [ ] Yes
- [ ] No

If yes, describe impact and migration instructions.

## Related issues

Link related issues and discussions. Example: Closes maximhq#123

## Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

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

Briefly explain the purpose of this PR and the problem it solves.

## Changes

- What was changed and why
- Any notable design decisions or trade-offs

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

Describe the steps to validate this change. Include commands and expected outcomes.

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

If adding new configs or environment variables, document them here.

## Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

## Breaking changes

- [ ] Yes
- [ ] No

If yes, describe impact and migration instructions.

## Related issues

Link related issues and discussions. Example: Closes maximhq#123

## Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

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

Extends environment variable substitution support to the `service_name`, `ml_app`, `env`, and `version` fields in the Datadog integration configuration, allowing these values to be sourced dynamically from environment variables at runtime.

## Changes

- Added `env.VAR_NAME` support notation to the `service_name`, `ml_app`, `env`, and `version` fields in the configuration reference table
- Updated the Environment Variable Substitution section to include `service_name`, `ml_app`, `env`, and `version` in the list of supported fields
- Added example usage of `env.BIFROST_DD_SERVICE`, `env.BIFROST_DD_ENV`, and `env.BIFROST_DD_VERSION` in the JSON code snippet

## Type of change

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

## Affected areas

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

## How to test

Review the updated Datadog observability documentation to confirm the configuration table and environment variable substitution section accurately reflect the supported fields and example usage.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

No security implications. This change only updates documentation to reflect existing or newly supported environment variable substitution behavior, which helps avoid hardcoding sensitive or environment-specific values in configuration files.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
…hq#6017)

## Summary

Adds end-to-end API tests for the virtual key budget override endpoints, covering both applying and removing a budget override on a virtual key.

## Changes

- Added `vk_budget_id` and `vk_budget_max_limit` as collection variables, populated dynamically from the first budget returned when fetching a virtual key.
- Added a **Set Virtual Key Budget Override** test (`PUT /api/governance/virtual-keys/{vk_id}/budgets/{vk_budget_id}/override`) that applies an override of `7.5` with mode `forever` and asserts the response contains the correct `override_mode`, `override_amount`, and that the `effective_max_limit` is raised above the base budget.
- Added a **Remove Virtual Key Budget Override** test (`DELETE /api/governance/virtual-keys/{vk_id}/budgets/{vk_budget_id}/override`) that clears the override and asserts `override_mode` and `override_amount` are empty/zero, and that `effective_max_limit` falls back to the original base budget value.

## Type of change

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

## Affected areas

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

## How to test

Run the Postman collection against a running Bifrost instance:

```sh
newman run tests/e2e/api/collections/bifrost-api-management.postman_collection.json \
  --env-var base_url=http://localhost:8080
```

The **Set Virtual Key Budget Override** and **Remove Virtual Key Budget Override** requests will execute after the virtual key fetch step, which populates `vk_budget_id` and `vk_budget_max_limit`. Both requests will be skipped automatically if no budget ID is available.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

No security implications. Tests exercise existing governance endpoints using collection-scoped variables only.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
…rrect describe block (maximhq#6048)

## Summary

A test for calendar-aligned budget override validity was accidentally nested inside an unrelated `it` block in the `budgetSignature without ids` describe block, causing it to never actually run. This PR moves the test to the correct location within the `budget overrides` describe block.

## Changes

- Removed the misplaced `it("anchors calendar-aligned validity to the current period boundary", ...)` block that was nested inside the `budgetSignature without ids` test, where it would never execute
- Added the same test cases correctly at the top level of the `budget overrides` describe block, where they are properly registered and run

## Type of change

- [x] Bug fix

## Affected areas

- [x] UI (React)

## How to test

```sh
cd ui
pnpm i || npm i
pnpm test || npm test
```

The previously dormant test cases for `getBudgetOverrideValidUntil` with monthly, weekly, daily, and yearly reset durations should now execute and pass.

## Breaking changes

- [x] No

## Related issues

## Security considerations

None.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
…ximhq#6049)

## Summary

Adds `needs_session_stickiness: true` to the MCP client creation request in the end-to-end API test collection, ensuring the test accurately reflects the expected payload for MCP clients that require session stickiness.

## Changes

- Added `needs_session_stickiness: true` to the raw request body in the `bifrost-api-management` Postman collection for the MCP client creation endpoint.

## Type of change

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

## Affected areas

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

## How to test

Run the Postman collection against a running Bifrost instance and verify the MCP client creation request succeeds with the `needs_session_stickiness` field included.

```sh
go test ./...
```

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

No security implications. This change only adds a session stickiness flag to a test request payload.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] 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
## Summary

Updates the documentation URL for custom pricing overrides to reflect the correct path in the docs site.

## Changes

- Updated `PRICING_OVERRIDES_DOCS_URL` from `https://docs.getbifrost.ai/features/governance/custom-pricing` to `https://docs.getbifrost.ai/providers/custom-pricing` to point to the accurate documentation location.

## Type of change

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

## Affected areas

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

## How to test

Navigate to the custom pricing overrides empty state in the UI and click the documentation link. Verify it redirects to `https://docs.getbifrost.ai/providers/custom-pricing`.

```sh
cd ui
pnpm i || npm i
pnpm build || npm run build
```

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

None.

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

Fix Realtime input guardrails so they inspect prompt content supplied directly
in a valid `response.create` event.

Previously, Realtime pre-hooks only received conversation items accumulated
before the turn. A request that placed its prompt in `response.instructions` or
`response.input` was forwarded to the provider correctly, but those fields were
absent from the normalized request evaluated by guardrails. This caused
equivalent non-Realtime requests to be blocked while valid Realtime requests
could pass.

## Changes

- Pass the complete turn-start event into the Realtime pre-hook pipeline for
  both WebSocket and WebRTC transports.
- Extract `response.instructions`, `response.input`, and response-level
  `response.tools` from `response.create`.
- Combine inline response input with previously accumulated conversation input
  before running pre-hooks.
- Prefer response-level tools for that turn, falling back to session-level tools
  when no response-level tools are supplied.
- Preserve the existing behavior for turn starts that do not carry a `response`
  payload.
- Add regression tests for direct `response.create` content and mixed
  conversation/inline input.

### Before

A valid request could send all prompt content in `response.create`:

```json
{
  "type": "response.create",
  "response": {
    "output_modalities": ["text"],
    "instructions": "<some stuff that should be flagged>"
  }
}
```

The provider received the instructions, but the guardrail request was
effectively empty:

```text
response.create
  ├── response.instructions ───────────────► provider
  └── accumulated conversation (empty) ───► input guardrails

Result: the model generated a response even when the same prompt was blocked through the Responses API.
```

### After

The turn-start event is now included while constructing the request inspected by
pre-hooks:

```text
response.create
  ├── accumulated conversation ─┐
  ├── response.input ────────────┼──► normalized Realtime request ──► input guardrails
  ├── response.instructions ─────┤
  └── response.tools ────────────┘
                                      │
                                      ├── allowed ─► provider
                                      └── blocked ─► error returned; event is not forwarded
```

This also supports combining conversational and response-specific input:

```json
// Earlier event
{
  "type": "conversation.item.create",
  "item": {
    "type": "message",
    "role": "user",
    "content": [{ "type": "input_text", "text": "conversation context" }]
  }
}

// Turn-start event
{
  "type": "response.create",
  "response": {
    "instructions": "answer in one sentence",
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": "inline request"
      }
    ]
  }
}
```

Both `conversation context` and `inline request`, together with the
instructions, are now visible to the input guardrail pipeline.

## Type of change

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

## Affected areas

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

## How to test

Run the focused regression tests:

```sh
go test ./transports/bifrost-http/handlers -run 'TestBuildRealtimeTurnPreRequest|TestPendingRealtimeInputUpdate'
```

Expected outcome: the tests pass and confirm that:

- `response.instructions`, inline `response.input`, and response-level tools are
  present in the pre-hook request;
- accumulated conversation input and inline response input are combined.

Run the complete handler test package:

```sh
go test ./transports/bifrost-http/handlers
```

Expected outcome: all handler tests pass.

No new configuration or environment variables are required.

## Screenshots/Recordings

Not applicable; this change affects Realtime request processing.

## Breaking changes

- [ ] Yes
- [x] No

Existing conversation-item flows continue to work. Valid `response.create`
prompt fields now receive the same input guardrail coverage.

## Related issues

No linked issue.

## Security considerations

This closes a guardrail coverage gap. Prompt content sent through
`response.create` is now evaluated before the event is forwarded to the Realtime
provider. No secrets, authentication behavior, or stored data formats are
changed.

This change concerns input enforcement only; it does not alter the existing
post-turn behavior of Realtime output guardrails.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed (not required for this internal
      behavior fix)
- [x] I verified builds succeed (Go and UI) (affected Go handler package
      verified; UI not affected)
- [x] I verified the CI pipeline passes locally if applicable (focused and
      complete handler tests pass)
MCPClientConfig.PerUserHeaderKeys (per_user_header_keys) is required
(non-empty) for authType per_user_headers MCP clients, but the
clientConfigs -> config.json template in _helpers.tpl never mapped it,
so it silently dropped out of Helm-rendered config regardless of what
was set in values.yaml. values.schema.json also never declared the
property. Fixes maximhq#6033.

Affected packages:
- helm-charts/bifrost/values.schema.json
- helm-charts/bifrost/templates/_helpers.tpl
- helm-charts/bifrost/values.yaml
- helm-charts/bifrost/README.md
- .github/workflows/scripts/validate-helm-config-fields.sh
…er_headers

Address review feedback on the previous commit:
- values.schema.json now requires perUserHeaderKeys (non-empty, no
  whitespace-only entries) via an allOf/if/then keyed on authType, scoped
  to per_user_headers only — other auth types are unaffected.
- values.yaml's per_user_headers example used a bare connectionString
  with connectionType: http, which the schema requires httpConfig for;
  fixed to use httpConfig.url like the adjacent http example.

Affected packages:
- helm-charts/bifrost/values.schema.json
- helm-charts/bifrost/values.yaml
transports/config.schema.json already supports an inline oauth_config
bootstrap block and a token_exchange auth type for MCP clients, but
the Helm chart only exposed oauthConfigId - a field config.schema.json
no longer even accepts (it referenced an API-created OAuth config row,
not a static-config field), so setting it would silently fail schema
validation.

Adds mcp.clientConfigs[].oauthConfig (clientId, clientSecret,
authorizeUrl, tokenUrl, registrationUrl, scopes) and .tokenExchange
(audience, clientId, clientSecret, scopes), rendered into oauth_config
and token_exchange respectively, with the same conditional enforcement
config.schema.json uses (oauthConfig forbidden unless authType is
oauth/per_user_oauth, tokenExchange required iff authType is
token_exchange). Also adds token_exchange to the authType enum.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@CallumWayve
CallumWayve requested a review from a team as a code owner August 11, 2026 10:37
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b9808471-44e5-4596-bd68-19e984c41ace

📥 Commits

Reviewing files that changed from the base of the PR and between f3d20b2 and f2046df.

📒 Files selected for processing (2)
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • helm-charts/bifrost/values.yaml
  • helm-charts/bifrost/values.schema.json

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added Helm support for MCP per-user header authentication.
    • Added token-exchange authentication with audience, credentials, and scope settings.
    • Added inline OAuth configuration, replacing OAuth configuration ID references.
  • Bug Fixes
    • Improved validation for complete and compatible authentication settings.
  • Documentation
    • Updated Helm examples and changelog with new MCP authentication options.
  • Tests
    • Added validation coverage for headers, OAuth, and token-exchange configurations.

Walkthrough

MCP Helm configuration now supports per-user header keys, inline OAuth settings, and token-exchange authentication. The schema validates conditional fields, templates render nested authentication objects, examples document the new values, and workflow checks verify rendered output.

Changes

MCP Helm authentication

Layer / File(s) Summary
Authentication schemas and examples
helm-charts/bifrost/values.schema.json, helm-charts/bifrost/values.yaml, helm-charts/bifrost/README.md
The schema, examples, and changelog define inline OAuth, token exchange, and per-user header settings. Conditional validation replaces oauthConfigId.
Authentication configuration rendering
helm-charts/bifrost/templates/_helpers.tpl
The Helm template renders oauth_config, token_exchange, and per_user_header_keys from camelCase values.
Rendered configuration validation
.github/workflows/scripts/validate-helm-config-fields.sh
Workflow fixtures and assertions verify authentication types and their configured fields.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant HelmValues
  participant ValuesSchema
  participant HelmHelpers
  participant ValidationScript
  HelmValues->>ValuesSchema: Validate MCP authentication fields
  ValuesSchema->>HelmHelpers: Provide accepted configuration
  HelmHelpers->>ValidationScript: Produce rendered MCP configuration
  ValidationScript->>ValidationScript: Assert authentication fields
Loading

Possibly related PRs

  • maximhq/bifrost#6034: Adds the related perUserHeaderKeys schema, template mapping, examples, documentation, and validation changes.

Suggested reviewers: akshaydeo, bearts, roroghost17

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the Helm chart changes for MCP OAuth configuration and token-exchange authentication.
Description check ✅ Passed The description covers the required sections, explains the changes and compatibility impact, and provides test commands and security considerations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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 `@helm-charts/bifrost/values.schema.json`:
- Around line 6165-6180: Update the mcpClientConfig schema rule around the
authType conditional in helm-charts/bifrost/values.schema.json lines 6165-6180
to reject the removed oauthConfigId property, either by adding a not rule or by
disallowing undeclared properties while preserving supported fields. In
helm-charts/bifrost/README.md line 17, keep the schema-rejection statement only
once the schema enforces this rejection.

In `@helm-charts/bifrost/values.yaml`:
- Around line 515-530: Update the commented “example-oauth-mcp” configuration in
values.yaml to replace connectionString with the required httpConfig.url
structure, while preserving the existing HTTP endpoint and OAuth settings so the
example passes the schema when enabled.
🪄 Autofix

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: 026187ca-2d15-4b12-b17a-be15d2fcba32

📥 Commits

Reviewing files that changed from the base of the PR and between c01a0a2 and f3d20b2.

📒 Files selected for processing (5)
  • .github/workflows/scripts/validate-helm-config-fields.sh
  • helm-charts/bifrost/README.md
  • helm-charts/bifrost/templates/_helpers.tpl
  • helm-charts/bifrost/values.schema.json
  • helm-charts/bifrost/values.yaml

Comment thread helm-charts/bifrost/values.schema.json
Comment thread helm-charts/bifrost/values.yaml
…sage

Removing the oauthConfigId property definition wasn't enough on its own -
without additionalProperties:false at this level, the field was still
silently accepted by schema validation and then dropped by _helpers.tpl.
Add an explicit not/required rule so it's rejected outright, matching
config.schema.json's behavior.

Also fixes the example-oauth-mcp comment block in values.yaml, which used
a bare connectionString with connectionType: http - the schema requires
httpConfig for that connection type, and _helpers.tpl only maps
connectionString for sse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 11, 2026
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.