litellm/tests/test_litellm/proxy
ryan-crabbe-berri 96c008f420
ci: fail on new unbounded SQL IN lists and add a Prisma chunking helper (#42629)
* ci: warn on SQL IN lists with no written bound

Postgres caps a prepared statement at 32,767 bind parameters and a
membership filter binds one per value, so an IN list built from table
data breaks once the table outgrows the cap. That is how the budget reset
job froze every due budget (LIT-7535, #40564).

check_unbounded_in_lists.py reports every Prisma "in" / "not_in" filter
whose value has no fixed size and every raw SQL literal that splices a
list in after "IN (", unless the line carries "# bounded-ok: <reason>".
It only warns for now: the output is the inventory for RCA action item
AI-1, and it exits 0.

* ci: decide a constant IN list by its module binding, not its casing

An ALL_CAPS name imported or filled at runtime is as unbounded as any
other, so a name now passes only when the module binds it once to a
value of fixed size. Adds Final to the locals a loop does not forbid.

* ci: only a frozen module value makes an IN list constant

A module list bound once could still grow through append or extend, so
a name now counts as fixed only when it is bound to a tuple, frozenset
or constant. Trims the module docstring to what a reader needs.

* ci: chunk Prisma IN lists with a shared helper and fail on new unbounded ones

Add litellm.repositories.bounded_in: find_many_in, count_in, update_many_in
and delete_many_in split a deduplicated value list into 5,000-value chunks,
AND each chunk with the caller's where, run them in order (a transaction
handle works) and combine the results. Writes take a required atomicity
argument, and a where that already filters the chunked field is refused.

check_unbounded_in_lists.py now fails CI on any finding missing from
unbounded_in_baseline.txt and on any stale baseline entry, so the baseline
only shrinks. Entries are keyed by path, enclosing scope, kind, field and
occurrence, not line numbers. The helper module is exempt, a constant
spread into a frozen tuple counts as fixed, and messages point at the
helper for "in" and at an array parameter for "not_in" and raw SQL.

A real-Postgres integration test shows a raw 40,000-value filter rejected
for too many bind variables while the helpers handle it.

* refactor: rename bounded_in to chunked_in and let callers pick a chunk size

The helper module is litellm.repositories.chunked_in, and its unit and
integration tests, the checker's exemption path and its finding messages
follow the new name. The `# bounded-ok` marker is unchanged.

find_many_in, count_in, update_many_in and delete_many_in take a
keyword-only chunk_size, defaulting to IN_LIST_CHUNK_SIZE (5,000). A value
below 1 or above MAX_IN_LIST_CHUNK_SIZE (30,000) raises ValueError before
any query, which leaves the rest of the filter headroom under Postgres's
32,767 bind-parameter cap.

* refactor: flatten chunked_in's stacked comprehensions with chain.from_iterable

LIT014 (#42650) caps a comprehension at one for and one if clause. The four nested walks in the helper now chain their iterables instead, with the same order and results.

* refactor: recover user details with find_many_in, sending chunks as lists

_details_for_user_ids reads users through find_many_in instead of a raw
"in" filter, so its lookup stays under the bind-parameter cap for any
number of recovered keys. Up to 5,000 ids it still sends one find_many
with the same where dict, and a PrismaError from any chunk is still
logged and treated as no details.

The helper now sends each chunk as a list, so a chunked filter equals
the dict a hand-written call would send and a migrated call site's
existing assertions keep passing.

The site's baseline entry is gone.

* ci: skip functional TypedDict field maps in the unbounded IN list check

The dict passed as the field map of TypedDict("Name", {...}), or as its fields= keyword, names fields: an "in" or "notIn" key there is a type, not a filter. Only that dict is skipped, for TypedDict, typing.TypedDict and typing_extensions.TypedDict; a filter nested in a field value or passed to any other call is still reported. The two types/proxy/management_endpoints/team_endpoints.py entries leave the baseline, which is now 156.

* fix: refuse an update_many_in whose data writes the chunked field

Chunks run one after another, so an update that sets the chunked field can move a row into a later chunk, which updates it again and counts it twice: values ["old", "new"] with chunk_size=1 and data={"id": "new"} does exactly that. update_many_in now raises ChunkedFieldWriteError before any query when data has the chunked field as a top-level key, in any form, including Prisma operators such as {"set": ...}.

* docs: cut the unbounded IN list checker's docstring to what it flags and how to clear it

It now says what is reported, the three ways to clear a finding, and how the baseline and --update-baseline work, in 11 lines. The per-shape detail lives in the tests.

* ci: key an unbounded IN list finding by its filtered expression too

A baseline key of path, scope, kind, field and occurrence let a PR delete
a baselined filter and add a different unbounded one on the same field in
the same function, and the new one took over the old key. The key now
also carries the filtered expression's source, whitespace-normalized
(the Prisma value, or a raw-SQL `IN (...)` slot), so that swap reads as
one new and one stale entry and fails the run. The same expression
re-added in the same function is still the same finding.

Every baseline entry is rewritten in the new form; the 156 findings are
unchanged, and only occurrence indexes renumber where one field had
several different expressions.
2026-09-26 13:40:44 -07:00
..
_experimental/mcp_server refactor(mcp): add shared server resolver without changing callers (#43262) 2026-09-26 13:01:37 -07:00
a2a fix(a2a): reject malformed protocolVersion suffixes while keeping semver prereleases 2026-07-21 13:24:58 -07:00
agent_endpoints feat(agents): add optional per-agent kill switch webhook (#42841) 2026-09-24 18:26:50 -05:00
analytics_endpoints fix(proxy): attribute gate-rejected requests to their endpoint in cache analytics (#40824) 2026-09-12 16:03:38 -07:00
anthropic_endpoints feat(proxy): opt-in litellm_call_id in JSON error bodies (#42391) 2026-09-21 19:17:18 -07:00
auth feat(proxy): email alerts at configured percentages of a team member budget (#42665) 2026-09-26 02:42:45 +00:00
batches_endpoints fix(spend): attribute CLI session spend to the per-user cli-session alias instead of the hashed session token (#40541) 2026-09-24 18:21:47 -07:00
client test: move tests/test_litellm core utils, routing, responses, caching and rust_bridge into tests/unit (#43199) 2026-09-25 17:10:13 -07:00
common_utils fix(proxy): send a real error event when a /v1/messages stream fails (#41826) 2026-09-25 15:36:35 -07:00
config_resolvers test: drop two inert type: ignore comments 2026-09-19 14:22:19 -07:00
container_endpoints fix(containers): page upstream until a non-admin container list fills its limit 2026-09-02 21:26:34 -07:00
credential_endpoints fix(credentials): answer 409 on a name collision, let PATCH resolve values from model_id 2026-09-15 10:41:43 -07:00
db fix(proxy): pass team member spend rows as jsonb so a $0 flush cannot poison the pool connection (#43029) 2026-09-24 20:44:56 +00:00
discovery_endpoints chore(proxy): drop explanatory docstrings from credentials hint helper and tests 2026-09-14 19:29:30 +00:00
enterprise_billing feat(proxy): push-based OTLP billable-request metering for enterprise deployments (#31592) 2026-07-15 12:12:52 -07:00
experimental/mcp_server test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
fine_tuning_endpoints test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
google_endpoints test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
guardrails refactor(anthropic): rename experimental_pass_through to pass_through (#43329) 2026-09-26 13:00:50 -07:00
health_endpoints feat(langfuse): migrate the sdk callback to langfuse v4 (#36741) 2026-09-24 23:22:56 -07:00
hooks feat(proxy): add fail_closed_rate_limit_enforcement to reject requests with 503 while Redis rate limit counters are unreachable (#43251) 2026-09-26 12:11:26 -07:00
image_endpoints ci: move tests/proxy_unit_tests to tests/unit/proxy and run the proxy-db shards from litellm-tests (#42903) 2026-09-24 22:59:11 +00:00
list_api feat: page the public model hub table off /public/v1/model_hub, keeping every filter (#39691) 2026-09-03 22:36:16 -07:00
logging_endpoints fix(usage): recover aliases for v1.99 double-hashed spend keys 2026-09-03 14:21:25 +00:00
management_endpoints test(mcp): pin server resolution and authorization behavior (#43261) 2026-09-26 12:59:11 -07:00
management_helpers fix(key_management): count team unified access group MCP servers when validating key MCP grants (#41231) 2026-09-24 23:34:15 -07:00
memory feat(proxy): add a search param to key, memory, audit, and spend log listings 2026-09-03 15:20:13 -07:00
middleware fix(proxy): release unclaimed budget reservations at request end (#42304) 2026-09-21 19:51:12 -07:00
ocr_endpoints refactor(ocr): remove the Python OCR execution path and require the Rust route (#43081) 2026-09-24 18:18:50 -07:00
openai_files_endpoint feat(vertex): native batch JSONL passthrough with cost tracking (#42810) 2026-09-24 12:35:34 -07:00
pass_through_endpoints test: move tests/test_litellm core utils, routing, responses, caching and rust_bridge into tests/unit (#43199) 2026-09-25 17:10:13 -07:00
policy_engine fix(policy_engine): keep inherited parent guardrails when a child policy condition misses (#42548) 2026-09-22 23:27:38 -07:00
prompts fix(prompts): accept a string prompt_version and carry the viewed environment into code snippets 2026-08-29 12:55:34 -07:00
proxy_server feat(proxy): add fail_closed_rate_limit_enforcement to reject requests with 503 while Redis rate limit counters are unreachable (#43251) 2026-09-26 12:11:26 -07:00
public_endpoints feat(ui): simplify auto-router setup and clarify feature limits (#42625) 2026-09-22 18:03:32 -07:00
rag_endpoints test(rag): drop the docstrings from the registered-store ingest tests 2026-09-19 04:10:49 -07:00
realtime_endpoints refactor(proxy): replace configurable model access denied message with a fixed clean client message 2026-09-16 01:44:36 +00:00
rerank_endpoints fix(proxy): carry litellm_call_id through endpoint specific error logs and failure responses 2026-09-16 02:29:26 +00:00
response_api_endpoints fix(proxy): document request body and response schemas for the Responses API in OpenAPI (#42802) 2026-09-24 01:28:34 +00:00
shutdown refactor(proxy): inject scheduled job shutdown timeouts 2026-09-21 19:37:28 +00:00
spend_tracking ci: fail on new unbounded SQL IN lists and add a Prisma chunking helper (#42629) 2026-09-26 13:40:44 -07:00
test_configs
types_utils feat(proxy): unified custom_key_policy hook for key generate, update and regenerate 2026-09-12 16:09:24 -07:00
ui_crud_endpoints fix(proxy): keep the submitted body out of 422 validation errors (#43231) 2026-09-25 17:05:53 -07:00
utils refactor(anthropic): rename experimental_pass_through to pass_through (#43329) 2026-09-26 13:00:50 -07:00
vector_store_endpoints fix(vector_stores): keep config-defined vector stores listed and read-only (#42574) 2026-09-23 04:02:16 +00:00
vector_store_files_endpoints test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
video_endpoints fix(videos): forward uploaded source file on /v1/videos/edits to the provider 2026-08-24 15:34:21 -07:00
__init__.py
conftest.py test(proxy): isolate the agent read-through singleton between unknown-agent tests 2026-09-22 01:34:31 +00:00
test__types.py feat(mcp): configure protocol versions and capability discovery (#43169) 2026-09-25 13:13:52 -07:00
test_aiohttp_cleanup_closed.py
test_aiohttp_session_recovery.py
test_api_key_masking_in_errors.py
test_audio_speech_prometheus_hooks.py fix(proxy): match /v1/audio/speech content-type to the returned audio format 2026-08-29 13:44:43 -07:00
test_batch_expiry.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_batch_metadata_none_fix.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_batch_retrieve_bedrock.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_batch_x_litellm_model_encoding.py fix(proxy): apply model grants to unified file and batch ids on batch routes 2026-09-10 18:10:18 -04:00
test_blocked_response_usage.py fix(guardrails): remove the module-global translation mapping that leaked between tests 2026-09-03 03:28:52 -07:00
test_budget_reservation.py refactor(anthropic): rename experimental_pass_through to pass_through (#43329) 2026-09-26 13:00:50 -07:00
test_bug_report_config.py feat(proxy): admin-only /debug/report sharing the bug report environment (#42440) 2026-09-22 12:05:23 -07:00
test_caching_routes.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_chat_completion_metadata.py
test_claude_code_marketplace.py test: run the 30 test files stranded in the second mirror (#37595) 2026-08-20 10:59:43 -07:00
test_collector.py feat(proxy): offload spend tracking to a pod-local collector sidecar (#40545) 2026-09-10 17:14:13 -07:00
test_common_request_processing.py fix(proxy): send a real error event when a /v1/messages stream fails (#41826) 2026-09-25 15:36:35 -07:00
test_component_allowlists.py test(proxy): make two proxy-infra tests independent of sibling-test state (#42581) 2026-09-22 14:58:42 -07:00
test_conftest.py test(proxy): stop monkeypatch.undo re-planting fixture-mocked prisma_client 2026-08-13 20:11:06 -07:00
test_cors_config.py
test_custom_proxy.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_dynamic_mcp_route.py fix(proxy): serve aggregate MCP endpoint on bare /mcp instead of 307-redirecting (#34845) 2026-08-14 17:04:32 -07:00
test_empty_model_list.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_enforce_user_param.py test: require a match= on broad pytest.raises, and drop duplicate parametrize cases (#37769) 2026-08-20 20:24:49 -07:00
test_fallback_management_endpoints.py
test_fastapi_offline_routes.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_filter_models_by_team_access_group.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_health_check_functions.py fix(health): skip background health check DB writes when the latest-row read fails 2026-09-14 23:03:30 +00:00
test_health_check_max_tokens.py feat(auto-router): integrate JEV context and usage accounting 2026-09-18 21:38:15 +00:00
test_init_litellm_callbacks.py test: run the 30 test files stranded in the second mirror (#37595) 2026-08-20 10:59:43 -07:00
test_langfuse_passthrough_security.py
test_lazy_openapi_snapshot.py refactor(proxy): type the snapshot fragments and wrap a long test line 2026-08-26 14:39:51 -07:00
test_litellm_pre_call_utils.py fix(spend): attribute CLI session spend to the per-user cli-session alias instead of the hashed session token (#40541) 2026-09-24 18:21:47 -07:00
test_max_budget_env_var.py
test_mcp_asgi_response.py fix(mcp): surface upstream 401 for token-forwarding MCP servers (#27847) 2026-05-13 12:03:36 -07:00
test_model_based_routing_files_batches.py test(batches): move orphan tests into tests/test_litellm for CI coverage (#30510) 2026-06-16 10:20:59 -07:00
test_model_deprecations_endpoint.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_model_dump_with_preserved_fields.py
test_model_id_header_propagation.py feat(proxy): add x-litellm-model-name response header with deployment model string (#33698) 2026-07-17 20:29:42 -07:00
test_model_info_default_limits.py perf(proxy): serialize /model/info listing once with orjson 2026-09-14 19:47:51 +00:00
test_model_level_guardrails.py fix(mcp): keep tool attribution on guardrail-blocked REST calls (#42790) 2026-09-23 15:40:56 -07:00
test_model_list_aliases.py fix(proxy): list key and team model aliases in GET /v1/models (#42908) 2026-09-24 06:41:13 -07:00
test_model_list_callback_filter.py feat(proxy): let callbacks filter the model listing routes per caller (#43027) 2026-09-24 15:52:44 -07:00
test_model_list_discoverable.py feat(proxy): honor model_info.discoverable on the model listing endpoints (#42825) 2026-09-23 17:51:16 -07:00
test_model_list_healthy_only.py perf(proxy): serialize /model/info listing once with orjson 2026-09-14 19:47:51 +00:00
test_modify_response_streaming_passthrough.py fix(proxy): use e.request_data for logging_obj in ModifyResponseException streaming passthrough (#30800) 2026-06-18 23:29:08 -07:00
test_native_compaction.py fix(gateway): expose /api/event_logging/batch on the gateway allowlist (#42572) 2026-09-22 14:09:40 -07:00
test_openai_ws_passthrough_routes.py fix(proxy): keep the token's team model list in the websocket passthrough gate without a database 2026-09-04 19:05:35 -07:00
test_openapi_schema_validation.py fix(proxy): preserve HTTP operations when injecting WebSocket stubs into OpenAPI schema 2026-05-06 00:28:42 +02:00
test_plugin_routes.py refactor(proxy): resolve config and DB settings precedence in one SettingsStore 2026-09-17 23:36:27 -07:00
test_pointfive_dashboard_config.py feat(pointfive): add pointfive to the dashboard logging integrations 2026-09-10 14:02:35 +03:00
test_pointfive_ui_callback.py feat(pointfive): list pointfive in the proxy callback registry 2026-09-10 14:02:35 +03:00
test_pricing_field_strip.py fix(proxy): fold litellm_metadata into metadata on chat routes so tag routing sees merged tags 2026-08-29 00:42:43 -07:00
test_prisma_engine_watchdog.py fix(proxy): recreate the Prisma client when the writer session turns read-only (#40610) 2026-09-10 13:53:42 -07:00
test_prisma_migration.py fix(proxy): run migrations through python -m prisma when the prisma console script is not on PATH 2026-09-09 18:17:12 -07:00
test_prometheus_cleanup.py feat(deploy): metrics sidecar and separate metrics port in Helm and Terraform (#40163) 2026-09-08 13:31:07 -07:00
test_prometheus_metrics_server.py feat(deploy): metrics sidecar and separate metrics port in Helm and Terraform (#40163) 2026-09-08 13:31:07 -07:00
test_provider_url_destination_guard.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_proxy_cli.py feat(proxy_cli): add --validate_config dry-run flag (#41705) 2026-09-24 17:07:10 -05:00
test_proxy_logging_hook_detection.py fix(guardrails): store the masked output in spend logs when Presidio masks the response (#42441) 2026-09-22 01:19:22 -07:00
test_proxy_server.py test: move tests/test_litellm core utils, routing, responses, caching and rust_bridge into tests/unit (#43199) 2026-09-25 17:10:13 -07:00
test_proxy_types.py fix(router): honor team and key provider weights 2026-09-14 23:31:52 -07:00
test_proxy_utils.py test: move tests/test_litellm core utils, routing, responses, caching and rust_bridge into tests/unit (#43199) 2026-09-25 17:10:13 -07:00
test_pyroscope.py Implement normalize_nonempty_secret_str function to trim whitespace from secrets and treat empty values as unset. Update proxy_server to use this function for Grafana credentials. Enhance tests to validate the new normalization behavior. 2026-05-04 18:17:31 +00:00
test_read_model_list.py feat: add minimal rust router + axum ai-gateway calling router.realtime (2/2) (#31135) 2026-06-23 19:16:34 -07:00
test_redis_auth_cache_flag.py fix(proxy): share per-model budget counters across replicas through the spend counter cache (#39375) 2026-09-02 12:40:59 -07:00
test_response_model_sanitization.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_route_a2a_models.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_route_llm_request.py test(proxy): isolate the agent read-through singleton between unknown-agent tests 2026-09-22 01:34:31 +00:00
test_route_priority.py perf(proxy): register liveness and core inference routes first (#40687) 2026-09-11 17:10:38 +00:00
test_sensitive_route_auth.py
test_shared_health_check.py fix(proxy): derive auto-router health from its underlying models (#38174) 2026-08-26 16:41:54 -07:00
test_spend_log_cleanup.py fix(proxy): give SpendLogToolIndex its own share of the cleanup budget and log a per-run summary (#41768) 2026-09-25 09:40:20 -07:00
test_swagger_chat_completions.py
test_team_member_update.py fix(team): schedule membership audit writes after commit and lock the roster on role updates 2026-09-19 22:33:22 +00:00
test_team_org_move.py test: require a match= on broad pytest.raises, and drop duplicate parametrize cases (#37769) 2026-08-20 20:24:49 -07:00
test_tools_allowlist_enforcement.py fix(anthropic): close hybrid tool-name allowlist gap and keep native tools through guardrails 2026-08-26 20:37:11 -07:00
test_update_llm_router_resilience.py fix(proxy): keep the no-model_list guard to absent reads so model_list: [] still evicts 2026-09-16 23:14:52 +00:00
test_zerobus_dashboard_config.py feat(integrations): add Databricks Zerobus trace logging callback (#42013) 2026-09-25 15:29:23 -07:00