Commit graph

1340 commits

Author SHA1 Message Date
ryan-crabbe-berri
5a5dd41052 fix(auth): keep main's team member budget enforcement, alert once per request
Restore the builder's team member budget check and 422 message exactly as on main and drop the MCP-only gate. The builder sends the member alert only on the request it rejects; common_checks sends it for requests that get past the builder, so no request alerts twice.
2026-09-24 14:35:10 -07:00
ryan-crabbe-berri
ea2b666a68 fix(mcp): keep team member budget enforcement on the MCP OAuth auth dependency
The MCP OAuth dependency stops at _user_api_key_auth_builder and never reaches common_checks, so removing the builder's inline member budget check would have let over-budget members through there. Enforce it explicitly for that caller.
2026-09-24 14:24:41 -07:00
ryan-crabbe-berri
98eb84d7d3 Revert "fix(team): reject malformed team_member_max_budget_alert_emails on team writes"
This reverts commit 703e754b46.
2026-09-24 14:00:43 -07:00
ryan-crabbe-berri
703e754b46 fix(team): reject malformed team_member_max_budget_alert_emails on team writes
Thresholds outside 1-100, non-list recipients, and invalid emails now return 422 on
/team/new, /team/update and PATCH /team/{id} instead of being stored and silently
ignored. The value is stored canonically. Read-side LiteLLM_TeamTable is unchanged,
and the PATCH body stays a raw merge patch so a null threshold still deletes it.
2026-09-23 17:25:11 -07:00
devin-ai-integration[bot]
5028f9ec59
fix(proxy): validate model credential name only when it changes (#42701)
PATCH /model/{id}/update rejected read-modify-write edits that resent an unchanged but dangling litellm_credential_name. Existence validation now runs only when the requested name differs from the stored one; empty string and non-admin detach rejections are unchanged

Co-authored-by: yuneng <yuneng@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-23 07:34:32 -07:00
Oliver Jensen
bc3b5b1d5b
fix(proxy): revoke UI session tokens on logout and password change (#42463)
* fix(proxy): revoke UI session tokens on logout and password change

Adds POST /session/logout to revoke the presented UI session key server
side (previously logout was client-side only and the key stayed valid
until expiry). Password changes now revoke the user's other UI sessions:
self-change keeps the caller's session, admin reset and onboarding claim
revoke all. The BYOK OAuth cookie auth now re-resolves the embedded key
against the DB so revoked sessions get a 401.

* fix(proxy): satisfy B008 budget and backend allowlist for /session/logout

* refactor(proxy): satisfy type-discipline budget in session_endpoints
2026-09-23 10:31:38 +02:00
moe-berri
2157351004
feat(ui): simplify auto-router setup and clarify feature limits (#42625)
* feat(ui): simplify auto-router setup and clarify feature limits

* fix(ui): validate auto-router drafts before saving

* fix: keep auto-router allowances consistent after deletes and refreshes
2026-09-22 18:03:32 -07:00
devin-ai-integration[bot]
da82ea8e94
fix(ui): let the Create Key user picker find users by user_id, not just email (#41687)
* feat(ui): search users by id or email when assigning a key owner

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): label users without an email by user id in key owner picker

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): freeze merged user-filter where, format create key test

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(proxy): suppress module-global patch findings in ui_view_users search test

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): keep merged user-filter where as a plain dict for prisma serialization

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): forward search param from userFilterUICall to /user/filter/ui

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): mention user ID in the Create Key user picker helper text

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: jesus <jesus@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-22 16:30:29 -07:00
devin-ai-integration[bot]
d7c27cdc08
feat(proxy): configurable key_alias_pattern for key generate, update, and regenerate (#42553)
* feat(proxy): configurable key_alias_pattern for key generate, update, and regenerate

Adds litellm_settings.key_alias_pattern, a regex every key_alias sent to
/key/generate, /key/service-account/generate, /key/update, and
/key/{key}/regenerate has to fully match. A non-matching alias gets a 400
that names the setting and the pattern. When set, it replaces the built-in
rule enable_key_alias_format_validation turns on, and the baseline
unsafe-name check still runs first. An invalid regex fails config load.

* fix(proxy): cap key_alias length under key_alias_pattern and type the test fixtures

* style(proxy): declare key_alias_pattern with a PEP 604 union

---------

Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
2026-09-22 14:52:01 -07:00
yuneng-jiang
666f6b01b4
fix: enforce disable_custom_api_keys from general_settings (#42437)
* fix: enforce disable_custom_api_keys from general_settings

The gate in _check_custom_key_allowed read the persisted UI settings row
through get_ui_settings_cached, which had two consequences.

A config-file general_settings.disable_custom_api_keys was never enforced,
because the gate only ever looked at the stored ui_settings row. POST
/key/generate with a custom key value returned 200 even with the flag set
to true in config.yaml.

The read went through a DualCache with a 600s TTL, which is per worker
without Redis, and only the worker that served PATCH /update/ui_settings
refreshed it. A gate flipped through the UI was then a coin flip across
workers for up to ten minutes.

Both go away by routing the flag the way the other runtime UI flags are
already routed. Adding it to _RUNTIME_GENERAL_SETTINGS_FLAGS and to the
settings rules' _UI_SETTINGS_FIELDS makes SettingsStore resolve it from the
ui_settings row with the config file winning, and every pod re-reads it on
its own settings sync rather than holding a private cached copy. The two
lists have to stay in step: a flag in one and not the other resolves
against the wrong stored row and silently never reaches a reader, so there
is a test for that invariant.

Writes to the ui_settings table did not publish on the config-sync channel,
so other pods only discovered a change on their next periodic reload. Adding
litellm_uisettings to _CONFIG_SYNCED_TABLE_NAMES puts it on the same pubsub
path model and SSO config writes already use, which cuts cross-pod
propagation from tens of seconds to a few.

The value reaching the gate is run through coerce_bool first. Resolution
hands back the raw YAML value, so a quoted "true" in config.yaml is a str
and the old `is True` check let custom keys straight through.

* test: assert both directions of the coerced config value

* test: assert the runtime flags read back instead of inspecting the registry
2026-09-22 13:28:31 -07:00
tin-berri
3b9c9e0523
feat(router): add group-scoped priority routing strategy (#42378)
* feat(router): add group-scoped priority routing strategy

* fix(router): satisfy priority routing type-discipline checks
2026-09-22 13:09:38 -07:00
devin-ai-integration[bot]
f3a0bb7249
fix(proxy): write key deleted audit logs for cascade and alias key deletions (#42446)
* fix(proxy): write key deleted audit logs for cascade and alias key deletions

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(proxy): assert persisted key deleted audit rows for cascade paths

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(e2e): route /audit and /v2/login to the control plane in split transport

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: yucheng <yucheng@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-22 11:52:08 -07:00
devin-ai-integration[bot]
b673ee61e7
feat(arize): per-team success and error sampling rates for the Arize AX callback (#42383)
* feat(arize): per-team success and error sampling rates for the Arize AX callback

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(arize): fail open on invalid sampling rates and type the new sampling code

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(arize): type the sampling test helpers and parametrized fixture

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-22 11:21:40 -05:00
joshua-berri
25af172b85
fix(mcp): keep config-defined servers read-only (#42299)
* fix(mcp): persist config server edits in the database

* test(mcp): cover config loading and failed promotion responses

* test(mcp): preserve auth policy during config server promotion

* fix(mcp): preserve existing YAML metadata during config loading

* fix(mcp): reuse bounded traversal for config secret checks

* fix(mcp): honor database access groups after config promotion

* fix(mcp): keep config-defined servers read-only

* fix(ui): clear frontend warnings and require warning-free green checks

* fix(ui): preserve legacy MCP access group labels

* ci: remove remaining frontend action runtime warnings

* fix(mcp): limit read-only fix to ticket scope

* fix(mcp): preserve API stability and remove unrelated guidance

---------

Co-authored-by: Joshua Valluru <326636767+joshua-berri@users.noreply.github.com>
2026-09-21 22:56:21 -07:00
devin-ai-integration[bot]
fa8483b6ae
fix(proxy): answer 503 no_db_connection on management routes when the caller's user read hits a database outage (#42410)
* fix(proxy): answer 503 no_db_connection on management routes when the caller's user read hits a database outage

Under allow_requests_on_db_unavailable, once the caller's key row lapses the
request runs as the restricted fallback identity, and its own user read fails
on the outage. /v2/team/list, /user/list, and /user/filter/ui answered a bare
500 for that; every route now answers the same 503 body auth gives, through
one shared builder consulted by the generic exception handler and by
ui_view_users' own catch-all

* fix(proxy): log the database outage before answering 503 on user search

* chore(proxy): drop the docstrings on the db outage 503 helper and its tests

---------

Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
2026-09-21 22:37:33 -07:00
devin-ai-integration[bot]
5d3d99eb9f
fix(proxy): drop cost-map metadata echoed back on model save (#41944)
* fix(proxy): drop cost-map metadata echoed back on model save

Filter unchanged cost-map fields from model-info save echoes while preserving edited overrides.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): drop a stored override when an echoed save resets it to the cost-map value

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): compare model_info echo against the deployment's cost-map lookup

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): decrypt the stored model before the cost-map lookup

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): treat a reset to the bundled catalog value as an echo even after router registration

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): compare the reset against the catalog as loaded, not only the bundled backup

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(types): type the catalog snapshot and echo filter parameters as Mapping[str, object]

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(proxy): inject the loaded catalog into update_db_model instead of patching the class

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): use contextlib.suppress for cost-map lookup miss to stay under BLE001 budget

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: ryan <ryan@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 19:33:16 -07:00
mateo-berri
1c6c1e568d Merge remote-tracking branch 'origin/main' into litellm_mcp_tools_camelcase_keys 2026-09-21 17:21:46 -07:00
Yassin Kortam
9cc5b78c33
Merge pull request #41634 from BerriAI/litellm_agent_access_groups
feat(agents): attach access groups to agents and enforce them for models, MCP servers and agent calls
2026-09-21 19:13:46 -05:00
yuneng-jiang
1f4b595072
Merge pull request #41788 from BerriAI/litellm_config_read_source
feat(proxy): report the source of alerting, UI and router settings on read
2026-09-21 17:02:18 -07:00
yuneng-jiang
6b254b6be2
Merge pull request #41769 from BerriAI/litellm_model-actor-edges
test(model_management): cover actor edges and wildcard models
2026-09-21 16:43:24 -07:00
tin-berri
c1c1ec4f84
Merge pull request #42026 from BerriAI/litellm_user_jwt_savings
feat(ui): add internal-user savings and auto-router usage
2026-09-21 16:41:16 -07:00
mateo-berri
b58c9349dd test(mcp): drop the docstring from the wire spelling regression test 2026-09-21 16:15:43 -07:00
joshua-berri
1baa26d36b
Merge pull request #41074 from BerriAI/litellm_mcp_server_list_stable_order
fix(mcp): keep server lists stable across refreshes
2026-09-21 23:06:09 +00:00
Yuneng Jiang
143725fc06
Merge remote-tracking branch 'origin/main' into litellm_config_read_source 2026-09-21 15:54:52 -07:00
mateo-berri
51aa021c6e fix(mcp): return camelCase tool keys from /v1/mcp/tools after the SDK 2 upgrade
SDK 2 spells the Tool model's Python attributes in snake_case behind camelCase aliases, so dumping attribute names handed scripts input_schema and output_schema instead of the inputSchema and outputSchema v1.102.0 returned. Dump each tool by its MCP wire aliases, as the other list routes do, and pin the shape with a regression test. Also drop an unused tools dict in the Responses MCP stream iterator.
2026-09-21 15:38:06 -07:00
ryan
8a1c6e49fb feat(auth): only allow password-login dashboard sessions to call /user/password/change
Password login now stamps login_method=username_password into the UI session key
metadata, and change_password rejects any caller that is not a litellm-dashboard
key carrying that marker with 403 before the user row is read. SSO sessions and
user-associated virtual keys can no longer use the endpoint as a current_password
guessing oracle. The forced-reset session is still minted by the password login
path, so it keeps access to the endpoint

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 22:22:12 +00:00
ryan
28f70c75d1 fix(auth): reject unchanged password on /user/password/change
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 22:02:05 +00:00
Yuneng Jiang
1cc38f05f4
test(proxy): type the router settings source test parameters 2026-09-21 15:00:24 -07:00
ryan
7c8aed072f chore: merge main into litellm_cherry_pick_password_breach_reset
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 21:54:35 +00:00
Mateo Wang
4b54897b36
Merge pull request #42315 from BerriAI/litellm_scim_delete_evict_user_cache
fix(proxy): evict the cached user row when SCIM or /user/delete removes a user
2026-09-21 14:51:53 -07:00
Joshua Valluru
5ec61e7a0b chore: merge main into MCP ordering fix 2026-09-21 14:36:41 -07:00
yucheng-berri
79d6e236f9
Merge pull request #39805 from BerriAI/litellm_mcp_admin_api_preserve_oauth_scopes
fix(mcp): keep oauth scopes in admin api credential redaction
2026-09-21 14:29:13 -07:00
Yuneng Jiang
4602376977
fix(proxy): report a stored alerting value as db even when it is null
A stored null or empty list for a nested alerting field is still the value
the proxy serves when the config file leaves alerting_args alone, so the
source is db. Keying off the value rather than its presence reported those
fields as default and hid a stored setting that is genuinely in effect.

Presence in the stored row now decides, with the config file still checked
first so a config-owned key keeps reporting config. Test helpers are typed
and the router test injects a stub rather than patching a class attribute.
2026-09-21 14:24:32 -07:00
yuneng-jiang
5e0512b611
Merge pull request #42291 from BerriAI/litellm_lit7597_detach_credential
fix(proxy): detach stored credential when model editor selects None
2026-09-21 14:05:28 -07:00
mateo-berri
d8ce49de06 fix(proxy): evict the cached user row when SCIM or /user/delete removes a user 2026-09-21 13:51:26 -07:00
Yuneng Jiang
ddf6565970
Merge remote-tracking branch 'origin/main' into litellm_config_read_source 2026-09-21 13:25:45 -07:00
Yuneng Jiang
be2f0d081b
fix(proxy): report sources only on the read endpoints main does not cover
/config/field/info and /config/list already report per-key source on main,
so this drops the branch's versions of those and keeps /alerting/settings,
/get/ui_settings and /router/settings.

Read endpoints no longer write the freshly read database row back into the
shared settings store; the reload path already keeps it current, and a GET
that mutates global state leaks across callers.

Regenerates the lazy OpenAPI snapshot on Python 3.12, matching CI, and the
dashboard API types for the two new response fields.
2026-09-21 13:25:39 -07:00
ryan
baee50546f chore: merge main into litellm_cherry_pick_password_breach_reset
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 19:54:40 +00:00
yuneng
d69eb7f095 fix(proxy): fall back to the credentials table when validating litellm_credential_name
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 19:47:27 +00:00
tin-berri
457b01e96d
Merge pull request #42055 from BerriAI/litellm_prompt_caching_request_table
feat(ui): show prompt caching requests and net savings
2026-09-21 12:45:11 -07:00
Joshua Valluru
68074da1d1 test(mcp): cover stable server ordering and sort priorities 2026-09-21 12:39:47 -07:00
Yuneng Jiang
86c4021e83
Merge branch 'main' into litellm_config_read_source
The shared settings-store work this branch was stacked on landed on main,
along with source reporting for /config/field/info and /config/list.
Resolved by taking main for the store, the config routes and their tests,
and re-applying only the read surfaces main does not cover:
/alerting/settings, /get/ui_settings and /router/settings.
2026-09-21 12:36:15 -07:00
Joshua Valluru
f5d511b3f9 Merge remote-tracking branch 'origin/main' into litellm_mcp_server_list_stable_order 2026-09-21 12:33:27 -07:00
yuneng
177021b2ac fix(proxy): gate explicit credential detach only on PATCH /model/{id}/update
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 19:22:57 +00:00
yuneng
10d343c3ee fix(proxy): detach stored credential when model editor selects None (LIT-7597)
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 19:22:57 +00:00
moe-berri
a83773cfa5
Merge pull request #41886 from BerriAI/litellm_jev_autorouter_launch_1789767495
feat(auto-router): add JEV classifier alongside LLM classifier
2026-09-21 11:55:44 -07:00
ryan
3fe405a5cc feat(auth): breached password detection, self-service change-password and forced password reset
Cherry-pick of merge commit b3882d8e43 (PRs #39321, #39562, #40107), which landed on litellm_internal_staging instead of main.

Co-authored-by: ojensen-berri <ojensen@berri.ai>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 18:48:35 +00:00
ryan-crabbe-berri
5573265013
Merge pull request #41906 from BerriAI/litellm_team_member_budget_source_reset
feat(team): show whether a member follows the team default budget and allow resetting to it
2026-09-21 10:34:08 -07:00
Moe Khalil
bb46e8b774 chore(auto-router): merge main and preserve JEV configuration
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-21 17:16:18 +00:00
yucheng-berri
51ae7ab1fd
Merge pull request #41588 from BerriAI/litellm_ui_session_personal_key_budget_ceiling
* fix(key_generate): use user's budget for UI session personal keys

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Update litellm/proxy/management_endpoints/key_management_endpoints.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix(user_update): evict cached user on max_budget change so the personal key ceiling refreshes on every worker

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: jesus-berri <jesus@berri.ai>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: yucheng <yucheng@berri.ai>
2026-09-21 10:11:29 -07:00