diff --git a/litellm/responses/file_search/emulated_handler.py b/litellm/responses/file_search/emulated_handler.py index 77539efd090..aacef9c2198 100644 --- a/litellm/responses/file_search/emulated_handler.py +++ b/litellm/responses/file_search/emulated_handler.py @@ -461,7 +461,7 @@ async def _execute_file_search_tool_calls( vs_id_arg = args.get("vector_store_id") if vs_id_arg is not None and vs_id_arg not in all_vs_ids: verbose_logger.warning( - "file_search emulated: model picked vector_store_id='%s' outside the request's vector_store_ids %s; " + "file_search emulated: model picked vector_store_id=%r outside the request's vector_store_ids %s; " "searching the request's stores instead", vs_id_arg, all_vs_ids, diff --git a/tests/test_litellm/llms/test_file_search_responses.py b/tests/test_litellm/llms/test_file_search_responses.py index 0339f07d414..90c60fd20e8 100644 --- a/tests/test_litellm/llms/test_file_search_responses.py +++ b/tests/test_litellm/llms/test_file_search_responses.py @@ -940,10 +940,8 @@ class TestEmulatedFileSearchHandler: @pytest.mark.asyncio async def test_H16_model_chosen_id_outside_request_is_not_searched(self, caplog): - """Security regression: a vector_store_id the model returns that was not in the - request's file_search tool must never be searched. Per-key authorization only sees - request ids, so honoring an off-schema id leaks stores the key cannot access. - The handler must fall back to the request's own stores instead.""" + """A vector_store_id the model returns that the request did not list is never + searched; the request's own stores are searched instead, with a warning.""" from litellm.responses.file_search.emulated_handler import ( aresponses_with_emulated_file_search, ) @@ -953,11 +951,11 @@ class TestEmulatedFileSearchHandler: { "type": "function_call", "name": "litellm_file_search", - "call_id": "call_leak", - "arguments": '{"queries": ["launch codeword"], "vector_store_id": "vs_unauthorized"}', + "call_id": "call_unlisted", + "arguments": '{"queries": ["launch codeword"], "vector_store_id": "vs_unlisted"}', } ] - first_resp.id = "resp_leak" + first_resp.id = "resp_unlisted" first_resp.created_at = 1700000000 first_resp.model = "claude-3-5-sonnet" first_resp.usage = None @@ -990,11 +988,9 @@ class TestEmulatedFileSearchHandler: searched_ids = [c.kwargs["vector_store_id"] for c in mock_asearch.call_args_list] assert searched_ids, "Expected the vector store to be searched at least once" - assert "vs_unauthorized" not in searched_ids, ( - "Handler searched the off-schema store the model picked; per-key auth never saw it" - ) + assert "vs_unlisted" not in searched_ids, "Handler searched a store the request did not list" assert set(searched_ids) == {"vs_allowed"} - dropped_id_warnings = [r for r in caplog.records if "vs_unauthorized" in r.getMessage()] + dropped_id_warnings = [r for r in caplog.records if "vs_unlisted" in r.getMessage()] assert len(dropped_id_warnings) == 1, "Expected one warning naming the dropped model-picked id" assert dropped_id_warnings[0].levelno == logging.WARNING assert "vs_allowed" in dropped_id_warnings[0].getMessage()