Commit graph

19624 commits

Author SHA1 Message Date
yassin
15ff8d18e7 test(proxy): cover the CLI single-model branch of /model/info JSON serialization
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 10:07:10 +00:00
yassin
b86de179dc fix(utils): stop wrapper_async submitting the sync success handler twice
_client_async_logging_helper re-submitted logging_obj.success_handler to the
executor after _dispatch_success_logging had already done so, running the same
success pipeline twice per async request and racing on shared logging state.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 10:02:51 +00:00
Devin AI
cd8887d72c fix(mistral): accept reasoning_effort on all models and drop client_metadata for Codex compatibility
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 09:55:07 +00:00
yassin
93e6770d68 perf(proxy): serialize /model/info listing once with orjson
FastAPI walked the multi-megabyte /model/info payload through jsonable_encoder
before json.dumps on every request. Return a prebuilt orjson Response instead,
keeping jsonable_encoder as the fallback for datetimes and other non-native values

Resolves LIT-5724

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 09:37:00 +00:00
Devin AI
a70f9a17cc perf(logging): skip correlation contextvar stamping when request_correlation_in_logs is off
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 08:54:34 +00:00
Oliver Jensen
f9da8a19b6
test(models): stop the password serialization test matching field-name substrings 2026-09-14 09:59:45 +02:00
Oliver Jensen
40118bd158
test(auth): annotate the session-minting patch for the test-quality gate 2026-09-14 09:59:45 +02:00
Oliver Jensen
e77d11d8d7
refactor(auth): type the breach-screen DB dicts and flatten the session-key kwargs
Annotate screen_login_password_for_breach's update/where dicts with
prisma input TypedDicts and replace authenticate_user's conditional
dict splat with plain keyword arguments, clearing the LIT002 lines
this branch added in login_utils.py. No behavior change: an unflagged
login now passes allowed_routes=None and metadata={} explicitly, which
are the parameter defaults
2026-09-14 09:59:45 +02:00
Oliver Jensen
4f2836bc60
feat(auth): screen the login password inline and restrict the session on a fresh breach hit
A breach found during a login previously only flagged the account for the
NEXT login, handing out one free unrestricted 24h session. The HIBP screen
is now awaited before the session key is minted (worst case one 5s window
per user per 24h, fail-open unchanged), so a fresh hit restricts the
current session and the dashboard routes straight to change-password.

Also repairs two casualties of merge f5e47974db that the layout tests
caught: the lost usePathname import and a call to migratedHref, which
staging renamed to uiHref.
2026-09-14 09:59:45 +02:00
Oliver Jensen
671d032b20
feat(auth): force password reset for breached or admin-set passwords 2026-09-14 09:59:45 +02:00
Oliver Jensen
faf755345a
fix(auth): clear the CI gates on the change-password PR
The Terraform endpoint audit wanted POST /user/password/change covered
or allowlisted; it is a caller-scoped one-shot action, so allowlist it
next to /user/bulk_update. leftnav.test.tsx mocked next/navigation
without useRouter, which SidebarAccountMenu now calls, so every render
in that file threw. The two unannotated audit-log patches in
test_password_endpoints.py get their test-quality-ok reasons.

Also removes the LIT002 violations the PR added: prisma input TypedDicts
annotate the where/data dicts, a shared HTTPExceptionErrorDetail
TypedDict covers the HTTPException detail dicts, and the route decorator
takes a tags tuple.
2026-09-14 09:59:44 +02:00
Oliver Jensen
d79a893e37
feat(auth): add self-service change-password endpoint
Admin password sets on /user/update and per-user /user/bulk_update stay
supported and policy-enforced. The request model hides the password from
repr so management alerts never format the plaintext, and the all_users
bulk path rejects passwords instead of writing one plaintext value to
every row.
2026-09-14 09:59:44 +02:00
Oliver Jensen
0bb0218d0b
fix(auth): screen bulk-update passwords concurrently before any db write
/user/bulk_update awaited a separate HIBP lookup for each user in the
batch, so a degraded-slow HIBP (5s timeout per lookup) could stretch a
500-user batch to ~2500s and time out the request after some updates
had already persisted.

validate_passwords_bulk dedupes the batch's passwords, strength-checks
first, then fires every needed HIBP lookup concurrently, bounding the
worst case at one 5s timeout window. bulk_update_processed_users now
screens the whole batch before the serial update loop, so a rejected
password fails only its own entry and validation failures precede any
persistence.
2026-09-14 09:59:43 +02:00
Oliver Jensen
bf8df3ab02
hibp support in password policy 2026-09-14 09:59:43 +02:00
Devin AI
19c43eb875 test(cli): drop structural StrEnum source check; smoke job covers the 3.10 import
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 07:08:24 +00:00
Devin AI
03e6dd051c fix(cli): drop enum.StrEnum so the CLI imports on Python 3.10
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 06:59:10 +00:00
ryan
c25498b66d fix(proxy): remove a bulk-deleted user's email-only roster entries without touching same-email teammates
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 06:08:42 +00:00
ryan
dbb4de7bc2 fix(proxy): match bulk-deleted users on team rosters by user_id only and give /team/bulk_member_delete the 60s batch timeout
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 05:59:19 +00:00
ryan
d442d90411 test(proxy): add /team/bulk_member_delete behavior-suite scenarios for route coverage
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 05:56:52 +00:00
ryan
82872c9627 fix(proxy): run /user/bulk_delete team rewrites and user deletes in one transaction
Lock affected teams in sorted order inside a single 60s transaction so a
failure on any team rolls back every rewrite and every user row delete.
PrismaClient.tx() gains an optional timeout for the larger batch.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 05:35:55 +00:00
ryan
595aba3cb0 fix(proxy): evict deleted keys from the auth cache and make bulk user deletion transactional
/user/bulk_delete now deletes the users' keys, invitation links, org and team
memberships and user rows in one transaction and reports a rolled-back batch
per row instead of leaving partial deletes behind. Both bulk endpoints evict
the deleted keys (and deleted user objects) from the auth cache, so a deleted
key stops authenticating immediately rather than at TTL expiry.

/team/bulk_member_delete rejects member rows that carry both user_id and
user_email, reports repeated rows as duplicates, and only cleans up keys and
memberships of members it actually matched.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 05:12:34 +00:00
ryan
cd9c39921b feat(proxy): add POST /user/bulk_delete and POST /team/bulk_member_delete
Batch user deletion that also removes each user from every team they belong to, and batch removal of many members from one team. Each touched team is rewritten once under the team advisory lock from a roster re-read under that lock

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 04:55:39 +00:00
ryan
0c9e0c407e fix(proxy): keep a team on a /user/bulk_new row when the roster already lists that user id
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 03:37:20 +00:00
ryan
4285f1dfb0 fix(proxy): do not claim rows a concurrent request inserted when /user/bulk_new create_many fails
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 02:39:47 +00:00
ryan
24a1d772b6 fix(proxy): keep key policy fields and reconcile committed rows in /user/bulk_new
Rows opting into auto_create_key lost blocked, permissions, aliases, config,
agent_id, budget_fallbacks and budget_limits before reaching the key helper.
When create_many commits but the response is lost, re-read which ids landed
and retry only the rest so committed rows report success and get their teams.
Regenerate schema.d.ts and allowlist the endpoint in the Terraform audit.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 01:48:44 +00:00
ryan
ff5b59b173 feat(proxy): add POST /user/bulk_new for batched user and team membership creation
Creates up to 500 internal users in one request with set-based validation,
a single create_many for user rows, and one locked write per referenced team.
Rows fail independently, keys are opt-in per row via auto_create_key, and
send_invite_email is rejected for the batch.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-14 01:17:19 +00:00
yassin
a41b719920 fix(proxy): refund batch TPD reservation on failure and report active window reset time
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 10:56:17 +00:00
yassin
c47120cbf7 fix(proxy): add tpd_limit to deleted token table and fix CI fixtures
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 10:31:35 +00:00
mateo-berri
fff7a2cecf fix(responses): keep context-window events out of mid-stream fallback and fix stale exception assertions 2026-09-13 03:18:59 -07:00
yassin
438d46cb50 feat(proxy): add tpd_limit (tokens per day) for batch submissions
Adds a nullable tpd_limit column and field to keys, teams, budgets and end users. The batch submission limiter swaps the per-minute RPM/TPM descriptor of any scope that has a tpd_limit for a token-only 24h descriptor, so batch traffic is budgeted per day while online traffic keeps the existing per-minute limits. The Admin UI exposes the field on key, team and budget create/edit forms

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 10:06:07 +00:00
mateo-berri
2923c4ac55 fix(guardrails): read the rewrite from texts when a guardrail echoes every row back unchanged 2026-09-13 03:02:15 -07:00
mateo-berri
7ea19eccc7 fix(responses): keep namespace custom tools through guardrail merges and Mantle params identity 2026-09-13 03:02:03 -07:00
mateo
db79226b6b test(auth): freeze the cache clock in auth prefetch tests
The org cache entries written by prefetch_auth_objects carry the 5s
DEFAULT_IN_MEMORY_TTL. The first @log_db_metrics getter lazily imports
litellm.proxy.proxy_server, which on a cold CI runner can take longer
than 5s, so the org entry expired before get_org_object read it and the
getter fell through to the MagicMock database. Inject a frozen clock
into InMemoryCache so the test asserts the join, not import latency.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 09:59:39 +00:00
mateo-berri
65160a97c5 fix(guardrails): keep tool calls carried by a later choice of a packed multi-choice chunk
The rebuild's tool-call selection and its text-only fast path only looked at
choice 0 of each chunk, so a chunk that packs several choices (Gemini with
candidateCount above 1) lost a tool call carried by a later candidate, and a
chunk whose later choice had no tool calls at all made the rebuild raise.
Both now consider every choice in the chunk.
2026-09-13 02:55:03 -07:00
yassin
e41b3bd13f test(router): annotate return types of team cooldown test helpers
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 09:50:12 +00:00
yassin
e61b6bfd5f fix(router): classify pass-through cooldown against pass-through deployments only
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 09:48:35 +00:00
mateo-berri
dd173a0b1b fix(guardrails): count the PANW latest-user scan over the hoisted system prompt 2026-09-13 02:43:35 -07:00
yassin
9080f0904a fix(router): ignore blocked siblings when checking team model cooldown alternatives
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 09:35:54 +00:00
mateo-berri
c246372859 fix(responses): import BaseLLMException lazily and collect stream chunks via anext
Move the BaseLLMException import into _map_error_event_exception so the
module no longer imports it at load time, clearing the module-level cyclic
import CodeQL flagged. The class is used only on the cold error path.

Replace the mutable list-append test collector with aiter/anext so the
regression tests read the stream immutably.
2026-09-13 02:35:53 -07:00
yassin
10f411e60d fix(router): name the all-deployments-in-cooldown error on 429 responses
RouterRateLimitError now carries the model group's deployment ids so it
can tell when every deployment is cooled down, and exposes that as
type=all_deployments_in_cooldown with an explicit message. A partial
cooldown keeps type=rate_limit_error. Either way the proxy no longer
reports type=internal_server_error next to code 429

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 09:34:16 +00:00
mateo-berri
37447c98f7 fix(guardrails): reject per-message texts that cannot land on a string input or a Messages request 2026-09-13 02:28:43 -07:00
yassin
d0a846c8be test(router): cover team_model_has_alternatives directly in the mapped router test
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 09:27:33 +00:00
mateo-berri
825e4f17e9 fix(sdk): carry body and proxy headers on relayed litellm errors and content policy blocks too 2026-09-13 02:23:34 -07:00
yucheng
685c654298 refactor(proxy): assert separate login counter stores in the spray regression test instead of a comment
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 09:18:39 +00:00
mateo-berri
e732a484f6 fix(responses): hoist Codex additional_tools input items into the chat bridge tools 2026-09-13 02:11:59 -07:00
mateo-berri
073d4fe2b0 fix(responses): route mid-stream error events through exception_type so content_policy_fallbacks fire
Mid-stream error events on the streaming Responses API were all raised as
APIError, so a content_policy_violation event never matched the router's
content-policy fallback dispatch and the client got the raw error instead
of the fallback model's answer. Map each error event's code and status
through the existing exception_type mapping, matching the non-streaming
path, and unwrap the typed ContentPolicyViolationError and
ContextWindowExceededError so the router routes them to the configured
content_policy_fallbacks and context_window_fallbacks.
2026-09-13 02:11:06 -07:00
yassin
76b26e41ab fix(router): cool down team deployments on 429 when a sibling serves the same public model
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 09:07:53 +00:00
mateo-berri
c0c0c9a9eb fix(sdk): keep body and proxy headers on BadRequestError mapped from a litellm_proxy 400
The generic 400 branch of the OpenAI exception mapper dropped the wire body and no
branch carried the response headers, so an application calling a LiteLLM proxy through
a litellm_proxy/ model could not tell a guardrail block from any other failure without
walking __cause__. BadRequestError now takes headers, filled for a litellm_proxy
upstream, and the generic branch passes the body. The proxy edge treats the literal
"None" type and param an older proxy sends as absent and stops forwarding an upstream
proxy's date and server headers.
2026-09-13 02:05:10 -07:00
yucheng
05fe17e027 test(proxy): drop the section banner comment from the login tests
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 09:02:45 +00:00
yucheng
ce82033f62 refactor(proxy): inject settings and Redis cache into LoginThrottle.from_request
Removes the runtime import of proxy_server from login_throttle so the
throttle module no longer participates in the import cycle CodeQL
flagged (py/cyclic-import). Callers pass general_settings and
redis_usage_cache explicitly; behavior is unchanged.

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