Skip to content

chore(deploy): build image off 1.89.1 backport (#30502) - #30547

Open
tin-berri wants to merge 37 commits into
litellm_internal_stagingfrom
litellm_deploy_1_89_1_30502
Open

chore(deploy): build image off 1.89.1 backport (#30502)#30547
tin-berri wants to merge 37 commits into
litellm_internal_stagingfrom
litellm_deploy_1_89_1_30502

Conversation

@tin-berri

Copy link
Copy Markdown
Contributor

Relevant issues

This PR exists to run the build/deploy workflow off the exact file state of the 1.89.1 backport merge (#30502, commit 3983231) so the resulting image can be deployed to a vcluster for testing. It is not intended as new feature work; the head branch points directly at that commit

Pre-Submission checklist

  • not applicable; this is a deploy/CI build branch carrying an already-reviewed backport set

Type

🚄 Infrastructure

Changes

The head branch is the 1.89.1 backport (#30502); base is litellm_internal_staging, so the diff reflects the 1.89.x patch set (MCP, model-info, passthrough, DB fixes plus the 1.89.0 -> 1.89.1 version bump). No changes were authored here beyond pointing a branch at that commit

shin-berri and others added 30 commits May 13, 2026 22:37
[Infra] Promote internal staging to main
[Infra] Promote internal staging to main
chore(ci): promote internal staging to main
chore(ci): promote internal staging to main
chore(ci): promote internal staging to main
chore(ci): promote internal staging to main
chore(ci): promote internal staging to main
chore(ci): promote internal staging to main
chore(ci): promote internal staging to main
…#30064) (#30143)

* Add Claude Fable 5 across Anthropic, Bedrock, Vertex AI, and Azure AI

Adds cost map entries for claude-fable-5 ($10/$50 per MTok, 1M context,
128K output, adaptive thinking only) on the Anthropic API, Bedrock
converse (base, global, and us/eu geo inference profiles at the 10%
regional premium), Vertex AI, and Azure AI (Microsoft Foundry, which
serves Fable 5 with the full 1M context window unlike Opus 4.8).

Registers anthropic.claude-fable-5 in BEDROCK_CONVERSE_MODELS, lists the
model in the setup wizard, and extends the reasoning effort e2e grid.
The Bedrock, Vertex, and Azure grid cells carry fail_reason markers
until the CI accounts are provisioned: Bedrock needs the provider data
sharing opt-in Fable 5 requires, and the Foundry resource needs a
claude-fable-5 deployment.

The first-party entry carries provider_specific_entry {us: 1.1} for the
inference_geo premium and deliberately no fast multiplier since Fable 5
has no fast mode.

https://claude.ai/code/session_01MZarYYT3aS7DxaNjoax6Gm

* Drop removed sampling params for Claude 4.7+ when drop_params is set

Fable 5, Opus 4.7, and Opus 4.8 removed sampling params: the API rejects
top_p, top_k, and any temperature other than 1 with a 400. LiteLLM was
forwarding them even with drop_params enabled because the Anthropic and
Bedrock converse transformations passed temperature/top_p through
unconditionally.

Mirror the GPT-5/o-series handling: temperature=1 still passes through,
other values and any top_p are dropped when drop_params is set, and
without drop_params a clean client-side UnsupportedParamsError tells the
caller how to opt in, instead of surfacing the raw provider error.

https://claude.ai/code/session_01MZarYYT3aS7DxaNjoax6Gm

* Drive sampling param gating from the cost map and cover top_k

Greptile review follow-ups on the sampling param fix: the restriction for
Fable 5 / Opus 4.7 / 4.8 is now declared as supports_sampling_params: false
on every affected cost map entry (perplexity excluded; that route is
OpenAI-compatible and maps sampling params upstream) and read back through
a tri-state map lookup, keeping the name check only as a fallback for
provider-routed ids whose hosted map entries predate the flag, the same
layering supports_adaptive_thinking uses. top_k bypasses map_openai_params
as a provider-specific kwarg, so it is gated at the shared
AnthropicConfig.transform_request boundary (direct, Bedrock invoke, Vertex,
Azure) and in the Bedrock converse _handle_top_k_value path, with
drop_params threaded through the converse transform helpers.

Also updates the reasoning effort grid cell count assertion for the four
Fable 5 rows added on this branch (29 x 11 cells).

https://claude.ai/code/session_01MZarYYT3aS7DxaNjoax6Gm

* Declare supports_sampling_params in the cost map schema

The model map validation schema uses additionalProperties: false, so the
new flag must be declared for the 28 entries that carry it; this was the
one failing job (misc / Run tests) on the previous commit.

https://claude.ai/code/session_01MZarYYT3aS7DxaNjoax6Gm

* fix(bedrock): gate top_k=0 on converse to match Anthropic boundary

Truthiness check let top_k=0 silently disappear on models that removed
sampling params, while AnthropicConfig.transform_request treats 0 as
present and raises UnsupportedParamsError (or drops when drop_params is
set). Switch to 'is not None' so converse, direct Anthropic, invoke,
Vertex, and Azure all behave the same for top_k=0.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* feat(proxy): publish /v2/model/info in Swagger OpenAPI spec

Expose the v2 model info endpoint in /docs by removing include_in_schema=False
and documenting query parameters used by the admin UI and proxy CLI consumers.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore(ui): regenerate schema.d.ts for /v2/model/info OpenAPI docs

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit f5b11b7)
…the Tools page (#29867)

* fix(ui): let non-creator users OAuth into OBO-mode MCP servers from the Tools page

* fix(ui): clear OBO Tools-tab one-shot on navigate-back and gate on credential-status errors

(cherry picked from commit 1528f43)
…#29665) (#29788)

* feat(responses): add default no-op sign_request to BaseResponsesAPIConfig

* feat(responses): call sign_request after body is final, send signed bytes when signed

* feat(bedrock_mantle): add SigV4 sign_request via composed BaseAWSLLM (bearer path)

* test(bedrock_mantle): cover SigV4 access-key, AssumeRole, body bytes, region/auth consistency

* feat(bedrock_mantle): defer auth to sign_request; validate_environment no longer requires bearer

* docs(bedrock_mantle): document SigV4 + Bearer auth on Responses route

* test(responses): cover fake-stream signing order and mantle bearer arg/env precedence

* fix(bedrock_mantle): wrap all botocore credential errors with both-paths guidance

* fix(bedrock_mantle): catch specific credential errors, not all BotoCoreError, so STS transport failures are not masked

* fix(bedrock_mantle): sign the compact Responses route too, not just create

(cherry picked from commit 2c95d0b)
…gs (#29991)

Capture user_id and extra_info from metadata or litellm_metadata. The single-bag read dropped identity whenever a request carried a present litellm_metadata field (null or a user-supplied dict), since /chat/completions routes the authenticated identity into metadata while the guardrail read litellm_metadata first

(cherry picked from commit 1bbaf1c)
…29493)

* feat(proxy): add disable_budget_reservation general setting (#27639)

* feat(proxy): register disable_budget_reservation in ConfigGeneralSettings (#27639)

* docs(proxy): document disable_budget_reservation concurrency tradeoff (#27639)

* ci: re-trigger flaky docker build (prisma generate ECONNRESET)

* fix(proxy): warn and document budget enforcement tradeoff when disable_budget_reservation is set (#27639)

(cherry picked from commit 1032dd7)
…ware GET path (#29960)

* fix(ui): load MCP tool configuration tools via the OBO/passthrough-aware GET path

* fix(mcp): admin-only include_disabled_tools so the settings UI shows toggled-off tools

* fix(ui): repopulate MCP server edit form when server data loads after mount (OAuth return)

* fix(ui): persist MCP OAuth token on save and return to the Settings tab after authorize

* fix(ui): scope MCP OAuth callback to the initiating form so create and edit flows don't cross-talk

* fix(ui): derive OAuth-return Settings tab via lazy state init instead of setState-in-effect

* Fix MCP OAuth edit token handling

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
(cherry picked from commit 51ba6e3)
…r server's token no longer leaks into the next add-server session (#30000)

* fix(ui/mcp): reset OAuth hook state on modal close so a prior server's token no longer leaks into the next add-server session

* fix(ui/mcp): clear in-flight OAuth guard on reset and reset form/tools on modal close so nothing leaks on a parent-driven dismiss

(cherry picked from commit d8fe091)
…ess check (#30041)

* fix(mcp): honor team access-group grants in OAuth authorize/token access check

* test(mcp): mock build_effective_auth_contexts in non-admin authorize tests for isolation

(cherry picked from commit 5b7063d)
…T-3593) (#30009)

* fix(proxy): authorize batch files using upload target_model_names (LIT-3593)

After replace_model_in_jsonl, body.model is a stripped provider id. Reverse-mapping it via resolve_model_name_from_model_id is first-match on model_list and caused false 403s when multiple deployments share the same stripped name. Use target_model_names from the unified file id instead.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proxy): restore resolve_model_name_from_model_id for JSONL fallback path (LIT-3593)

Restores the reverse-lookup for the JSONL body.model fallback path so that
legacy/pre-target_model_names managed files still map stripped provider IDs
back to proxy aliases before auth. Also cleans up redundant `or None`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Revert "fix(proxy): restore resolve_model_name_from_model_id for JSONL fallback path (LIT-3593)"

This reverts commit 30d2e96.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit 2cd7e87)
* fix(proxy): align /v1/model/info with router deployments

Return router model_list entries (including team-scoped models) with team
access metadata instead of wildcard-expanded names from get_complete_model_list.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proxy): gate v1 team filter and honor key allowlists

Only apply get_all_team_and_direct_access_models for admin or user-bound
keys, then intersect with key/team model restrictions to avoid empty lists
for service tokens and metadata leaks for restricted keys.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proxy): skip v1 team filter when user row is missing

Require a DB-backed user before applying team-access filtering on
/v1/model/info, and skip the trailing filter in get_all_team_and_direct_access_models
when user context cannot be resolved.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Revert "fix(proxy): skip v1 team filter when user row is missing"

This reverts commit 74e1fbd.

* fix(proxy): restore legacy v1 model access filtering

Keep /v1/model/info on key/team allowlists instead of DB team-membership
filtering, while still listing router deployments for team-scoped models.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proxy): drop A2A agent entries from public /v1/model/info list

* fix(proxy): scope team BYOK rows on /v1/model/info to caller's teams

Listing the full router model_list let any authenticated key without
explicit model restrictions enumerate other teams' BYOK deployments
(public name, team_id, api_base) via /v1/model/info. Reuse the existing
_get_caller_byok_team_scope check so non-admin callers only see global
deployments plus their own team's BYOK rows; admins keep the full view.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
(cherry picked from commit 6068bb7)
Enable teams to configure their own Datadog credentials via
POST /team/{team_id}/callback, following the same pattern as Langfuse.

(cherry picked from commit f5e6012)
… responses (#26153) (#27346)

* fix: coerce server_tool_use dict to ServerToolUse in Usage.__init__ (#26153)

* fix: coerce server_tool_use to ServerToolUse in stream_chunk_builder (#26153)

* fix: dict/pydantic-tolerant access in tool_call_cost_tracking (#26153)

* fix: dict/pydantic-tolerant access in anthropic cost_calculation (#26153)

* test: assert ServerToolUse type in existing stream_chunk_builder anthropic web search test

* test: regression test for #26153 (stream_chunk_builder server_tool_use type)

* test: dict/pydantic safety for tool_call_cost_tracking helper

* test: dict/pydantic safety for anthropic web_search cost

* refactor: consolidate _get_web_search_requests into shared cost-calc utils

* test(realtime): use gpt-realtime; openai retired gpt-4o-realtime-preview

OpenAI shut down the gpt-4o-realtime-preview family (incl. the undated
alias) on 2026-05-07, causing the live realtime test to fail with a
4000 invalid_request_error.invalid_model close. gpt-realtime is the GA
successor; switch the live-call tests to it, matching the base branch.

* refactor(types): drop redundant server_tool_use coercion in Usage.__init__

---------

Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
(cherry picked from commit 4a3860d)
…r genuine auth failures (#29986)

(cherry picked from commit da9d64b)
fix(proxy): atomic merge for team model aliases and team.models on BYOK create

(cherry picked from commit ac7c2dc)
* fix(proxy): populate access_via_team_ids on /v1/model/info

Team metadata enrichment previously only ran on /v2/model/info with
include_team_models=true, leaving /v1/model/info without
access_via_team_ids for project model-picker flows.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(dashboard): sync OpenAPI schema for /v1/model/info query params

Add include_team_models and teamId to the generated schema for /model/info
and /v1/model/info after the proxy endpoint gained team-access filtering.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proxy): always return direct_access on /v1/model/info

Set direct_access to true or false on every enriched model so clients
can filter without treating a missing field as ambiguous.

Co-authored-by: Cursor <cursoragent@cursor.com>

* perf(proxy): fail fast when teamId is set without a connected DB on /v1/model/info

Raise the db_not_connected error before building, enriching, and translating the model list instead of after, so a teamId query against a proxy with no database no longer wastes the full enrichment pipeline.

* fix(proxy): fail fast when include_team_models is set without a database

include_team_models=True relies on _populate_team_access_on_models to set
direct_access/access_via_team_ids, which only runs when a database is connected.
Without one, _filter_models_to_user_accessible discarded every model and the
endpoint returned an empty list with HTTP 200. Mirror the teamId guard so the
request fails fast with a clear db_not_connected error before any model-list work.

* fix(proxy): populate direct_access on single-model /model/info lookup

The /v1/model/info list path populates model_info.direct_access (and
access_via_team_ids) when a database is connected, but the
litellm_model_id single-model lookup returned early without it. This
made the two endpoints disagree, breaking the parity assertion in
test_get_specific_model. Run the same population on the single-model
path so both responses match.

* fix(proxy): apply no-DB fast-fail before litellm_model_id branch

The teamId/include_team_models no-DB guard sat after the litellm_model_id
early return, so ?litellm_model_id=X&teamId=Y with no DB returned 200 with
unpopulated access fields instead of the 500 raised on every other path.
Move the guard ahead of the branch so the fast-fail is uniform.

* fix(proxy): apply teamId/include_team_models filters on single-model lookup

The litellm_model_id early-return branch in model_info_v1 populated the
team access fields but returned before the teamId and include_team_models
filters ran, so a single-model lookup surfaced the deployment regardless
of team access when the DB was connected. Run both filters on the
single-model list before returning so the documented query params behave
the same with and without litellm_model_id.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
(cherry picked from commit 7d1f68e)
Sameerlite and others added 7 commits June 15, 2026 18:37
…thropic streaming logging

Targeted subset of staging commit cfcdf87 (#30202): only the
anthropic_passthrough_logging_handler.py hardening hunks and their four
tests are taken; the rest of that staging batch is intentionally excluded.

(cherry picked from commit cfcdf87)
(cherry picked from commit 973c7eb)
…combined view (#30327)

The grace-period branch assigned the recursive get_data result (a
finished LiteLLM_VerificationTokenView) back into the variable that the
combined-view dict normalization then subscripts, raising TypeError on
every request made with a rotated key inside its grace window; auth
surfaced that as a 401. Return the recursive result directly instead.

Regression test drives the full get_data flow: old hash misses the view,
deprecated table resolves to the active token, and the call must return
the view object

(cherry picked from commit 5047eaf)
The OAuth2 passthrough ran user_api_key_auth on the client's upstream bearer
first and only recovered after the failed validation had already logged a 401
auth event to the tracer, so successful tool calls to a delegated server each
carried a phantom 401 span. Check delegate_auth_to_upstream before validating:
a delegated server skips the doomed call entirely so nothing is logged, and a
non-delegated server validates normally and surfaces a real 401 rather than
being exchanged for an anonymous upstream-passthrough session.

(cherry picked from commit 039a2d8)
(cherry picked from commit d96ab46)

Backport adaptation: applied only the pyproject.toml and
ui/litellm-dashboard/package.json manifest hunks; uv.lock and
package-lock.json are regenerated on this line in a separate commit
rather than cherry-picked, and the package.json devDependencies are
unioned with this line's @types/uuid and vite entries
Regenerate uv.lock (pypdf 6.13.2, tornado/aiohttp constraints from #30220)
and ui/litellm-dashboard/package-lock.json (vitest 3.2.6). Pin
brace-expansion to 5.0.6 via an explicit package.json override so the
line's lockfile resolves the patched transitive version that #30220
ships on staging
Prerequisite for #27346 (completion_cost AttributeError on streaming
Anthropic web_search). #27346's per-chunk coercion is undone by the
existing Usage(**returned_usage.model_dump()) reconstruction in
calculate_usage, which round-trips server_tool_use back to a plain dict;
without this Usage.__init__ coercion the cost path still does attribute
access on a dict and raises. The same prerequisite was bundled into the
stable/1.88.x backport of #27346 (24b9655).

Content-verified present on litellm_internal_staging via aggregator
32c88ca (Litellm oss staging 080626, #29932); this restores only the
two-line coercion, not the rest of that aggregator.

(cherry picked from commit 32c88ca)
…9x_multi

chore(release): backport 1.84.8 patch set + MCP/model-info/DB fixes to stable/1.89.x and cut 1.89.1
@tin-berri
tin-berri requested a review from a team June 16, 2026 18:06
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
8 out of 11 committers have signed the CLA.

✅ yuneng-berri
✅ mateo-berri
✅ Sameerlite
✅ aanchal22
✅ kingdoooo
✅ Ar-maan05
✅ ryan-crabbe-berri
✅ tin-berri
❌ shin-berri
❌ yassin-berriai
❌ ishaan-berri
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This is the 1.89.1 backport deployed against litellm_internal_staging for vcluster testing. The patch set bundles several independent fixes across MCP auth, model-info endpoints, DB resilience, Anthropic sampling-param gating, and team BYOK concurrency.

  • MCP auth (user_api_key_auth_mcp.py): explicit litellm key is now validated before the delegate_auth_to_upstream bypass (security improvement), _target_servers_use_oauth2 is removed, and the anonymous cold-start fallback is narrowed to auth_type=none passthrough servers only.
  • DB resilience (exception_handler.py, auth_exception_handler.py, utils.py): DB outages during auth now surface as 503 instead of 401; the PostgreSQL cached-plan error recovery no longer injects a unique SQL comment but instead calls attempt_db_reconnect; a silent bug where deprecated-key grace-period lookups fetched a result but never returned it is fixed.
  • model_info_v1 (proxy_server.py): now reads from llm_router.model_list directly (aligning with v2), adds include_team_models/teamId query params, and applies team BYOK scoping to prevent cross-team metadata leakage.
  • Anthropic sampling params (common_utils.py, transformation.py): Claude 4.7+ models that removed temperature/top_p/top_k now get a clean 400 or silent drop rather than a passthrough that the API rejects.
  • Team BYOK concurrency (team_endpoints.py): team_model_add now uses an atomic SQL ARRAY append with DISTINCT unnest to eliminate the race condition when concurrent BYOK model creates overwrite each other's team.models.

Confidence Score: 4/5

The backport is largely additive and defensive, but two changes warrant a closer look before promoting to production: the removal of the model-ID-to-proxy-name mapping in the batch rate limiter auth loop may reject legitimate non-managed batch job submissions, and the _supports_sampling_params fallback embeds hardcoded Claude model-name patterns that bypass the JSON-driven capability system.

The deprecated-key grace-period fix, DB 503 promotion, and cached-plan reconnect are clear improvements. The MCP auth reorder correctly tightens the security boundary. The batch rate limiter change removes a mapping that the code comment explicitly noted was needed for post-replacement JSONL files; whether that path is still exercised for legacy (non-managed) files needs confirmation.

litellm/proxy/hooks/batch_rate_limiter.py (resolve_model_name_from_model_id removal), litellm/llms/anthropic/common_utils.py (_supports_sampling_params fallback names)

Important Files Changed

Filename Overview
litellm/proxy/hooks/batch_rate_limiter.py Introduces target_model_names from unified file ID for managed files, and removes the resolve_model_name_from_model_id mapping that previously normalized provider IDs to proxy names for all batch files in the auth loop.
litellm/llms/anthropic/common_utils.py Adds _supports_sampling_params to gate top_p/top_k/temperature on Claude 4.7+ models. Primary lookup is model-map driven, but retains a hardcoded name-pattern fallback list that violates the no-hardcode-model-flags rule.
litellm/proxy/management_endpoints/team_endpoints.py team_model_add replaces Python-side merge with an atomic SQL ARRAY append using DISTINCT unnest to fix race conditions in concurrent BYOK model creates; updates updated_at only for the follow-up find.
litellm/proxy/_experimental/mcp_server/auth/user_api_key_auth_mcp.py MCP auth refactor: reorders condition tree so explicit litellm key is checked before delegate_auth_to_upstream bypass, removes _target_servers_use_oauth2 fallback, narrows anonymous cold-start fallback to auth_type=none passthrough servers only.
litellm/proxy/proxy_server.py model_info_v1 now reads directly from llm_router.model_list (like v2), adds include_team_models/teamId params, applies team BYOK scoping; v2/model/info promoted out of include_in_schema=False; helper functions extracted for testability.
litellm/proxy/utils.py Cached-plan error recovery now calls attempt_db_reconnect (singleflight) instead of injecting a unique comment; also fixes a silent bug where deprecated_response was fetched but never returned during grace-period key lookups.
litellm/proxy/db/exception_handler.py Adds is_prisma_engine_internal_error and is_database_service_unavailable_error to distinguish DB outage from auth failure, enabling 503 responses during connectivity issues instead of 401.
litellm/proxy/auth/auth_exception_handler.py Adds a 503 fast-path when the authentication database is unreachable, preventing DB outages from masquerading as 401 auth failures.
litellm/proxy/auth/user_api_key_auth.py Adds disable_budget_reservation flag to general_settings; passes general_settings into _reserve_budget_after_common_checks for the new skip path.
litellm/proxy/_experimental/mcp_server/rest_endpoints.py Adds include_disabled_tools query param (admin-only) that bypasses allowed_tools filtering for MCP configuration UI; gated on PROXY_ADMIN role so non-admins always see filtered tools.
litellm/proxy/_experimental/mcp_server/db.py MCP server delete now cleans up both litellm_mcpusercredentials and litellm_mcpuserenvvars independently so a failure on one table still attempts the other.
litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py exchange_token_with_server: expires_in is now omitted instead of defaulted to 3600 when absent, matching RFC 6749 §4.2.2 which makes expires_in optional.
litellm/llms/anthropic/chat/transformation.py Routes temperature, top_p, and top_k through _apply_sampling_param to enforce model capability checks; no logic changes for supported models.

Comments Outside Diff (1)

  1. litellm/proxy/hooks/batch_rate_limiter.py, line 657-663 (link)

    P1 resolve_model_name_from_model_id mapping removed from auth loop

    The deleted code translated provider-level model IDs back to proxy model names before running access checks. The comment it carried ("body.model may be the provider id after replace_model_in_jsonl") described a real case: when a non-managed JSONL file is pre-processed by replace_model_in_jsonl, the body.model fields become provider IDs (e.g. openai/gpt-4.1), not the proxy aliases the caller has access to. After this change, model_to_check equals the raw JSONL value for the non-managed path, so the access check compares a provider ID against a proxy-model allowlist and spuriously rejects legitimate callers.

    For managed files this is fine — target_model_names already carries the proxy alias and bypasses the JSONL parse. The regression risk is on the legacy non-managed path if replace_model_in_jsonl has already transformed the content before this hook runs.

Reviews (1): Last reviewed commit: "Merge pull request #30502 from BerriAI/l..." | Re-trigger Greptile

Comment on lines +288 to +302
model_lower = model.lower()
return not any(
v in model_lower
for v in (
"fable",
"opus-4-7",
"opus_4_7",
"opus-4.7",
"opus_4.7",
"opus-4-8",
"opus_4_8",
"opus-4.8",
"opus_4.8",
)
)

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.

P2 Hardcoded model-name fallback violates no-hardcode-flags rule

The fallback name list ("fable", "opus-4-7", "opus-4-8" variants) is evaluated when _get_model_capability returns None — i.e. when the model map has no supports_sampling_params entry. The policy here is to express model capabilities solely through model_prices_and_context_window.json so users benefit from updates without code changes. The "fable" substring in particular is very broad and could silently match unintended provider-routed IDs.

Since the verified model IDs (claude-opus-4-7, claude-fable-5, etc.) already carry "supports_sampling_params": false in the JSON, the fallback names add risk rather than safety. The preferred pattern is to gate solely on _get_model_capability and, if that returns None, treat the model as supported (fail-open for unknown models) rather than maintaining a parallel name list in code.

Rule Used: What: Do not hardcode model-specific flags in the ... (source)

Comment on lines +4699 to 4715
" END || $1::text[]"
" ))"
") "
"WHERE team_id = $2",
models_to_add,
data.team_id,
)
# Re-fetch via update (write-routed) instead of find_unique (read-routed)
# to avoid returning stale data from a read replica. The models column was
# already set by execute_raw above; this bumps updated_at. `include` mirrors
# the relations the auth path consumes off the cached team object so that
# `_refresh_cached_team` doesn't null them out — see
# object_permission_utils.validate_key_search_tools_against_team and the
# MCP/agent authz paths, which treat a missing object_permission as
# "no team-level restriction".
updated_team = await prisma_client.db.litellm_teamtable.update(
where={"team_id": data.team_id},

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.

P2 Silent success when team_id does not match any row

execute_raw returns None regardless of whether the WHERE team_id = $2 clause matched any rows. If data.team_id refers to an already-deleted or nonexistent team, the SQL succeeds silently, the subsequent update also finds no row and returns None, and the caller receives no error. The old add_new_models_to_team + update(data={"models": ...}) path would raise a Prisma RecordNotFound from the update. Consider checking updated_team is None after the update and raising a 404 if the team row was not found.

)
region = self._resolve_region({**litellm_params, "api_base": api_base})
base = (
api_base

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.

High: SigV4 signing to caller-controlled hosts

api_base can come from the request path through the proxy, and the new SigV4 fallback signs whatever URL is returned here when no bearer token is configured. An authenticated caller can set api_base to an attacker-controlled host for a Bedrock Mantle /v1/responses request and receive the proxy's AWS-signed headers and prompt body; restrict IAM signing to the standard Mantle host or an operator-configured allowlist, and reject request-supplied custom hosts before calling _sign_request.

@veria-ai

veria-ai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

PR overview

This PR backports the deployment image build to the 1.89.1 line and includes changes affecting the Bedrock Mantle /v1/responses request transformation path. The touched code handles how Bedrock Mantle response requests are prepared and signed when routed through the proxy.

There is one open security issue: an authenticated caller can influence the Bedrock Mantle api_base and cause the proxy to SigV4-sign requests to a caller-controlled host. That could expose AWS-signed headers and prompt contents to the caller’s infrastructure unless signing is limited to trusted Mantle hosts or an operator allowlist. No issues have been addressed yet, so the PR still carries a clear attacker-driven data exposure risk.

Open issues (1)

Fixed/addressed: 0 · PR risk: 7/10

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.