From 6ecad76deca720c5e753515d8f4154ecd6fbb656 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Tue, 18 Aug 2026 19:38:05 -0700 Subject: [PATCH] test: allow protocol-constrained pass-through routes to declare fewer methods (#37415) The pass-through method contract asserted that every route accepts GET, POST, PUT, DELETE and PATCH. That holds for routes fronting a REST API, where narrowing the set turns a request the upstream would have served into a 405, but it does not hold for Amazon Comprehend Medical: it speaks AWS JSON 1.1, which is POST-only, and its handler signs a POST upstream and requires a JSON object body. Registering the other four verbs there would only produce routes that always fail body parsing, so the route is POST-only on purpose and the blanket assertion is the part that is wrong. Carry a narrow exemption list instead of dropping the check. Exempted routes are still pinned to an exact method set, so widening or narrowing one fails, and a companion test asserts every exempted path is still registered so the list cannot outlive the routes it covers. --- .../test_pass_through_unit_tests.py | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/tests/pass_through_unit_tests/test_pass_through_unit_tests.py b/tests/pass_through_unit_tests/test_pass_through_unit_tests.py index c263b8ce381..77fb924c085 100644 --- a/tests/pass_through_unit_tests/test_pass_through_unit_tests.py +++ b/tests/pass_through_unit_tests/test_pass_through_unit_tests.py @@ -413,35 +413,54 @@ async def test_pass_through_request_logging_failure_with_stream( assert response.body == b'{"mock": "response"}' +PROTOCOL_CONSTRAINED_PASS_THROUGH_ROUTES = { + "/comprehendmedical": {"POST"}, + "/comprehendmedical/{operation}": {"POST"}, +} + + def test_pass_through_routes_support_all_methods(): """ - Test that all pass-through routes support GET, POST, PUT, DELETE, PATCH methods + A pass-through route fronts a whole provider API, so narrowing its method + set turns a request the upstream would have accepted into a 405. The + exceptions are providers whose wire protocol admits only one method: Amazon + Comprehend Medical speaks AWS JSON 1.1, which is POST-only, so there is no + other method to forward. """ - # Import the routers from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import ( router as llm_router, ) - # Expected HTTP methods expected_methods = {"GET", "POST", "PUT", "DELETE", "PATCH"} - # Function to check routes in a router def check_router_methods(router): for route in router.routes: if isinstance(route, APIRoute): - # Get path and methods for this route path = route.path methods = set(route.methods) - print("supported methods for route", path, "are", methods) - # Assert all expected methods are supported + allowed = PROTOCOL_CONSTRAINED_PASS_THROUGH_ROUTES.get(path, expected_methods) assert ( - methods == expected_methods - ), f"Route {path} does not support all methods. Supported: {methods}, Expected: {expected_methods}" + methods == allowed + ), f"Route {path} does not support all methods. Supported: {methods}, Expected: {allowed}" - # Check both routers check_router_methods(llm_router) +def test_protocol_constrained_pass_through_exemptions_are_not_stale(): + """ + The exemption list above weakens the method contract, so it must not + outlive the routes it covers: a renamed or deleted route has to fail here + rather than sit in the list silently exempting nothing. + """ + from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import ( + router as llm_router, + ) + + registered_paths = {route.path for route in llm_router.routes if isinstance(route, APIRoute)} + unmatched = set(PROTOCOL_CONSTRAINED_PASS_THROUGH_ROUTES) - registered_paths + assert not unmatched, f"Exempted pass-through routes no longer exist: {sorted(unmatched)}" + + def test_is_bedrock_agent_runtime_route(): """ Test that _is_bedrock_agent_runtime_route correctly identifies bedrock agent runtime endpoints