Commit graph

48845 commits

Author SHA1 Message Date
Abhyuday
e9836165d7 test(proxy): close patch-coverage gaps on the reset-race fix
Adds direct unit tests for async_reset_preserving_delta (the Lua
GET/compute/SET itself, previously only exercised indirectly through
mocked callers) and for the delete-also-fails and second-cancellation
edge cases in the reset job and cancel-path retry, all only reachable
through error injection.
2026-09-14 15:54:59 -04:00
Abhyuday
9f546fdb89 fix(proxy): stay within the ruff strict-rule BLE001 budget
The reset-race fix's new except Exception blocks pushed BLE001 4 over
ruff-strict-budget.json's limit. Each catches a Redis or reconcile
failure of unknown type by design, matching the noqa pattern this file
already uses on the equivalent non-cancel release path, so suppress
rather than narrow.
2026-09-14 10:16:26 -04:00
Abhyuday
b25920d9c9 style: ruff format 2026-09-14 08:57:01 -04:00
Abhyuday
1fdb6e95a5 fix(proxy): break reset_budget_job cyclic-import risk, tighten comments per repo convention
Addresses CodeQL and greptile findings on the reset-race fix.

CodeQL flagged reset_budget_job.py's module-level imports of RedisCache,
the two RESET_BUDGET_SPEND_COUNTER_RESET_* constants, and
evict_and_broadcast as cyclic-import risks: each target module can reach
back to this one before finishing its own initialization. RedisCache is
only used as a type hint, so it moves under TYPE_CHECKING with the
annotations quoted; the constants and evict_and_broadcast are only used
inside single functions, so they move to local imports there, per this
repo's own stated exception for avoiding circular imports.

Also fixes a CodeQL "empty except with no explanatory comment" on the
cancel-path's CancelledError handler, and trims the docstrings this fix
added or touched down to this repo's comment conventions (concise,
non-obvious-why only).
2026-09-14 08:57:01 -04:00
Abhyuday
bdd409430e fix(proxy): make budget-reset and cancel-path invalidation race-safe against concurrent reservations
Addresses two concurrency findings from automated security review on
the reset/invalidation fallbacks added for #30460.

reset_budget_job.py: a reset that failed and retried replayed an
unconditional SET to new_spend on every attempt. A request's Redis
INCR landing in the delay between a failed attempt and its retry (a
legitimate reservation against the just-reset budget) would be
silently erased by the next attempt's write, since retrying and the
final delete both treat the counter as static rather than possibly
having moved. Replaced the retry's SET with
async_reset_preserving_delta, a single Lua GET/compute/SET that resets
to new_spend plus whatever was added on top of a snapshot taken once
before the first attempt and held fixed across retries, so a
concurrent increment survives no matter which attempt eventually
succeeds. If the snapshot read itself fails, there's no safe baseline
to preserve against, so that case now skips straight to the existing
delete fallback rather than attempting a reset that could guess wrong.

budget_reservation.py: release_budget_reservation_on_cancel's fallback
on a reconcile failure invalidates the shared key/user/team counters
outright. Unlike reconcile, which only ever adjusts this reservation's
own recorded contribution, that invalidation deletes state a
concurrent reservation or recorded spend also shares on the same
counter. A transient failure (e.g. a Redis timeout) during
cancellation would take the destructive path immediately. Now retries
the reconcile itself, which is safe and idempotent, a bounded number
of times first, and only falls back to invalidating the aggregate
counters once every retry hits the same failure.

Both fixes are covered by regression tests that simulate the race
directly (a concurrent increment landing during the reset retry delay,
and a reconcile that fails once then recovers on the cancel path) and
assert the concurrent write survives / the aggregate counter is not
touched.
2026-09-14 08:57:01 -04:00
Abhyuday
fba32eea20 fix(proxy): invalidate stale key/user/team caches and retry Redis spend counter resets on budget reset
Fixes three of the phantom Redis spend-counter inflation mechanisms
reported in #30460 for a multi-pod deployment with intermittent Redis
timeouts.

Path 2: reset_budget_for_litellm_keys/_users/_teams (the per-row
budget_duration reset path) invalidated the Redis spend counter but
never dropped the corresponding user_api_key_cache entry, unlike the
budget-table cascade path. A stale cached object could get read back by
_get_source_cache_base_spend and re-seed the counter with the pre-reset
spend. Also route that invalidation through the existing cross-pod
broadcast (evict_and_broadcast/LIT-3803) instead of a local-only
delete, since only one pod runs the reset job per tick and every other
pod's cache needs to drop its copy too.

Path 3: a failed Redis SET-to-zero during a budget reset only logged a
warning and left the inflated pre-reset counter in place until its TTL.
Now retries the SET a bounded number of times with a short backoff, and
falls back to deleting the key (which reads as cold and reseeds from
the DB) if every attempt fails, logging at ERROR instead of WARNING.

Path 1 (narrow): release_budget_reservation_on_cancel silently
swallowed a reconcile failure with no invalidation fallback, unlike its
sibling release_or_invalidate_budget_reservation. Added the same
invalidate-and-mark-finalized fallback so a Redis timeout during the
cancel-path reconcile cannot leave a pre-charge stuck in the counter.
The broader pre-charge/reconcile path already retries via a
delete-and-reseed pattern (increment_spend_counters_pipeline /
_reconcile_budget_reservation_for_counter_update), so no further change
was made there.

Relates to #30460
2026-09-14 08:57:01 -04:00
Oliver Jensen
b3882d8e43
Merge pull request #40107 from BerriAI/litellm_forced_password_reset
feat(auth): breached password detection and forced change

BREAKING CHANGE: users can no longer change their password by issuing a request with a password parameter to /user/update; this has been replaced with /user/password/change dedicated to secure password change.
2026-09-14 10:17:21 +02: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
38c04638ef
fix(lint): clear the one-over LIT002 and inline-object budget hits 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
5bb2c9e76f
fix(auth): annotate the strict-rule suppressions the merged gates now count
The staging merge brought BLE001 into the strict ruff set and lowered the
LIT002 ceiling, so the HIBP fail-open except and the params/headers dicts
in password_policy.py now need their noqa and mutable-ok reasons. The
headers dict moves to an annotated Final so the suppression fits the line
limit.
2026-09-14 09:59:43 +02:00
Oliver Jensen
1d18d11fcf
Apply suggestion from @greptile-apps[bot]
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-09-14 09:59:43 +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
a9a0bcb9f8
move hibp url to constants 2026-09-14 09:59:43 +02:00
Oliver Jensen
fcf7cb6e0c
fix(ui): regenerate schema.d.ts for the new_user password docstring 2026-09-14 09:59:43 +02:00
Oliver Jensen
1f0ab3d176
fix(auth): drop general_settings import left unused in new_user 2026-09-14 09:59:43 +02:00
Oliver Jensen
e2ea7e97a5
fix(auth): document /user/new password rejection and format password_policy 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-integration[bot]
daa665e578
build(deps): re-suppress GHSA-h7x2-h6g9-p789 in osv-scan, mlflow still has no fixed release (#41036)
Co-authored-by: mateo <mateo@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 21:46:25 -07:00
Mateo Wang
c2c2a623c0
Merge pull request #39846 from BerriAI/litellm_bedrock_mantle_govcloud_cost_row
Some checks are pending
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests / proxy-endpoints (push) Waiting to run
Unit Tests / proxy-extras (push) Waiting to run
Unit Tests / caching-local (push) Waiting to run
Unit Tests / core-utils (push) Waiting to run
Unit Tests / enterprise-package (push) Waiting to run
Unit Tests / enterprise-routing (push) Waiting to run
Unit Tests / integrations (push) Waiting to run
Unit Tests / All Other Providers (push) Waiting to run
Unit Tests / Vertex AI (push) Waiting to run
Unit Tests / proxy-infra (push) Waiting to run
Unit Tests / proxy-server (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
LiteLLM Rust / rust-test (push) Waiting to run
Unit Tests: Documentation Validation / documentation (push) Waiting to run
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests / misc (push) Waiting to run
Unit Tests / proxy-auth (push) Waiting to run
Unit Tests / responses-caching-types (push) Waiting to run
fix(bedrock_mantle): price GovCloud regions from the regional cost row and accept region-prefixed model names
2026-09-12 21:13:58 -07:00
devin-ai-integration[bot]
62b3a93219
build(deps): bump smol-toml to 1.8.0 to clear GHSA-7w5x-hrqm-74c2 in osv-scan (#40478)
Co-authored-by: mateo <mateo@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-12 21:13:54 -07:00
Mateo Wang
b1a61f510c
Merge pull request #35918 from Lee-Si-Yoon/feat/friendli-model-metadata-sync
feat(friendli): auto-sync Friendli model metadata into price registry
2026-09-12 21:13:52 -07:00
Shivam Rawat
e8d671c94a
Merge pull request #36585 from BerriAI/litellm_remove_user_soft_budget_docstring
docs(user endpoints): remove unsupported soft_budget param from user docstrings
2026-09-12 21:13:46 -07:00
devin-ai-integration[bot]
8851148330
fix(router): preserve Azure Entra ID params in reusable credentials (#40889)
CredentialLiteLLMParams omitted tenant_id, client_id, client_secret,
azure_scope, azure_username and azure_password, so the strict dump used
by credential reuse and Azure client init dropped them and the reused
credential ended with no auth at all

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-12 21:13:45 -07:00
Yassin Kortam
036bfc08fc
docs(e2e): ban unit tests under tests/e2e (#33852)
The e2e harness exists to prove product features end to end against a live
proxy. The prior Hard Rule carved out an exception for "tests that cover the
harness itself" and pointed at coverage_registry/test_collector.py, which in
practice invited unit tests of harness helpers to be staged alongside e2e
work. That is the wrong tool: harness logic that is worth locking down does
not need a mock-driven unit test living under tests/e2e.

Drop the carve-out. The Hard Rule now reads that no unit tests of any kind
belong under tests/e2e, and the passing mention of unmarked harness coverage
in the transport section is removed so the doc no longer contradicts itself.

coverage_registry/test_collector.py still exists on disk and is left in place
for now; whether to relocate or remove it is a separate decision.
2026-09-12 21:13:43 -07:00
Mateo Wang
939d320246
Merge pull request #40618 from BerriAI/litellm_pr_template_affected_release
docs(github): add an Affected release section to the PR template
2026-09-12 21:13:38 -07:00
devin-ai-integration[bot]
77dc1a6c03
fix(anthropic-adapter): surface mid-stream provider errors as Anthropic error events (#33352)
* fix(anthropic-adapter): surface mid-stream provider errors as Anthropic error events

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

* style(anthropic-adapter): drop added comments per repo convention

Co-Authored-By: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Ishaan Jaffer <155045088+ishaan-berri@users.noreply.github.com>
2026-09-12 21:13:35 -07:00
Mateo Wang
386d29ee67
Merge pull request #38867 from BerriAI/litellm_hide_admin_tabs_view_only
fix(ui): hide admin write-form tabs on the models page from view-only admins
2026-09-12 21:13:34 -07:00
ryan-crabbe-berri
760119681c
Merge pull request #40814 from BerriAI/litellm_gate_health_services_alert_tests
fix(proxy): gate the webhook test alert on proxy admins
2026-09-12 21:13:30 -07:00
Mateo Wang
70e3f5a02e
Merge pull request #39836 from BerriAI/litellm_lit_6975_bedrock_files_delete_list
feat(bedrock): support file delete and list for S3-backed managed files
2026-09-12 21:13:27 -07:00
ryan-crabbe-berri
1ce3690257
Merge pull request #40657 from BerriAI/litellm_lit_7358_session_token_grant_resolver
fix(auth): refresh lite login session token grants from the live user and team rows
2026-09-12 21:13:25 -07:00
Mateo Wang
a978ad2227
Merge pull request #39068 from BerriAI/litellm_spend_log_request_id_call_id
fix(spend_logs): store litellm_call_id and match it in request_id lookups
2026-09-12 21:12:57 -07:00
yuneng-jiang
daa2b0248a
Merge pull request #40172 from BerriAI/litellm_remove_main_guard
ci: remove main branch source guard
2026-09-12 21:10:34 -07:00
mateo-berri
8608a03bd8 Merge origin/litellm_internal_staging into litellm_spend_log_request_id_call_id
Keeps the base's rule that a non-admin id lookup matching no spend-log row answers 403, so the detail route never consults cold storage without an owner row
2026-09-12 21:04:25 -07:00
kerry-berri
9ae727bc8e
Merge pull request #40929 from BerriAI/litellm_fireworks_short_key_lookup
fix(fireworks): resolve short model names to long cost map keys
2026-09-12 20:49:44 -07:00
Devin AI
7a0ea9867d docs(fireworks): drop provider example from get_model_cost_key docstring
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 03:38:14 +00:00
Devin AI
f1fe61af06 docs(fireworks): explain what get_model_cost_key is for
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 03:36:00 +00:00
Devin AI
a519d805bb refactor(fireworks): resolve cost map key through a provider config hook
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 03:29:11 +00:00
Devin AI
0904051fda refactor(fireworks): move cost map key construction under llms/
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-13 03:24:23 +00:00
Mateo Wang
e240997529
Merge pull request #40912 from BerriAI/litellm_logging_worker_timeout_summary
fix(logging): log one bounded summary for a burst of timed-out LoggingWorker callbacks
2026-09-12 19:12:22 -07:00
joshua-berri
b7f4258e32
Merge pull request #40923 from BerriAI/litellm_fix_mcp_delegated_auth_tracking_6970
fix(mcp): require admission for delegated OAuth
2026-09-12 19:11:35 -07:00
devin-ai-integration[bot]
56045503db
fix(proxy): bound tool and guardrail index create_many by the spend-log statement budgets (#40561)
* fix(proxy): bound tool and guardrail index create_many by the spend-log statement budgets

One flush drains up to MAX_LOGS_PER_INTERVAL source transactions or logs, but a
transaction fans out to one LiteLLM_SpendLogToolIndex row per tool and a log
to one LiteLLM_SpendLogGuardrailIndex row per guardrail, so the index
create_many payload was unbounded. Both index writes now go through
spend_log_write_batches(SPEND_LOG_WRITE_BATCH_MAX_BYTES, SPEND_LOG_WRITE_BATCH_MAX_ROWS).
The tool index write moves out of the rollup batch_() so the split reduces
the query-engine payload; replayed index rows are no-ops under
skip_duplicates, and the daily rollup upserts stay in one transaction

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

* test(proxy): pin the row budget in the index fan-out tests

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-12 19:00:47 -07:00
ryan-crabbe-berri
67dd150fed
Merge pull request #36363 from joshgarnett/bugfix/responses-reasoning-object-to-effort
fix(responses): translate the reasoning object into a chat-completion reasoning effort
2026-09-12 18:52:25 -07:00
yuneng-jiang
0f16cff575
Merge pull request #40931 from BerriAI/litellm_/release-version-bump-6cf851
chore: rebuild Admin UI bundle from staging
2026-09-12 18:42:18 -07:00
Joshua Valluru
939fa4ee73 test(mcp): remove unrelated formatting changes 2026-09-12 18:27:20 -07:00