Add DEFAULT_MANAGEMENT_OBJECT_IN_MEMORY_CACHE_TTL to both async_set_cache
calls in sync_user_role_and_teams for consistency with all other user cache
writes. Add 3 tests covering cache invalidation on role change, team change,
and no-op when nothing changes.
sync_user_role_and_teams updates the DB when a user's JWT role changes,
but the in-memory cache retained the stale role until TTL expiry. This
caused subsequent requests to see the old role for up to 60 seconds.
Fix: accept user_api_key_cache parameter and re-cache the updated user
object after both role and team membership DB writes.
- Migrate budget CRUD from manual state to React Query hooks (useBudgets, useCreateBudget, useUpdateBudget, useDeleteBudget)
- Fix crash when budget list contains null entries by filtering in query hook
- Fix max_budget type from string to number to match DB schema (double precision)
- Disable budget_id field in edit modal to prevent accidental changes
- Use budget_id as React key instead of array index
- Update tests to mock hooks instead of networking functions
/user/bulk_update was missing from the management_routes list in _types.py,
causing it to fall through to a 403 in non_proxy_admin_allowed_routes_check
even for proxy admin users. Also added it to the PROXY_ADMIN_VIEW_ONLY
blocked write operations list in route_checks.py to prevent view-only
admins from using it.
Add None-token test cases to both proxy_unit_tests and test_litellm
to cover the guard added in the previous commit. Also add -> bool
return type annotation to is_jwt().
When JWT auth is enabled and a request arrives without an Authorization
header (e.g. health checks, monitoring), api_key is None due to
APIKeyHeader(auto_error=False). The is_jwt() call crashes with
AttributeError: 'NoneType' object has no attribute 'split'.
Return False for None tokens since they are not JWTs.
During SSO login, bearer tokens are stripped from the OAuth response
before role mapping runs. Custom role claims encoded inside the JWT
access token are lost, so map_jwt_role_to_litellm_role() returns None
and the user falls back to internal_user_viewer.
process_sso_jwt_access_token() now returns the decoded JWT payload, and
a new _sync_user_role_from_jwt_role_map() receives it so
jwt_litellm_role_map works correctly during SSO login.
Pin all pip install commands to exact versions and SHA-pin all GitHub
Actions to prevent supply chain attacks. Remove snok/install-poetry
in favor of direct pip install. Delete orphaned load test scripts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>