[Infra] Merge personal dev branch with daily dev branch#23826
[Infra] Merge personal dev branch with daily dev branch#23826yuneng-jiang merged 20 commits intolitellm_internal_dev_03_16_2026from
Conversation
Tests added for: UiLoadingSpinner, HashicorpVaultEmptyPlaceholder, PageVisibilitySettings, errorUtils, and mcpToolCrudClassification. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
[Test] UI Dashboard - Add unit tests for 5 untested files
…x_budget updates to admins Non-admin users (INTERNAL_USER) could call /key/block and /key/unblock on arbitrary keys, and modify max_budget on their own keys via /key/update. These endpoints are now restricted to proxy admins, team admins, or org admins. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
…calation_fix [Fix] Privilege Escalation on /key/block, /key/unblock, and /key/update max_budget
Remove `.length > 0` check so that when a backend filter returns an empty result set the table correctly shows no data instead of falling back to the previous unfiltered logs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[Fix] UI - Logs: Empty Filter Results Show Stale Data
…ate and key/update Internal users could exploit key/generate and key/update to create unbound keys (no user_id, no budget) or attach keys to non-existent teams. This adds validation for non-admin callers: auto-assign user_id on generate, reject invalid team_ids, and prevent removing user_id on update. Closes LIT-1884 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the non-admin team validation into the existing get_team_object call site to avoid an extra DB round-trip. The existing call already fetches the team for limits checking — we now add the LIT-1884 guard there when team_obj is None for non-admin callers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lid_keys [Fix] Prevent Internal Users from Creating Invalid Keys
…changed When updating or regenerating a key without changing its key_alias, the existing alias was being re-validated against current format rules. This caused keys with legacy aliases (created before stricter validation) to become uneditable. Now validation only runs when the alias actually changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…n_on_update [Fix] Key Alias Re-validation on Update Blocks Legacy Aliases
The test expected fallback to all logs when backend filters return empty, but the source was intentionally changed to show empty results instead of stale data. Updated test to match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add disable_custom_api_keys UI setting that prevents users from specifying custom key values during key generation and regeneration. When enabled, all keys must be auto-generated, eliminating the risk of key hash collisions in multi-tenant environments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Without this field on the model, GET /get/ui_settings omits the setting from the response and field_schema, preventing the UI from reading it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a toggle switch to the admin UI Settings page so administrators can enable/disable custom API key values without making direct API calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
[Feature] Disable Custom Virtual Key Values via UI Setting
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
dcbaa05
into
litellm_internal_dev_03_16_2026
Greptile SummaryThis PR merges a personal dev branch into the daily dev branch, delivering security hardening for key management endpoints (LIT-1884), a new admin UI toggle to disable custom virtual key values, a bug fix for log-filter fallback behaviour, and a batch of new unit tests across Python and TypeScript. Key changes:
Confidence Score: 2/5
|
| Filename | Overview |
|---|---|
| litellm/proxy/management_endpoints/key_management_endpoints.py | Core key management endpoint — adds custom-key-allow check, auto user_id assignment for non-admins (breaking), team validation (breaking), block/unblock admin enforcement, and key-alias skip-validation on unchanged alias. Contains backwards-incompatible changes and a direct DB query bypassing the helper function pattern. |
| litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py | Adds disable_custom_api_keys field to UISettings model and ALLOWED_UI_SETTINGS_FIELDS; exposes get_ui_settings_cached helper (10-min cache). Clean and consistent with existing patterns. |
| tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py | Adds comprehensive mock-only tests for the new LIT-1884 behaviours: custom-key-disable enforcement, admin/non-admin key generation checks, block/unblock access control, and key-alias unchanged-skip logic. Tests are well-structured and appropriately mocked. Tests are properly located in the mock-only test folder. |
| ui/litellm-dashboard/src/components/Settings/AdminSettings/UISettings/UISettings.tsx | Adds a new "Disable custom Virtual key values" toggle backed by disable_custom_api_keys. Clean addition that follows the existing pattern for other UI settings toggles. |
| ui/litellm-dashboard/src/components/organisms/create_key_button.tsx | Reads disable_custom_api_keys from UI settings and conditionally hides the custom key field in the create-key form. Small, correct change. |
| ui/litellm-dashboard/src/components/view_logs/log_filter_logic.tsx | Removes the .length > 0 guard so an empty backend-filtered result is returned directly rather than falling back to unfiltered client-side logs. Behaviour change is intentional and matched by the updated test. |
Sequence Diagram
sequenceDiagram
participant Client
participant generate_key_fn
participant _check_custom_key_allowed
participant get_ui_settings_cached
participant key_generation_check
participant _common_key_generation_helper
Client->>generate_key_fn: POST /key/generate (data, user_api_key_dict)
generate_key_fn->>generate_key_fn: [NEW] auto-assign user_id if non-admin & user_id is None
generate_key_fn->>generate_key_fn: [NEW] reject non-existent team_id for non-admins
generate_key_fn->>key_generation_check: validate team permissions
generate_key_fn->>_common_key_generation_helper: proceed with key creation
_common_key_generation_helper->>_check_custom_key_allowed: check data.key (custom value)
_check_custom_key_allowed->>get_ui_settings_cached: read disable_custom_api_keys (10-min cache)
get_ui_settings_cached-->>_check_custom_key_allowed: settings dict
alt disable_custom_api_keys == true AND custom key provided
_check_custom_key_allowed-->>Client: 403 Forbidden
else
_check_custom_key_allowed-->>_common_key_generation_helper: OK
_common_key_generation_helper-->>Client: Generated key response
end
participant block_key_fn as block_key / unblock_key
participant _check_key_admin_access
participant prisma_direct as prisma_client.db (direct)
participant get_team_object
Client->>block_key_fn: POST /key/block (data, user_api_key_dict)
block_key_fn->>_check_key_admin_access: [NEW] enforce admin access
alt user is PROXY_ADMIN
_check_key_admin_access-->>block_key_fn: OK
else
_check_key_admin_access->>prisma_direct: find_unique(token) — bypasses cache
prisma_direct-->>_check_key_admin_access: key row (team_id)
_check_key_admin_access->>get_team_object: fetch team (with cache)
get_team_object-->>_check_key_admin_access: team obj
alt caller is team admin or org admin
_check_key_admin_access-->>block_key_fn: OK
else
_check_key_admin_access-->>Client: 403 Forbidden
end
end
block_key_fn-->>Client: blocked key response
Comments Outside Diff (2)
-
litellm/proxy/management_endpoints/key_management_endpoints.py, line 63-70 (link)Backwards-incompatible rejection of keys with non-existent
team_idwithout feature flagPreviously, when
team_tablewasNone(team not found in DB),key_generation_checkreturnedTrueunconditionally — allowing any caller to assign an arbitraryteam_id. Now non-admins receive a 400 error.Any existing non-admin workflow that creates keys with a
team_idwhere the team doesn't yet exist in the DB (or was deleted) will now break without warning. This behaviour change should be controlled by an opt-in flag rather than applied globally, consistent with the backwards-compatibility policy in this codebase.The same concern applies to the non-admin team validation added in
_validate_update_key_data(line ~1928) and ingenerate_key_fn(~line 1279).Rule Used: What: avoid backwards-incompatible changes without... (source)
-
ui/litellm-dashboard/src/components/view_logs/log_filter_logic.test.tsx, line 1576-1587 (link)Test expectation changed to match new behaviour — verify intent is correct
The old test asserted that when backend filters are active but the API returns an empty array, the hook falls back to client-side logs (1 result). The updated test now expects 0 results, matching the updated
log_filter_logic.tsxchange that removes thelength > 0guard.The code change makes sense: showing unfiltered client-side data when an active backend filter returns no matches is misleading. Just confirm this is the intended UX change (i.e. empty backend response = "no results", not a trigger to show all local logs).
Last reviewed commit: a087c44
| if not _is_proxy_admin and data.user_id is None: | ||
| data.user_id = user_api_key_dict.user_id | ||
| verbose_proxy_logger.warning( | ||
| "key/generate: auto-assigning user_id=%s for non-admin caller", | ||
| user_api_key_dict.user_id, | ||
| ) |
There was a problem hiding this comment.
Backwards-incompatible auto-assignment of
user_id without feature flag
Non-admin internal users who previously called /key/generate without a user_id (e.g. to create shared/service keys) will now have the caller's user_id silently auto-assigned to the key. This is a breaking behavior change — existing automation scripts or integrations relying on creating unbound keys will produce different results without any opt-in.
Per the repo's backwards-compatibility policy, this should be gated behind a feature flag (e.g. litellm.enforce_key_user_id_binding = True) so existing deployments are not broken.
# Safer approach — opt-in flag
if not _is_proxy_admin and data.user_id is None and litellm.enforce_key_user_id_binding:
data.user_id = user_api_key_dict.user_id
verbose_proxy_logger.warning(...)Rule Used: What: avoid backwards-incompatible changes without... (source)
| target_key_row = await prisma_client.db.litellm_verificationtoken.find_unique( | ||
| where={"token": hashed_token} | ||
| ) |
There was a problem hiding this comment.
Direct DB query bypasses established helper-function pattern
_check_key_admin_access issues a raw prisma_client.db.litellm_verificationtoken.find_unique call instead of going through the existing get_key_object helper. This bypasses DualCache (so the key record is fetched from DB on every block/unblock/update call even if it was recently read) and is inconsistent with the pattern used elsewhere in this file, where all key look-ups go through get_key_object / get_team_object. Any caching logic, telemetry spans, or future changes to key lookup behaviour won't automatically apply here.
Consider using the get_key_object helper instead, which handles cache read/write and is consistent with the rest of the codebase.
Rule Used: What: In critical path of request, there should be... (source)
Relevant issues
CI/CD: only failing known flaky tests: https://app.circleci.com/pipelines/github/BerriAI/litellm?branch=litellm_yj_march_16_2026
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
tests/test_litellm/directory, Adding at least 1 test is a hard requirement - see detailsmake test-unit@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewDelays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
CI (LiteLLM team)
Branch creation CI run
Link:
CI run for the last commit
Link:
Merge / cherry-pick CI run
Links:
Type
🚄 Infrastructure
Changes