litellm/tests/test_litellm/proxy/guardrails
yucheng-berri 6e05ac5d97
feat(guardrails): add inspect_embeddings toggle for AIM and Cato (#39918)
* fix(guardrails): don't inspect embeddings in the AIM and Cato hooks

`pre_call_hook` fires for /embeddings as well as chat. An embeddings body
carries `input` — documents being indexed, not a prompt — which
`build_inspection_messages` lifts into synthetic chat messages, so both hooks
inspect it as a conversation and a policy verdict on that text breaks a request
that was never one:

- AIM, anonymize + batched `input`: `has_non_string_content` is true for any
  list, so `_anonymize_request` raises 400 "...multimodal input...".
- AIM, anonymize + single-string `input`: no error — the input is rewritten to
  redacted text and the caller embeds text it never sent.
- AIM and Cato, block: the embeddings request is blocked outright.

Gate both hooks on a new `NON_CONVERSATIONAL_CALL_TYPES` deny-list. This is
deliberately not `TEXT_CONTENT_CALL_TYPES`: that allow-list omits
`anthropic_messages`, `responses` and `call_mcp_tool`, so gating on it would
stop these guardrails inspecting real chat traffic. An unrecognised or newly
added call type is still inspected.

* feat(guardrails): add inspect_embeddings toggle for AIM and Cato

* fix(guardrails): redact batched embedding input on anonymize

A list of plain strings is the /embeddings batch shape. AIM rejected it as
multimodal and Cato forwarded the original strings, so anonymize never
reached the provider for batched input. Redactions are now written back
element-wise, one redacted message per non-empty element, so a fully
redacted element cannot shift the following documents into the wrong slot.

* fix(guardrails): reject partial embedding redactions

* fix(guardrails): avoid unnecessary batch type check

* style(tests): drop trailing blank line in cato guardrail tests

* fix(guardrails): reject malformed batch redactions

* fix(guardrails): reject malformed batch redactions

* fix(guardrails): reject aim redactions with no text content

The anonymize path read role and content off every entry of the vendor's
redacted_chat before the shared write-back helper could refuse the payload,
so a message missing content, or a bare string in place of a message, raised
out of the hook as a 500. Validate the vendor list first and return the 400
the guardrail already uses for an unusable redaction.

* fix(guardrails): validate all aim redaction paths

Validate AIM redaction containers before request or output rewrites, reject
cardinality mismatches and empty output, and cover malformed vendor payloads
with regression tests.

* fix(guardrails): preserve aim output redaction alignment

AIM returns the inspected request messages followed by the assistant output.
Validate that full response and select the final redacted message instead of
requiring a single entry.

* test(guardrails): cover aim output anonymize alignment and malformed redactions

---------

Co-authored-by: Guy Levi <guy.levi@catonetworks.com>
2026-09-05 17:15:46 -07:00
..
guardrail_hooks feat(guardrails): add inspect_embeddings toggle for AIM and Cato (#39918) 2026-09-05 17:15:46 -07:00
test_auto_router_compression.py docs(auto-router compression): cut the explanatory comments back 2026-09-05 11:33:21 -07:00
test_content_filter_path_traversal.py Litellm OSS Staging 010626 (#29422) 2026-06-01 21:42:51 -07:00
test_content_utils.py feat(guardrails): add inspect_embeddings toggle for AIM and Cato (#39918) 2026-09-05 17:15:46 -07:00
test_custom_code_security.py feat(guardrails): add non-blocking flag() verdict to custom code guardrails (#39728) 2026-09-05 13:08:03 -07:00
test_deferred_guardrail_logging.py fix(guardrails): unwrap HiddenParamsAsyncIteratorWrapper before deferred dispatch class sniffing 2026-08-29 02:30:34 -07:00
test_guardrail_coverage.py feat(guardrails): add Lakera v2 skip-message honoring and advisory (inject_system_message) mode (#34940) 2026-08-28 14:13:49 -07:00
test_guardrail_endpoints.py feat(guardrails): add inspect_embeddings toggle for AIM and Cato (#39918) 2026-09-05 17:15:46 -07:00
test_guardrail_registry.py Merge pull request #39243 from BerriAI/litellm_fix_guardrail_event_hook_resync 2026-09-03 14:37:52 -07:00
test_init_guardrails.py feat(guardrails): add Lakera v2 skip-message honoring and advisory (inject_system_message) mode (#34940) 2026-08-28 14:13:49 -07:00
test_llm_as_a_judge.py test: require a match= on broad pytest.raises, and drop duplicate parametrize cases (#37769) 2026-08-20 20:24:49 -07:00
test_mcp_jwt_signer.py fix(mcp): JWT on tools/list and REST tools/call server resolution (#28227) 2026-05-20 13:31:44 -07:00
test_pillar_guardrails.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_prompt_security_guardrails.py fix(guardrails): configure Prompt Security file timeout policy (#38083) 2026-08-31 12:05:57 -07:00
test_qostodian_nexus_guardrail.py test: enforce F811 so a duplicate definition cannot silently replace the first 2026-08-21 12:06:19 -07:00
test_usage_endpoints.py Merge pull request #39853 from BerriAI/litellm_guardrail_usage_cost_ui 2026-09-05 14:41:11 -07:00
test_usage_tracking.py feat(guardrails): add non-blocking flag() verdict to custom code guardrails (#39728) 2026-09-05 13:08:03 -07:00