Fix bedrock mantle streaming 5871 - #5872
Conversation
…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 -->
## 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 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
…aximhq#5805) * [fix]: clear stuck entity-assignment validation on virtual key sheet Eager trigger on assignment-type changes left a refine error on entityType that selecting a team/customer never cleared; also align the assignment controls to items-start. Co-authored-by: Cursor <cursoragent@cursor.com> * [docs]: add before/after screenshots for virtual key entity-assignment fix Co-authored-by: Cursor <cursoragent@cursor.com> * [docs]: add on-submit validation screenshot for entity-assignment fix Co-authored-by: Cursor <cursoragent@cursor.com> * [chore]: remove PR screenshots from .github/assets Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
…ntainers are not relabelled (maximhq#5823)
maximhq#5847) ## Summary Provider-specific model IDs (e.g. Bedrock cross-region inference profiles, dated OpenAI/Anthropic snapshots) were creating separate metric series for what is logically the same model. This PR introduces a `NormalizeModelName` function that strips vendor/region prefixes, Bedrock version suffixes, and trailing date/version segments before model names are used as metric labels, preventing cardinality explosion in Prometheus and OTel metrics. Additionally, pre-dispatch rejections where both provider and model are empty are now skipped entirely to avoid polluting metric series with empty labels. ## Changes - Added `NormalizeModelName` in `core/schemas/utils.go` that: - Strips Bedrock region and vendor prefixes (e.g. `us.anthropic.`, `anthropic.`) using a regex that only matches letter/hyphen tokens, leaving digit-dotted names like `gpt-3.5-turbo` and `gemini-1.5-pro` untouched - Strips Bedrock version suffixes (e.g. `-v1:0`) - Delegates to the existing `BaseModelName` to strip trailing date/version segments - Preserves OpenAI fine-tune IDs (`ft:...`) as-is - Trims surrounding whitespace, collapsing blank input to `""` - Applied `NormalizeModelName` to the model label in both the Prometheus plugin (`PostLLMHook`) and the OTel plugin (`buildSpanAttrs`, `buildContextAttrs`) - Added early-return guards in both plugins when provider and model are both empty, skipping metric recording for pre-dispatch rejections - Added a comprehensive test suite for `NormalizeModelName` covering Bedrock inference profiles, OpenAI dated snapshots, Anthropic dated names, digit-dotted names, fine-tune IDs, whitespace, and empty input ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/schemas/... -run TestNormalizeModelName -v go test ./plugins/otel/... go test ./plugins/telemetry/... go test ./... ``` Expected: all tests pass, and metrics emitted for Bedrock inference profile model IDs (e.g. `us.anthropic.claude-opus-4-20250101-v1:0`) use the normalized label `claude-opus-4` rather than the full provider-specific string. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations None. This change only affects metric label values and does not touch auth, secrets, or PII handling. ## 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
…#5848) ## Summary Adds support for multi-valued team, customer, and business unit identity dimensions in telemetry and metrics. Previously, only a single scalar value per dimension was recorded. This PR introduces a `CanonicalEntitySet` utility that deduplicates, sorts, and comma-joins parallel id/name arrays into stable strings, ensuring the same set of entities always produces the same metric label value regardless of input ordering. ## Changes - Added `CanonicalEntitySet` in `core/schemas/utils.go` that accepts index-aligned id/name slices, drops empty ids, deduplicates by id (keeping the first name), sorts by id, and returns comma-joined `(idsCSV, namesCSV)` strings. - Added `canonicalentityset_test.go` covering empty input, single values, sorted/deduped sets, duplicate ids, missing names, and empty id filtering. - Added `getStringSliceAttr` in the otel plugin to tolerate both `[]string` and `[]any` encodings of array-valued span attributes. - Added `entitySetFromAttrs` and `entitySetFromContext` helpers in the otel plugin that resolve a dimension from the plural governance arrays when present, falling back to the scalar as a set of one. - Added `canonicalEntitySet` helper in the telemetry plugin with the same fallback logic for the Prometheus path. - Extended `BuildBifrostAttributes` to accept and emit `business_unit_id`/`business_unit_name` attributes alongside the existing team and customer dimensions. - All label names remain singular (`team_id`, `customer_id`, `business_unit_id`) for dashboard backward-compatibility; the values are now canonical comma-joined sets. ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/schemas/... -run TestCanonicalEntitySet -v go test ./plugins/otel/... ./plugins/telemetry/... go test ./... ``` Verify that a request carrying multiple team ids (e.g. `["t1","t2"]`) produces a `team_id` label of `"t1,t2"` (sorted) in both Prometheus metrics and OTel span attributes, and that a single-team request continues to produce the same label format as before. ## Screenshots/Recordings N/A ## Breaking changes - [ ] Yes - [x] No The `BuildBifrostAttributes` function signature has changed (two new parameters added for `businessUnitIDs`/`businessUnitNames`, and scalar team/customer args replaced with their CSV equivalents). Any direct callers outside this repo will need to update their call sites. ## Related issues N/A ## Security considerations Label values are derived from governance context keys set server-side. No user-supplied PII is introduced beyond what was already present in the scalar team/customer labels. ## 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
## Summary Several correctness fixes across model name normalization, OTel metrics alignment, and Prometheus active-request tracking. The common theme is preventing data loss or label pollution caused by edge-case inputs (fine-tune model IDs with date-like suffixes, mixed-type attribute arrays, spans with no provider/model, and pre-dispatch rejections that left active-request counters incremented). ## Changes - **`NormalizeModelName` fine-tune short-circuit**: OpenAI fine-tune IDs prefixed with `ft:` are now returned immediately before `BaseModelName` is called, preventing a date-like custom suffix (e.g. `custom-20250514`) from being stripped as if it were a Bedrock version tag. - **`getStringSliceAttr` index preservation**: When a `[]any` attribute value contains non-string elements, the slot is now kept as an empty string rather than being dropped. This keeps id and name arrays index-aligned so that `entitySetFromAttrs` can correctly pair and filter them. - **OTel span filtering**: Spans with both an empty provider and an empty model are skipped before final-span selection in `recordMetricsFromTrace`, preventing empty-label metric series from being emitted. - **`serviceInstanceID` as a package-level variable**: The hostname/fallback resolution is now computed once at startup and reused in both the resource attribute and as a `service_instance_id` datapoint label, so per-replica breakdown survives collector configurations that drop resource attributes. - **Prometheus `ActiveRequests` decrement on pre-dispatch rejection**: `PostLLMHook` now decrements `ActiveRequests` before returning early for no-provider/no-model requests, fixing a counter leak introduced when `PreLLMHook` incremented it. - **Key rotation event uses normalized model name**: `KeyRotationEventsTotal` now records the normalized `model` value instead of `originalModel`, keeping label values consistent with other metrics. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [x] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/schemas/... ./plugins/otel/... ./plugins/telemetry/... ``` - `TestNormalizeModelName` covers the new `ft:gpt-4o-mini:acme:custom-20250514` case. - `TestGetStringSliceAttr_AnyPreservesIndex` verifies that non-string elements produce an empty string at the correct index. - `TestEntitySetFromAttrs_MixedAnyKeepsAlignment` verifies that a non-string ID element drops both that ID and its paired name without shifting remaining entries. ## Breaking changes - [ ] Yes - [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
…cing overrides OpenAPI spec (maximhq#5852) ## Summary Extends the Pricing Overrides API with user-scoped override support, pagination/search on the list endpoint, and a significantly expanded set of priceable fields covering new token tiers, cache variants, image quality/size tiers, and OCR costs. ## Changes - Introduced a shared `PricingOverrideScopeKind` schema component, replacing inline enum definitions across `PricingOverride`, `CreatePricingOverrideRequest`, `UpdatePricingOverrideRequest`, and the list query parameter. The enum now includes three new `user*` scopes: `user`, `user_provider`, and `user_provider_key`. Resolution priority is documented: `virtual_key*` > `user*` > `provider`/`global`, with more-specific matches winning within a family. - Added `user_id` field to override request/response schemas and as a query filter on the list endpoint, required when using `user*` scopes. - Updated `provider_id` and `provider_key_id` descriptions to reflect their applicability to the new `user_provider` and `user_provider_key` scopes. - Added pagination and search to the list endpoint via `limit`, `offset`, and `search` query parameters. When any of these are present, the response switches to a paginated shape with `total_count`, `limit`, and `offset` fields alongside the existing `count`. The non-paginated path remains backward-compatible. - Expanded `PricingPatch` with many new pricing fields, organized into logical sections: - **Text**: `input/output_cost_per_token_flex`, `input/output_cost_per_token_fast` (Anthropic research preview, flat rate with no tiering) - **128k tier**: `input_cost_per_image/video/audio_above_128k_tokens` - **200k tier**: priority variants for input and output - **272k tier**: standard, priority, and flex variants for input and output - **Cache**: flex, priority, fast, and 272k-tier variants; `cache_creation_input_token_cost_above_1hr` and its 200k/fast variants - **Image**: `premium_image` combined tiers at 512px and 1024px, `input_cost_per_image_token` - **Other**: `inference_geo_us_multiplier` (Anthropic data-residency), `ocr_cost_per_page`, `annotation_cost_per_page` ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [x] Docs ## How to test Verify the updated OpenAPI spec is valid and that the new fields and parameters appear correctly: ```sh # Validate the OpenAPI spec npx @redocly/cli lint docs/openapi/openapi.yaml # Confirm new scope kinds are present grep -E "user|user_provider|user_provider_key" docs/openapi/openapi.yaml # Confirm pagination parameters are present on the list endpoint grep -E "limit|offset|search" docs/openapi/paths/management/governance.yaml ``` ## Breaking changes - [ ] Yes - [x] No The list endpoint response gains new optional fields (`total_count`, `limit`, `offset`) and the non-paginated path continues to behave as before. Existing `scope_kind` enum values are unchanged; new values are additive. ## Related issues ## Security considerations The new `user_id` scoping field allows pricing overrides to be applied per user. Ensure that `user_id` values are validated against authenticated session context server-side and are not accepted from untrusted input without authorization checks. ## 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
… custom pricing docs (maximhq#5853) ## Summary Expands the custom pricing documentation to cover new user-scoped overrides, additional pricing fields (fast-mode, OCR, premium images, extended cache creation/read tiers), and updated API behavior including paginated list responses and a corrected `PUT` verb for updates. ## Changes - Added three new scope kinds — `user`, `user_provider`, and `user_provider_key` — to the scope hierarchy, table, and field reference, positioned between the virtual-key family and the provider/global scopes - Clarified scope resolution order: virtual-key family is checked before user family, which is checked before provider/global scopes - Updated the `scope_kind` enum in the config field reference to include all `user*` variants and added the `user_id` conditional field - Corrected the update endpoint verb from `PATCH` to `PUT` and added a note that omitted fields are merged from the existing record - Added pagination support to the list endpoint (`limit`, `offset`, `search` query params) with documentation of the paginated response shape and all supported query filters - Added new pricing patch fields: `input_cost_per_token_fast`, `output_cost_per_token_fast`, and their cache counterparts (`cache_creation_input_token_cost_fast`, `cache_read_input_token_cost_fast`, `cache_creation_input_token_cost_above_1hr_fast`) - Added extended cache creation/read tier fields for flex and 272k+ context windows, 1hr+ TTL entries, and 200k+ context with 1hr+ TTL - Added premium image output cost fields and per-resolution premium image variants - Added `input_cost_per_image_above_128k_tokens` for image input above 128k context - Added `inference_geo_us_multiplier` for data-residency cost multipliers - Added a new OCR costs section covering `ocr_cost_per_page` and `annotation_cost_per_page` ## 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 rendered documentation to confirm: - The scope hierarchy diagram and table include all three `user*` scope kinds in the correct position - The update example uses `PUT` and includes the merge-patch note - The list example shows the paginated query and documents all supported filters - All new pricing fields appear in their respective sections with accurate descriptions ## Breaking changes - [ ] Yes - [x] No ## Security considerations None. This is a 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
…errides (maximhq#5854) ## Summary Adds support for two new image resolution-based pricing tiers — images above 2048×2048 pixels and images above 4096×4096 pixels — to the custom pricing override system. ## Changes - Added `output_cost_per_image_above_2048_and_2048_pixels` and `output_cost_per_image_above_4096_and_4096_pixels` fields to the `PricingOverridePatch` interface in `governance.ts` - Exposed these new fields in the pricing override sheet UI under the "image" group, positioned alongside the existing resolution-based pricing fields ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [x] UI (React) - [ ] Docs ## How to test Navigate to the custom pricing overrides sheet for an image-capable model and verify that the new "Output / image (>2048px)" and "Output / image (>4096px)" fields appear in the image pricing section and accept numeric cost values. ```sh cd ui pnpm i || npm i pnpm test || npm test pnpm build || npm run build ``` ## Screenshots/Recordings Verify the two new fields appear between the existing `>1024px` and `low quality` image pricing fields in the override sheet. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations No security implications. These are additive pricing configuration fields with no impact on auth, secrets, or PII. ## 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 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
…ntle) (maximhq#5867) ## Summary Fixes detection of GPT-5 series models so that reasoning effort support is correctly identified regardless of where "gpt-5" appears in the model name string (e.g., fine-tuned or versioned variants like `ft:gpt-5-...`). ## Changes - Replaced `strings.HasPrefix` with `strings.Contains` when checking if a model belongs to the GPT-5 series, allowing model names that include "gpt-5" in positions other than the start to be correctly recognized as reasoning models. ## Type of change - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/providers/openai/... ``` Verify that model names such as `ft:gpt-5-mini` or other variants containing "gpt-5" not at the start of the string are correctly identified as reasoning models and have `reasoning.effort` applied. ## Breaking changes - [ ] Yes - [x] No ## Related issues ## 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
…thods (maximhq#5462) The Vertex cached content methods (create/list/retrieve/update/delete) all authenticate via the shared vertexAuthHeaders helper, which unconditionally fetched an OAuth token from the key credentials and overwrote the Authorization header. This mirrors the pre-fix Embedding behaviour and prevents callers from supplying their own bearer token via context extra headers (e.g. a proxy that holds short-lived credentials out of band). Make vertexAuthHeaders take the API-key query-parameter path when the key carries a value — the same escape hatch the Gemini generation endpoints already use — leaving any Authorization header set from context extra headers intact. Signed-off-by: Charlie Gildawie <charlieg@monzo.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Akshay Deo <akshay@akshaydeo.com>
…aiting for a marker it never sends bedrock_mantle ends its stream after finish_reason without a [DONE] marker, same as the legacy mantle routing under the bedrock provider key, but the switch only matched schemas.Bedrock. The SSE loop waited indefinitely for a marker that never arrives. Affected packages: - core/providers/utils/utils.go - core/providers/utils/utils_test.go Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…o a stalled upstream body can't wedge the SSE producer loop ReleaseStreamingResponse drained the upstream body with an unbounded io.Copy. BuildStreamingClient sets ReadTimeout = 0, and the drain runs after stopIdleTimeout() has already fired, so nothing bounds it. An upstream that holds its chunked body open past the terminal SSE event (observed against bedrock_mantle) blocks the copy forever, parking the provider goroutine in this defer before the defer that closes the response channel runs, so the channel never closes, the SSE producer loop never exits, and the client never sees data: [DONE]. The drain now runs in its own goroutine, raced against GetStreamIdleTimeout(ctx). On timeout, the connection is force-closed with a non-nil error so fasthttp drops it instead of returning it to the idle pool, and resp is intentionally left unreleased (leaked to GC) since the drain goroutine may still be mid-Read on it -- the same trade-off already used elsewhere in this function when close ownership is uncertain. Affected packages: - core/providers/utils/utils.go - core/providers/utils/idle_timeout_reader_test.go Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…voice Rewrites two comment blocks added for the drain-timeout fix: breaks a run-on sentence chaining two colons into a shorter one plus an em-dash aside, matching the punctuation this file already uses for parenthetical consequence clauses (e.g. NewIdleTimeoutReader's doc comment). No functional change. Affected packages: - core/providers/utils/utils.go Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…rStreamIdleTimeout The drain-timeout fix introduced a new sentinel error passed to CloseWithError purely to force a non-nil value. NewIdleTimeoutReader's own timer already forces the same kind of close for the same reason (no data within GetStreamIdleTimeout(ctx)) using ErrStreamIdleTimeout, so the new error was an unnecessary near-duplicate. Reuse the existing sentinel instead. No functional change. Affected packages: - core/providers/utils/utils.go - core/providers/utils/idle_timeout_reader_test.go Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe PR adds Bedrock Mantle completion-marker handling and bounds streaming-response draining by the configured idle timeout. It adds tests for provider marker behavior, stalled stream closure, timeout enforcement, and normal response cleanup. ChangesStreaming utility behavior
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant ReleaseStreamingResponse
participant GetStreamIdleTimeout
participant ResponseBody
ReleaseStreamingResponse->>GetStreamIdleTimeout: Read configured idle timeout
ReleaseStreamingResponse->>ResponseBody: Start asynchronous drain
GetStreamIdleTimeout-->>ReleaseStreamingResponse: Return timeout
ReleaseStreamingResponse->>ResponseBody: CloseWithError(ErrStreamIdleTimeout) when drain stalls
ResponseBody-->>ReleaseStreamingResponse: Unblock read and report close
Possibly related issues
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" 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. Comment |
There was a problem hiding this comment.
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 `@core/providers/utils/idle_timeout_reader_test.go`:
- Around line 758-783: Strengthen the test around ReleaseStreamingResponse by
recording when body.CloseWithError is invoked and asserting that it occurs
within a CI-safe upper bound derived from the configured 30ms stream idle
timeout, rather than only checking it completes before 2 seconds. Preserve the
existing ErrStreamIdleTimeout assertion and use the blocking body’s signaling to
measure the forced-close timing deterministically.
- Around line 801-811: Update countingStreamCloser and the normal-path test
around ReleaseStreamingResponse to record the error argument passed to
CloseWithError, then assert that the recorded error is nil after cleanup. Keep
the existing close-count assertion and ensure the test distinguishes the normal
nil-error close from the idle-timeout forced-close branch.
🪄 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: 1494350d-a489-4370-8014-7b6d65c540cc
📒 Files selected for processing (3)
core/providers/utils/idle_timeout_reader_test.gocore/providers/utils/utils.gocore/providers/utils/utils_test.go
|
@akshaydeo @TejasGhatte do you have an estimate on when you will review these changes? I'm wondering if I need to fork this branch and patch my local deployments. |
Hey @zbloss approved it. @akshaydeo will merge soon |
The merge-base changed after approval.
|
@akshaydeo Do I need to fix these merge conflicts? |
244a01d to
ce1b2a6
Compare
|
Looks like this was addressed in 1.7.11? https://github.com/maximhq/bifrost/releases#release-core/v1.7.11 |
|
@TejasGhatte @akshaydeo I think we still need either this PR or another that changes bifrost/core/providers/utils/utils.go Lines 3183 to 3185 in 5bb5c65 Bedrock Mantle is not listed here even though it's in the code comments, which is causing our bedrock mantle streams to hang open waiting on a I think this should be |
|
This looks related: #6021 |
|
|
Summary
bedrock_mantle streaming chat completions never finish: every chunk is delivered, including the terminal chunk with finish_reason and usage, and then the response stalls -
data: [DONE]is never sent and the HTTP body is never terminated, leaking one goroutine and one upstream socket per request. Two defects combine to cause this, and this PR fixes both.Changes
ReleaseStreamingResponsedrained the upstream body with an unboundedio.Copy.BuildStreamingClientsetsReadTimeout = 0, and the drain runs after the SSE loop's own idle-timeout reader has already been stopped, so nothing bounds it - an upstream that holds its chunked body open past the terminal event (as bedrock_mantle does) blocks the copy forever, parking the provider goroutine in this defer before the defer that closes the response channel runs. The drain now runs in its own goroutine and races it againstGetStreamIdleTimeout(ctx);on timeout the connection is force-closed withErrStreamIdleTimeout(reusing the same sentinel NewIdleTimeoutReader's timer already uses for this failure mode, rather than adding a duplicate) so fasthttp drops it instead of returning it to the idle pool.schemas.BedrockMantle, so the SSE loop waited indefinitely for a [DONE] marker Mantle never sends. Added it alongside the existing schemas.Bedrock case.resp.CloseBodyStream()/fasthttp.ReleaseResponse(resp)are deliberately not called — the drain goroutine may still be mid-Read on the body stream, and a second concurrent close/release would double-Put fasthttp's pooled reader/requestStream, corrupting a later, unrelated request. resp is intentionally leaked to GC in that rare path, the same trade-off already used elsewhere in this function when close ownership is uncertain.Type of change
Affected areas
How to test
Expected: 1TestReleaseStreamingResponse_BoundsDrainAndDropsConnection1 completes in well under the 2s bound instead of hanging (reproduces the reported hang against a body stream that never terminates),
TestReleaseStreamingResponse_NormalDrainReleasesWithoutForcingCloseandTestProviderSendsDoneMarker(including the new bedrock_mantle case) pass, and the fullgo test ./... runshows no new failures (providers/bedrock and internal/mcptests have pre-existing, unrelated failures on dev).Manual repro against a mock upstream (from the linked issue): run a TLS server aliased to bedrock-mantle.us-east-1.api.aws that sends a few delta.content frames, a terminal frame with finish_reason, data: [DONE], and then never sends the closing 0\r\n\r\n chunk. Configure a bedrock_mantle key against it and stream a request through /v1/chat/completions. Before this change the client hangs indefinitely; after, data: [DONE] and the stream end arrive within the configured stream_idle_timeout_in_seconds.
No new configs or environment variables were added.
Breaking changes
If yes, describe impact and migration instructions.
Related issues
Closes #5871
Relates to #2910 (same missing-[DONE]-marker defect, reported for custom providers; that report's hang self-heals at the stream idle timeout, this one didn't because of the unbounded drain)
Security considerations
None. The change only affects timing/cleanup of an already-authenticated provider connection: it bounds how long a stalled upstream can hold a goroutine and socket open, and ensures a connection that failed to terminate cleanly is dropped rather than returned to the pool for reuse (avoiding stale-connection reuse, not introducing it). No auth, secrets, or PII handling is touched.
Checklist
docs/contributing/README.mdand followed the guidelines