Commit graph

39031 commits

Author SHA1 Message Date
Noah
8947a74e13
fix(cache): persist and replay streamed Responses API requests (#24580)
* fix(cache): persist and replay streamed Responses API requests

* Add focused coverage for streamed responses cache

* Cover streamed responses cache helper branches

* Exercise streamed responses cache edge branches
2026-05-01 11:55:36 +05:30
user
f51dd68ff0 test(proxy): cover lazy openapi operation ids 2026-04-30 23:00:25 -07:00
user
66c0fe23da handle bad reservation counters after spend write 2026-04-30 22:55:26 -07:00
user
6ef26945fa test(proxy): narrow media resource decoding 2026-04-30 22:55:00 -07:00
user
0704f672c5 test(proxy): cover resource model extraction fallbacks 2026-04-30 22:21:57 -07:00
user
a5135b1b55 chore(proxy): stabilize lazy openapi snapshot 2026-04-30 22:14:47 -07:00
user
3b54012b7b chore(proxy): satisfy auth model checks CI 2026-04-30 22:04:14 -07:00
user
336fe8276f chore(proxy): align resource model auth checks 2026-04-30 21:59:56 -07:00
yuneng-jiang
934ecdca78
Merge pull request #26962 from BerriAI/litellm_internal_staging
Some checks failed
Read Version from pyproject.toml / read-version (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
CodSpeed Benchmarks / benchmarks (push) Has been cancelled
Helm unit test / unit-test (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Unit Tests: Caching (Redis) / caching-redis (push) Has been cancelled
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Has been cancelled
Unit Tests: Security / security (push) Has been cancelled
GitHub Actions Security Analysis / zizmor (push) Has been cancelled
Unit Tests: Proxy DB Operations / auth-checks (push) Has been cancelled
Unit Tests: Proxy DB Operations / budgets (push) Has been cancelled
Unit Tests: Proxy DB Operations / custom-logging (push) Has been cancelled
Unit Tests: Proxy DB Operations / db-and-spend (push) Has been cancelled
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Has been cancelled
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Has been cancelled
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Has been cancelled
Unit Tests: Proxy DB Operations / key-generation (push) Has been cancelled
Unit Tests: Proxy DB Operations / logging-misc (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-runtime (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-server-core (push) Has been cancelled
Unit Tests: Proxy DB Operations / schema-migration (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-utils (push) Has been cancelled
[Infra] Promote Internal Staging to main
2026-04-30 21:59:55 -07:00
Sameer Kankute
03f6818a54
fix(mcp): cache negative org object_permission lookups to avoid per-request DB hits
Orgs with no MCP permissions configured (the common default) previously
returned None without writing to cache, meaning every subsequent MCP
request triggered a fresh find_unique against litellm_organizationtable.

Cache a sentinel string on the negative path so the DB is queried at most
once per cache TTL per org, regardless of whether the org has an
object_permission or not.

Made-with: Cursor
2026-05-01 10:29:39 +05:30
user
41eeaaf630
fix(guardrails): handle Aim multi-choice gather exceptions cleanly
Greptile P2: ``asyncio.gather`` without ``return_exceptions=True`` lets
the first failing call propagate immediately, leaving the other in-flight
inspections running until they complete on their own. Pass
``return_exceptions=True`` so every inspection finishes, then re-raise
the first exception encountered while iterating results.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 04:58:00 +00:00
user
0b1ea9eb8f harden budget reservation edge cases 2026-04-30 21:49:31 -07:00
Sameer Kankute
8398952e81
fix(mcp): address Greptile P1/P2 findings in org-level permission enforcement
- Cache org object_permission in user_api_key_cache to avoid a DB hit on
  every MCP request (was: raw find_unique on every call).
- Expand org mcp_servers list via expand_permission_list() so name-based
  entries resolve to canonical IDs, consistent with key/team/end-user path.
- Expand org mcp_tool_permissions via expand_tool_permissions() in both
  _get_allowed_mcp_servers_for_org and get_allowed_tools_for_server,
  closing the silent name-vs-ID mismatch that could let restricted tools
  through.
- The second _get_org_object_permission call in get_allowed_tools_for_server
  now hits the cache (warm from the earlier server-list check), resolving
  the double DB round-trip without changing the call structure.

Made-with: Cursor
2026-05-01 10:16:58 +05:30
shin-berri
9397409c5b
Merge pull request #26961 from BerriAI/yj_bump_apr30
[Infra] Bump Versions
2026-04-30 21:46:50 -07:00
user
5397ac4562
fix(guardrails): redact `data["input"]` for Responses-API mask paths
Greptile P1: Aim's ``_anonymize_request`` and Lakera v2's mask-PII path
both wrote redacted content only to ``data["messages"]``. The Responses
API backend reads ``data["input"]``, so when a request arrived via
``/v1/responses`` with a plain string ``input`` the hook would update
``messages`` (which the backend ignores) and leave ``input`` carrying
the original unredacted text. Net effect: anonymize/mask silently passed
PII through to the LLM.

Add ``apply_redacted_messages_back`` to ``_content_utils`` — it writes
the redacted messages back to ``data["messages"]`` AND, when present,
re-flattens the redacted content into ``data["input"]``. Aim and
Lakera v2 now route their mask writeback through this helper. List
``input`` (multimodal) is still handled by the upstream
block-on-multimodal guard.

Adds unit tests for the helper and regression tests asserting
``data["input"]`` is redacted for both hooks on Responses-API string
input.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 04:41:57 +00:00
Sameer Kankute
b540a71e47
feat(mcp): enforce org-level MCP server and toolset permissions
Apply organization object_permission as a ceiling on allowed MCP servers
and tool permissions, consistent with vector store org checks.

Includes unit tests for org ceiling, intersection, and tool filtering.

Made-with: Cursor
2026-05-01 10:10:38 +05:30
Yuneng Jiang
6da13efcec
uv lock 2026-04-30 21:40:09 -07:00
Yuneng Jiang
dd549d9c50
bump: version 0.4.69 → 0.4.70 2026-04-30 21:39:37 -07:00
user
40817caa4a
fix(guardrails): degrade Lasso/Aim mask paths to block on multimodal
Two more in-place rewrite paths exhibit the same regression as Lakera v2:
overwriting ``data["messages"]`` with text-only redacted versions silently
strips image/audio parts from multimodal requests.

- ``LassoGuardrail._run_lasso_guardrail``: when ``mask=True`` AND input
  is multimodal/Responses-API list, fall back to the classify endpoint
  (which raises on BLOCK actions but never overwrites the payload).
- ``AimGuardrail._anonymize_request``: when input is multimodal, raise
  the standard 400 instead of replacing ``data["messages"]`` with the
  text-only ``redacted_chat`` from Aim. The error message tells the
  user to either send plain string content or rely on block-mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 04:28:22 +00:00
user
9fcf234750
fix(guardrails): degrade Lakera v2 mask mode to block on multimodal input
Mask-in-place uses the offsets that Lakera returns for the inspection
payload. ``build_inspection_messages`` flattens multimodal content into
joined text before sending to Lakera, so the offsets refer to the
flattened representation. Writing those offsets back via
``_mask_pii_in_messages`` and overwriting ``data["messages"]`` would
silently strip image/audio parts from the original request — that is a
real functional regression for Lakera + mask mode + multimodal input.

Detect multimodal input (any list-format ``content`` or non-string
``data["input"]``) up front and skip the mask-in-place branch in that
case. The hook then falls into the standard block-on-detect path so PII
is still blocked but the multimodal payload is never silently rewritten.

Per-part masking that preserves multimodal structure is the right
long-term fix; tracking that as a follow-up.

Also: add ``has_non_string_content`` to ``_content_utils`` (with tests)
and a regression test that asserts multimodal+PII raises an HTTPException
instead of returning a flattened request body.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 04:22:57 +00:00
user
b53adf7cff address budget reservation review edges 2026-04-30 21:21:26 -07:00
user
7514bb4740
fix(guardrails): close mixed-list gap, drop dead code, rename helper
Greptile P2 follow-ups on _content_utils.py:

- Drop unreachable ``_resolve_messages``. The new
  ``_iter_inspection_messages`` walks ``messages`` AND ``input``
  independently; leaving the old fallback-only variant around invited a
  future maintainer to wire it back up and silently narrow coverage.
- Rename ``iter_user_text`` → ``iter_message_text``. The helper walks
  every role (user, assistant, system); the old name implied user-turn
  content only. Callers and tests updated.
- Close mixed-list coverage gap. When ``data["input"]`` was a list
  mixing content-part dicts and bare strings, ``iter_message_text`` and
  ``build_inspection_messages`` only saw the dict parts while
  ``walk_user_text`` already inspected both. ``_iter_text_parts_in_content``
  now treats bare strings inside a content list as text fragments, so
  read and write helpers agree on coverage.

Adds two regression tests for the mixed-list shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 04:10:04 +00:00
user
d767708571
fix(guardrails): add mypy type-ignore for lakera_v2 mask call
CI mypy flagged the two ``_mask_pii_in_messages(messages=new_messages, ...)``
call sites because ``build_inspection_messages`` returns
``List[Dict[str, str]]`` while ``_mask_pii_in_messages`` declares
``List[AllMessageValues]``. The runtime payload matches; widening the
return type to a Union of TypedDicts is a larger refactor than is
warranted by this hardening change, so add the localised ``# type: ignore``
to match the two we already added on the ``call_v2_guard`` calls above.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 04:01:27 +00:00
user
ce17639cf7 remove budget reservation disable flag 2026-04-30 20:57:20 -07:00
user
b1b00e4bdc
chore(guardrails): cover multimodal + Responses-API content shapes
Several guardrail hooks short-circuit when ``message.content`` is a list
or when the request uses the Responses-API ``input`` field instead of
``messages``. Centralise the content-walking logic in a shared helper and
update the affected hooks so list-format and Responses-API payloads no
longer skip inspection.

Also: Aim's ``async_post_call_success_hook`` now inspects every choice
(via ``asyncio.gather``) instead of only ``choices[0]`` — the prior
behaviour let ``n>1`` callers hide content in subsequent completions.

Hooks updated to use the new helper:
- aim, lakera_ai_v2, lasso (post a synthesised messages list to a remote
  guardrail service)
- azure_content_safety, ibm_detector, banned_keywords, openai_moderation,
  google_text_moderation (iterate text fragments locally)
- secret_detection (walk-and-rewrite to redact in place)

Drive-by fix: the legacy ``data["prompt"]`` list-handling path in
secret_detection rebound the loop variable instead of mutating the list,
leaving secrets unredacted on text-completion calls; corrected to index
back into the list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 03:50:15 +00:00
user
e9fb89b90c fix(proxy): avoid misleading multi-method operation ids 2026-04-30 20:44:14 -07:00
user
f30bfcf36a add budget reservation disable flag 2026-04-30 20:36:14 -07:00
user
f18ee0319d fix(proxy): isolate ownership persistence paths 2026-04-30 20:25:40 -07:00
user
4f8769943b skip invalid budget window counter increments 2026-04-30 20:18:07 -07:00
user
2ecc79b9e9 test(proxy): cover skill ownership propagation 2026-04-30 20:06:44 -07:00
user
dcfde1b899 fallback to plain org cache for spend counters 2026-04-30 20:04:16 -07:00
user
a02aacf1b5 fix(proxy): type openapi snapshot operation ids 2026-04-30 20:01:43 -07:00
user
3a566c3938 fix(proxy): stabilize ownership fallback and openapi ids 2026-04-30 19:55:00 -07:00
Sameer Kankute
efa33bfe50
Merge pull request #26222 from BerriAI/litellm_anthropic-json-mode-nonstreaming-mixed-tools
Some checks are pending
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
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 / schema-migration (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run
Unit Tests: Caching (Redis) / caching-redis (push) Waiting to run
fix(anthropic): json response_format + user tools non-streaming
2026-05-01 08:24:38 +05:30
Sameer Kankute
72ddbce50e
Merge pull request #25499 from BerriAI/litellm_vertex_request_metadata_labels
feat(vertex_ai): propagate metadata labels to embedding, Imagen, rerank
2026-05-01 08:20:55 +05:30
user
c28e093f41 finalize budget reservations after counter updates 2026-04-30 19:50:36 -07:00
user
abd51fc30e
fix(audit): label vault POST as updated when DB row exists
Greptile P2 follow-up: when a litellm_configoverrides row exists with a
NULL config_value (e.g. an earlier failed write left a stub), the audit
action was mislabeled "created" because we keyed off existing_decrypted
(which is only set when config_value is non-null). Key off existing_record
instead — a row is a row regardless of its value.

Also hoist asyncio + patch imports to module top in the test file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 02:44:47 +00:00
user
20eb9c96ca fix(proxy): avoid mutating container responses 2026-04-30 19:43:20 -07:00
user
7b1e3f278b test(proxy): cover container endpoint post processing 2026-04-30 19:34:20 -07:00
user
15d845c321 avoid stale local spend counters after redis misses 2026-04-30 19:33:55 -07:00
user
f3cff9338e fix(proxy): harden resource ownership fallbacks 2026-04-30 19:29:08 -07:00
user
405de46329 cap budget reservations to remaining headroom 2026-04-30 19:24:48 -07:00
user
6aac4552f9 fix(proxy): forward decoded container ids 2026-04-30 19:13:20 -07:00
user
9376b30bca fix(proxy): reset filtered container pagination 2026-04-30 19:01:37 -07:00
Krrish Dholakia
dd57ae6691 feat(rate-limit): atomic check-and-increment-by-N for multi-process safety
The previous fix for the TOCTOU bypass relied on a per-instance asyncio.Lock,
which closed the window only within a single proxy worker. Multi-replica
deployments still raced across processes — A and B both read counter=99,
both passed validation, both incremented to 100/100 → effective limit doubled.

Add `CHECK_AND_INCREMENT_BY_N_SCRIPT` Lua script that processes any number of
(window_key, counter_key, limit, increment, ttl) descriptors atomically with
all-or-nothing semantics: if any descriptor would exceed its limit, no counter
is modified and the script returns OVER_LIMIT with the offending descriptor's
state. When Redis isn't configured, the in-memory fallback uses the existing
asyncio.Lock for single-process atomicity.

Expose this as `_PROXY_MaxParallelRequestsHandler_v3.atomic_check_and_increment_by_n`
and rewire both call sites:

- batch_rate_limiter._check_and_increment_batch_counters: replace the
  read_only=True check + separate async_increment_tokens_with_ttl_preservation
  with a single atomic call passing the batch's (request_count, total_tokens)
  as the increment.
- dynamic_rate_limiter_v3._check_rate_limits: bundle model_saturation_check
  (always enforced) and priority_model (enforced only when saturated) into
  one atomic call. When priority is unenforced, increment its counter via
  the existing should_rate_limit(read_only=False) path for tracking only.

Update structural regression tests to assert the new atomic path is used
rather than the legacy two-phase pattern.

Tests: 4/4 TOCTOU tests pass, 59 existing rate-limiter tests pass, no
regressions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 18:54:36 -07:00
user
e4741fbb2b fix(proxy): add legacy skill ownership opt-out 2026-04-30 18:53:44 -07:00
harish-berri
7c86e6073b Merge branch 'litellm_internal_staging' of https://github.com/BerriAI/litellm into litellm_auth_bypass_tag_based_routing
Some checks failed
Unit Tests: Security / security (push) Has been cancelled
Unit Tests: Caching (Redis) / caching-redis (push) Has been cancelled
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Has been cancelled
Unit Tests: Proxy DB Operations / key-generation (push) Has been cancelled
Unit Tests: Proxy DB Operations / auth-checks (push) Has been cancelled
Unit Tests: Proxy DB Operations / budgets (push) Has been cancelled
Unit Tests: Proxy DB Operations / custom-logging (push) Has been cancelled
Unit Tests: Proxy DB Operations / db-and-spend (push) Has been cancelled
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Has been cancelled
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Has been cancelled
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Has been cancelled
Unit Tests: Proxy DB Operations / logging-misc (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-runtime (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-server-core (push) Has been cancelled
Unit Tests: Proxy DB Operations / schema-migration (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-utils (push) Has been cancelled
2026-05-01 01:49:39 +00:00
user
aa1312ef75 fix(audit): close NameError + mypy + asyncio-import nits
Three Greptile/CI findings on the prior commit:

1. **P1 (real bug):** ``before_config = existing_decrypted if existing_record
   is not None else env_values`` would NameError when ``existing_record``
   exists but its ``config_value`` is null (a valid nullable DB state) —
   the upper branch only defines ``existing_decrypted`` when *both*
   conditions are met, but the ternary only checked the first.  Pre-bind
   ``existing_decrypted: Optional[Dict] = None`` and ``env_values = {}``
   above the if/else so both names are always in scope, and key the
   audit-log decision off ``existing_decrypted is not None`` instead.

2. **mypy lint:** ``action: str`` rejected — the field is typed
   ``AUDIT_ACTIONS = Literal[...]``.  Annotate both helper signatures
   with ``AUDIT_ACTIONS`` and pre-bind the call-site ternary so mypy
   infers the literal correctly.

3. **P2:** ``import asyncio`` was at the bottom of the test file.
   Moved to the stdlib import block at top.
2026-05-01 01:47:11 +00:00
user
0745b1872e test(proxy): cover container endpoint forwarding 2026-04-30 18:46:14 -07:00
Krrish Dholakia
dbe5c3b0b2 fix: close TOCTOU window in batch + dynamic rate limiters
The batch rate limiter (`_check_and_increment_batch_counters`) and the
dynamic rate limiter (`_check_rate_limits`) implemented rate limiting in
two disjoint awaits: a `should_rate_limit(read_only=True)` check followed
by a separate increment. Concurrent requests could all observe the same
pre-increment state, all pass enforcement, and all then increment —
multiplying the effective quota by the concurrency level.

Demonstrated bypass (see new test):
- Batch: 5 concurrent batches of 40 tokens each against TPM=100 consumed
  200 tokens (100% over).
- Dynamic: 5 concurrent priority="high" requests against RPM=2 all
  passed Phase 1 + Phase 3.

Wrap both critical sections in a per-instance asyncio.Lock so the read
and increment execute atomically within a process. Multi-replica
deployments still rely on Redis Lua atomicity for cross-process safety;
that is a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 18:46:09 -07:00