From 107f8d1cd19fa70878c6c0cc9839ea09f8dcbe68 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Thu, 13 Aug 2026 12:07:35 -0700 Subject: [PATCH] test(e2e): cover Bedrock reached with the gateway's own AWS identity Every Bedrock test in the suite names os.environ/AWS_ACCESS_KEY_ID and os.environ/AWS_SECRET_ACCESS_KEY in its litellm_params, so all of them keep passing when the gateway's own AWS identity is revoked, repointed at the wrong role, or stripped of its Bedrock grant. That identity is how the gateway is actually deployed on AWS, and nothing covered it. Adds one deployment carrying only a region, so boto3 has to fall through to its ambient chain, plus the registry row it claims. --- tests/e2e/coverage_registry/other.yaml | 1 + .../other/test_ambient_aws_credentials_e2e.py | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 tests/e2e/other/test_ambient_aws_credentials_e2e.py diff --git a/tests/e2e/coverage_registry/other.yaml b/tests/e2e/coverage_registry/other.yaml index c7140a4503b..a4816bac880 100644 --- a/tests/e2e/coverage_registry/other.yaml +++ b/tests/e2e/coverage_registry/other.yaml @@ -43,3 +43,4 @@ - {id: other.a2a.message_send.bridge_invokes, module: other, tier: P1, area: a2a, assertions: [bridge_invokes], source: "a2a_protocol/litellm_completion_bridge/handler.py", rationale: "A2A message/send routes through the completion bridge to a real provider and logs an asend_message spend row"} - {id: other.a2a.version.serves_pinned_0_3, module: other, tier: P1, area: a2a, assertions: [serves_pinned_0_3], source: "agent_endpoints/a2a_endpoints.py _served_version", rationale: "An agent pinning 0.3 returns the flat 0.3 message shape (parts on the result)"} - {id: other.a2a.version.serves_pinned_1_0, module: other, tier: P1, area: a2a, assertions: [serves_pinned_1_0], source: "agent_endpoints/a2a_endpoints.py _served_version", rationale: "An agent pinning 1.0 returns the nested 1.0 message shape (result.message with ROLE_AGENT)"} +- {id: other.auth.aws_ambient_credentials.resolves_without_static_keys, module: other, tier: P0, area: auth, assertions: [resolves_without_static_keys], source: "llms/bedrock/base_aws_llm.py boto3.Session() fallback", rationale: "A Bedrock deployment carrying only a region must resolve credentials from the gateway's own AWS identity (EKS Pod Identity, IRSA, instance profile), which is how it is deployed on AWS; every other Bedrock test names static keys in litellm_params and so stays green when that identity is revoked or misassociated"} diff --git a/tests/e2e/other/test_ambient_aws_credentials_e2e.py b/tests/e2e/other/test_ambient_aws_credentials_e2e.py new file mode 100644 index 00000000000..85a84275b4c --- /dev/null +++ b/tests/e2e/other/test_ambient_aws_credentials_e2e.py @@ -0,0 +1,77 @@ +"""Live e2e: Bedrock reached with the credentials the gateway's environment gives it. + +A deployment whose litellm_params name no `aws_access_key_id` and no +`aws_secret_access_key` must still reach Bedrock, by resolving credentials +through boto3's ambient chain (`base_aws_llm.py` falls through to +`boto3.Session()`). That is how the gateway is deployed on AWS: an EKS Pod +Identity association, an IRSA role, or an EC2 instance profile supplies the +identity, and the config carries a region and nothing secret. + +Nothing else in the suite covers that. Every other Bedrock test names +`os.environ/AWS_ACCESS_KEY_ID` and `os.environ/AWS_SECRET_ACCESS_KEY` in its +litellm_params, so all of them keep passing if the pod's own identity is +revoked, misassociated, or stripped of its Bedrock grant. This test is the one +that goes red, and it is deliberately the cheapest possible shape of that +signal: one short completion, no tools, no streaming. +""" + +from __future__ import annotations + +import pytest + +from e2e_config import unique_marker +from e2e_http import Success +from lifecycle import ResourceManager +from models import ChatBody, ChatMessage, LiteLLMParamsBody +from proxy_client import ProxyClient + +pytestmark = pytest.mark.e2e + +BEDROCK_MODEL = "bedrock/converse/us.anthropic.claude-haiku-4-5-20251001-v1:0" + + +class TestAmbientAwsCredentials: + @pytest.mark.covers( + "other.auth.aws_ambient_credentials.resolves_without_static_keys", + exercised_on=["chat_completions"], + ) + def test_bedrock_deployment_without_static_keys_completes( + self, proxy: ProxyClient, resources: ResourceManager + ) -> None: + """A key-less Bedrock deployment answers a real completion. + + `aws_region_name` is the only AWS field set. Adding either static + credential here would defeat the test: boto3 prefers what it is handed, + so the call would pass without the ambient identity ever being consulted. + """ + model = f"e2e-bedrock-ambient-{unique_marker()}" + model_id = proxy.create_model( + model, + LiteLLMParamsBody(model=BEDROCK_MODEL, aws_region_name="os.environ/AWS_REGION"), + ) + resources.defer(lambda: proxy.delete_model(model_id)) + + result = proxy.chat( + resources.key(), + ChatBody( + model=model, + messages=[ + ChatMessage(role="user", content=f"Reply with one word. {unique_marker()}") + ], + max_tokens=16, + ), + ) + + match result: + case Success(data=response): + assert response.choices, ( + f"Bedrock answered without a completion, so the request reached AWS but " + f"came back empty: {response}" + ) + case failure: + pytest.fail( + "Bedrock was unreachable using only the gateway's ambient AWS identity. " + "A credentials error here means the pod lost that identity (association " + "removed or repointed, or its role lost Bedrock); any other error means " + f"the deployment itself is wrong. Got: {failure}" + )