diff --git a/litellm/llms/bedrock/base_aws_llm.py b/litellm/llms/bedrock/base_aws_llm.py index 9591b962ab5..7276eb7f19e 100644 --- a/litellm/llms/bedrock/base_aws_llm.py +++ b/litellm/llms/bedrock/base_aws_llm.py @@ -215,9 +215,25 @@ class BearerRequestTarget(BedrockRequestTarget): credentials: None = None -def bedrock_bearer_token(api_key: str | None) -> str | None: - token: Final = api_key if api_key is not None else get_secret_str("AWS_BEARER_TOKEN_BEDROCK") - return token or None +def _has_explicit_sigv4_params(auth_params: AwsAuthParams | None) -> bool: + return auth_params is not None and any( + ( + auth_params.aws_access_key_id, + auth_params.aws_secret_access_key, + auth_params.aws_session_token, + auth_params.aws_role_name, + auth_params.aws_profile_name, + auth_params.aws_web_identity_token, + ) + ) + + +def bedrock_bearer_token(api_key: str | None, auth_params: AwsAuthParams | None = None) -> str | None: + if api_key is not None: + return api_key or None + if _has_explicit_sigv4_params(auth_params): + return None + return get_secret_str("AWS_BEARER_TOKEN_BEDROCK") or None class _WebIdentityTokenClaims(LiteLLMBaseModel): @@ -1635,7 +1651,9 @@ class BaseAWSLLM(SignsRequestsWithAWS): api_key: str | None = None, supports_bearer_token: bool = True, ) -> AWSPreparedRequest | BearerPreparedRequest: - aws_bearer_token: Final = bedrock_bearer_token(api_key) if supports_bearer_token else None + aws_bearer_token: Final = ( + bedrock_bearer_token(api_key) if supports_bearer_token and (api_key or credentials is None) else None + ) if aws_bearer_token is not None: headers["Authorization"] = f"Bearer {aws_bearer_token}" @@ -1737,7 +1755,8 @@ class BaseAWSLLM(SignsRequestsWithAWS): Returns: Tuple[dict, Optional[str]]: A tuple containing the headers and the json str body of the request """ - aws_bearer_token: Final = bedrock_bearer_token(api_key) + auth_params: Final = AwsAuthParams.model_validate(optional_params) + aws_bearer_token: Final = bedrock_bearer_token(api_key, auth_params) if aws_bearer_token is not None: headers = headers or {} @@ -1751,7 +1770,6 @@ class BaseAWSLLM(SignsRequestsWithAWS): from botocore.awsrequest import AWSRequest from botocore.credentials import Credentials - auth_params: Final = AwsAuthParams.model_validate(optional_params) aws_region_name: Final = self._get_aws_region_name(optional_params=optional_params, model=model) credentials: Final[Credentials] = self.resolve_credentials(auth_params, aws_region_name) diff --git a/litellm/llms/bedrock/chat/chat_completions/transformation.py b/litellm/llms/bedrock/chat/chat_completions/transformation.py index dd2277a6c35..0375a5746b1 100644 --- a/litellm/llms/bedrock/chat/chat_completions/transformation.py +++ b/litellm/llms/bedrock/chat/chat_completions/transformation.py @@ -47,6 +47,7 @@ from litellm.llms.bedrock.common_utils import ( ) from litellm.llms.openai.chat.gpt_transformation import OpenAIChatCompletionStreamingHandler from litellm.llms.openai_like.chat.transformation import OpenAILikeChatConfig +from litellm.types.llms.bedrock import AwsAuthParams from litellm.types.llms.openai import AllMessageValues from litellm.types.utils import Choices, ModelResponse, ModelResponseStream @@ -355,7 +356,7 @@ class AmazonBedrockRuntimeChatCompletionsConfig(OpenAILikeChatConfig): messages=messages, optional_params=optional_params, litellm_params=litellm_params, - api_key=bedrock_bearer_token(api_key), + api_key=bedrock_bearer_token(api_key, AwsAuthParams.model_validate(optional_params)), api_base=api_base, ) diff --git a/litellm/llms/bedrock/chat/converse_handler.py b/litellm/llms/bedrock/chat/converse_handler.py index a6f9192339f..122637eb4fc 100644 --- a/litellm/llms/bedrock/chat/converse_handler.py +++ b/litellm/llms/bedrock/chat/converse_handler.py @@ -346,15 +346,14 @@ class BedrockConverseLLM(BaseAWSLLM): ) auth_params: Final = pop_aws_auth_params(optional_params) + aws_bearer_token: Final = bedrock_bearer_token(api_key, auth_params) aws_bedrock_runtime_endpoint: Final = optional_params.pop("aws_bedrock_runtime_endpoint", None) optional_params.pop("aws_region_name", None) litellm_params["aws_region_name"] = aws_region_name # [DO NOT DELETE] important for async calls credentials: Final[Credentials | None] = ( - None - if bedrock_bearer_token(api_key) is not None - else self.resolve_credentials(auth_params, aws_region_name) + None if aws_bearer_token is not None else self.resolve_credentials(auth_params, aws_region_name) ) ### SET RUNTIME ENDPOINT ### diff --git a/litellm/llms/bedrock/embed/embedding.py b/litellm/llms/bedrock/embed/embedding.py index f15a512077a..cd156d817cc 100644 --- a/litellm/llms/bedrock/embed/embedding.py +++ b/litellm/llms/bedrock/embed/embedding.py @@ -25,6 +25,7 @@ from litellm.llms.custom_httpx.http_handler import ( from litellm.secret_managers.main import get_secret from litellm.types.llms.bedrock import ( AmazonEmbeddingRequest, + AwsAuthParams, CohereEmbeddingRequest, TwelveLabsAsyncInvokeStatusResponse, ) @@ -439,7 +440,7 @@ class BedrockEmbedding(BaseAWSLLM): bedrock_model: Final = _without_region_path(model_without_async_route) credentials, aws_region_name = self._load_credentials( optional_params, - bearer_token=bedrock_bearer_token(api_key), + bearer_token=bedrock_bearer_token(api_key, AwsAuthParams.model_validate(optional_params)), region_from_model=self._get_aws_region_from_model_arn(model_id_param) or path_region, ) diff --git a/litellm/llms/bedrock/image_edit/handler.py b/litellm/llms/bedrock/image_edit/handler.py index bdfe6f5a8d2..f39a184e760 100644 --- a/litellm/llms/bedrock/image_edit/handler.py +++ b/litellm/llms/bedrock/image_edit/handler.py @@ -29,7 +29,7 @@ from litellm.llms.custom_httpx.http_handler import ( get_httpx_client, ) from litellm.types.llms.base import LiteLLMBaseModel -from litellm.types.llms.bedrock import BearerPreparedRequest +from litellm.types.llms.bedrock import AwsAuthParams, BearerPreparedRequest from litellm.types.utils import ImageResponse from ..base_aws_llm import BaseAWSLLM, bedrock_bearer_token @@ -214,7 +214,9 @@ class BedrockImageEdit(BaseAWSLLM): BedrockImageEditPreparedRequest: The prepared request object """ boto3_credentials_info: Final = self._get_boto_credentials_from_optional_params( - optional_params, model, bearer_token=bedrock_bearer_token(api_key) + optional_params, + model, + bearer_token=bedrock_bearer_token(api_key, AwsAuthParams.model_validate(optional_params)), ) # Use the existing ARN-aware provider detection method diff --git a/litellm/llms/bedrock/image_generation/image_handler.py b/litellm/llms/bedrock/image_generation/image_handler.py index abd6d40f9e9..1c525c95fda 100644 --- a/litellm/llms/bedrock/image_generation/image_handler.py +++ b/litellm/llms/bedrock/image_generation/image_handler.py @@ -28,7 +28,7 @@ from litellm.llms.custom_httpx.http_handler import ( get_httpx_client, ) from litellm.types.llms.base import LiteLLMBaseModel -from litellm.types.llms.bedrock import BearerPreparedRequest +from litellm.types.llms.bedrock import AwsAuthParams, BearerPreparedRequest from litellm.types.utils import ImageResponse from ..base_aws_llm import BaseAWSLLM, bedrock_bearer_token @@ -233,7 +233,9 @@ class BedrockImageGeneration(BaseAWSLLM): body (bytes): The request body """ boto3_credentials_info: Final = self._get_boto_credentials_from_optional_params( - optional_params, model, bearer_token=bedrock_bearer_token(api_key) + optional_params, + model, + bearer_token=bedrock_bearer_token(api_key, AwsAuthParams.model_validate(optional_params)), ) # Use the existing ARN-aware provider detection method diff --git a/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py b/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py index 6a773f41f01..49621223733 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py +++ b/litellm/proxy/guardrails/guardrail_hooks/bedrock_guardrails.py @@ -70,6 +70,7 @@ from litellm.types.guardrails import ( GuardrailEventHooks, LitellmParams, ) +from litellm.types.llms.bedrock import AwsAuthParams from litellm.types.llms.openai import AllMessageValues, ChatCompletionUserMessage from litellm.types.proxy.guardrails.guardrail_hooks.bedrock_guardrails import ( BedrockChecksMessage, @@ -329,6 +330,7 @@ class BedrockGuardrail(CustomGuardrail, BaseAWSLLM): # store kwargs as optional_params self.optional_params = kwargs + self.aws_auth_params: Final = AwsAuthParams.model_validate(kwargs) self.disable_exception_on_block: bool = disable_exception_on_block or False """ @@ -830,7 +832,7 @@ class BedrockGuardrail(CustomGuardrail, BaseAWSLLM): credentials: Final[Credentials | None] = ( None - if bedrock_bearer_token(api_key) is not None + if bedrock_bearer_token(api_key, self.aws_auth_params) is not None else self.get_credentials( aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key, @@ -874,7 +876,7 @@ class BedrockGuardrail(CustomGuardrail, BaseAWSLLM): proxy_endpoint_url = f"{proxy_endpoint_url}{request_path}" encoded_data: Final = json.dumps(data).encode("utf-8") - aws_bearer_token: Final = bedrock_bearer_token(api_key) + aws_bearer_token: Final = bedrock_bearer_token(api_key, self.aws_auth_params) if aws_bearer_token is not None: try: diff --git a/tests/unit/llms/bedrock/chat/chat_completions/test_bedrock_chat_completions_transformation.py b/tests/unit/llms/bedrock/chat/chat_completions/test_bedrock_chat_completions_transformation.py index f4dcff1969e..b35405d3536 100644 --- a/tests/unit/llms/bedrock/chat/chat_completions/test_bedrock_chat_completions_transformation.py +++ b/tests/unit/llms/bedrock/chat/chat_completions/test_bedrock_chat_completions_transformation.py @@ -550,6 +550,36 @@ def test_bearer_api_key_is_sent_as_the_authorization_header(monkeypatch): assert headers["Authorization"] == "Bearer bedrock-api-key" +@pytest.mark.parametrize( + "auth_kwargs, authorization_prefix", + [ + ( + { + "aws_access_key_id": SIGV4_PARAMS["aws_access_key_id"], + "aws_secret_access_key": SIGV4_PARAMS["aws_secret_access_key"], + }, + f"AWS4-HMAC-SHA256 Credential={SIGV4_PARAMS['aws_access_key_id']}/", + ), + ({}, "Bearer env-bedrock-token"), + ], + ids=["explicit-keys-sign-sigv4", "no-keys-use-env-token"], +) +def test_explicit_aws_keys_win_over_the_env_bearer_token( + local_cost_map, fake_aws_env, monkeypatch, auth_kwargs, authorization_prefix +): + monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "env-bedrock-token") + requests, client = _recording_client(json=_chat_completion_json("ok", "us.xai.grok-4.6")) + litellm.completion( + model="bedrock/chat_completions/us.xai.grok-4.6", + messages=[{"role": "user", "content": "hello"}], + client=client, + **auth_kwargs, + ) + + assert len(requests) == 1 + assert requests[0].headers["Authorization"].startswith(authorization_prefix), requests[0].headers + + @pytest.mark.parametrize( "request_params, expected_route", [ diff --git a/tests/unit/llms/bedrock/chat/test_bedrock_converse_handler.py b/tests/unit/llms/bedrock/chat/test_bedrock_converse_handler.py index 7d1b502df2b..f96be373452 100644 --- a/tests/unit/llms/bedrock/chat/test_bedrock_converse_handler.py +++ b/tests/unit/llms/bedrock/chat/test_bedrock_converse_handler.py @@ -218,9 +218,10 @@ def test_bearer_token_auth_serves_when_boto3_resolves_no_sigv4_credentials(monke @pytest.mark.parametrize("configured_through", ["env_var", "api_key"]) def test_bearer_token_auth_never_runs_the_sigv4_credential_chain(monkeypatch, configured_through): - """The deployment's AWS profile does not exist, so resolving SigV4 credentials - raises; a bearer-token deployment must still serve the request, since the - bearer token alone signs it.""" + """The process's default AWS profile does not exist, so resolving SigV4 + credentials raises; a bearer-token deployment must still serve the request, + since the bearer token alone signs it.""" + monkeypatch.setenv("AWS_PROFILE", "litellm-no-such-aws-profile") if configured_through == "env_var": monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "bedrock-bearer-token") else: @@ -229,7 +230,7 @@ def test_bearer_token_auth_never_runs_the_sigv4_credential_chain(monkeypatch, co response = BedrockConverseLLM().completion( **_completion_kwargs( - optional_params={"maxTokens": 16, "aws_profile_name": "litellm-no-such-aws-profile"}, + optional_params={"maxTokens": 16}, litellm_params={}, client=client, api_key="bedrock-bearer-token" if configured_through == "api_key" else None, @@ -240,6 +241,26 @@ def test_bearer_token_auth_never_runs_the_sigv4_credential_chain(monkeypatch, co assert client.post.call_args.kwargs["headers"]["Authorization"] == "Bearer bedrock-bearer-token" +def test_explicit_deployment_keys_sign_over_the_env_bearer_token(monkeypatch): + monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "bedrock-bearer-token") + client = _sync_client_returning_converse_response() + + response = BedrockConverseLLM().completion( + **_completion_kwargs( + optional_params={ + "maxTokens": 16, + "aws_access_key_id": "AKIAEXPLICITDEPLOYMENT", + "aws_secret_access_key": "explicit-secret", + }, + litellm_params={}, + client=client, + ) + ) + + assert response.choices[0].message.content == "hi" + assert "Credential=AKIAEXPLICITDEPLOYMENT/" in client.post.call_args.kwargs["headers"]["Authorization"] + + def test_session_tags_sign_the_request_and_stay_out_of_the_body(monkeypatch): """The tagged STS session signs the Converse call and the tags never reach the request body (#34069).""" monkeypatch.delenv("AWS_BEARER_TOKEN_BEDROCK", raising=False) diff --git a/tests/unit/llms/bedrock/embed/test_bedrock_async_invoke_embedding.py b/tests/unit/llms/bedrock/embed/test_bedrock_async_invoke_embedding.py index da5993fff6d..252a0da6e75 100644 --- a/tests/unit/llms/bedrock/embed/test_bedrock_async_invoke_embedding.py +++ b/tests/unit/llms/bedrock/embed/test_bedrock_async_invoke_embedding.py @@ -182,6 +182,37 @@ class TestBedrockAsyncInvokeEmbedding: request_url = mock_post.call_args.kwargs.get("url", "") assert "/async-invoke" in request_url + def test_async_invoke_signs_with_explicit_deployment_keys_over_env_bearer_token(self, monkeypatch): + """A deployment configured with its own IAM keys must sign StartAsyncInvoke + with SigV4 even when AWS_BEARER_TOKEN_BEDROCK is set in the process: a + Bedrock API key cannot write the S3 output, so Bedrock rejects the bearer + request with "Invalid S3 credentials".""" + monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "env-bearer-token-12345") + client = HTTPHandler() + + with patch.object(client, "post") as mock_post: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.text = json.dumps(async_invoke_response) + mock_response.json = lambda: json.loads(mock_response.text) + mock_post.return_value = mock_response + + response = litellm.embedding( + model="bedrock/async_invoke/twelvelabs.marengo-embed-3-0-v1:0", + input=test_input, + client=client, + aws_region_name="us-east-1", + aws_access_key_id="AKIAEXPLICITDEPLOYMENT", + aws_secret_access_key="explicit-deployment-secret", + input_type="text", + output_s3_uri="s3://test-bucket/async-invoke-output/", + ) + + authorization = mock_post.call_args.kwargs["headers"]["Authorization"] + assert response._hidden_params._invocation_arn == async_invoke_response["invocationArn"] + assert authorization.startswith("AWS4-HMAC-SHA256 Credential=AKIAEXPLICITDEPLOYMENT/") + assert "Bearer" not in authorization + def test_async_invoke_marengo_3_wraps_the_nested_payload_with_the_base_model_id(self): client = HTTPHandler() diff --git a/tests/unit/llms/bedrock/embed/test_bedrock_embedding.py b/tests/unit/llms/bedrock/embed/test_bedrock_embedding.py index 904ca3bb8ca..29bcaaafaf5 100644 --- a/tests/unit/llms/bedrock/embed/test_bedrock_embedding.py +++ b/tests/unit/llms/bedrock/embed/test_bedrock_embedding.py @@ -1449,10 +1449,11 @@ def test_embedding_session_tags_sign_the_request_and_stay_out_of_the_body(monkey def test_bedrock_embedding_bearer_token_never_runs_the_sigv4_credential_chain(monkeypatch): - """The deployment's AWS profile does not exist, so resolving SigV4 credentials - raises; a bearer-token deployment must still serve the request, since the - bearer token alone signs it.""" + """The process's default AWS profile does not exist, so resolving SigV4 + credentials raises; a bearer-token deployment must still serve the request, + since the bearer token alone signs it.""" monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "env-bearer-token-12345") + monkeypatch.setenv("AWS_PROFILE", "litellm-no-such-aws-profile") client = HTTPHandler() with patch.object(client, "post") as mock_post: @@ -1467,7 +1468,6 @@ def test_bedrock_embedding_bearer_token_never_runs_the_sigv4_credential_chain(mo input=test_input, client=client, aws_region_name="us-west-2", - aws_profile_name="litellm-no-such-aws-profile", ) assert response.data[0]["embedding"] == titan_embedding_response["embedding"] diff --git a/tests/unit/llms/bedrock/image/test_bedrock_image_bearer_token.py b/tests/unit/llms/bedrock/image/test_bedrock_image_bearer_token.py index 599507da03d..339b0d19b58 100644 --- a/tests/unit/llms/bedrock/image/test_bedrock_image_bearer_token.py +++ b/tests/unit/llms/bedrock/image/test_bedrock_image_bearer_token.py @@ -1,17 +1,18 @@ from unittest.mock import Mock def test_image_generation_bearer_token_never_runs_the_sigv4_credential_chain(monkeypatch): - """The deployment's AWS profile does not exist, so resolving SigV4 credentials - raises; a bearer-token deployment must still sign the request with the - bearer token alone.""" + """The process's default AWS profile does not exist, so resolving SigV4 + credentials raises; a bearer-token deployment must still sign the request + with the bearer token alone.""" from litellm.llms.bedrock.image_generation.image_handler import BedrockImageGeneration monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "env-bearer-token-12345") + monkeypatch.setenv("AWS_PROFILE", "litellm-no-such-aws-profile") request = BedrockImageGeneration()._prepare_request( model="amazon.nova-canvas-v1:0", prompt="A cute baby sea otter", - optional_params={"aws_region_name": "us-west-2", "aws_profile_name": "litellm-no-such-aws-profile"}, + optional_params={"aws_region_name": "us-west-2"}, api_base=None, extra_headers=None, api_key=None, diff --git a/tests/unit/llms/bedrock/image_edit/test_amazon_nova_canvas_image_edit.py b/tests/unit/llms/bedrock/image_edit/test_amazon_nova_canvas_image_edit.py index 122dd5b555a..4d430fdec71 100644 --- a/tests/unit/llms/bedrock/image_edit/test_amazon_nova_canvas_image_edit.py +++ b/tests/unit/llms/bedrock/image_edit/test_amazon_nova_canvas_image_edit.py @@ -610,16 +610,17 @@ def test_transform_response_empty_images_without_error_raises(): def test_prepare_request_bearer_token_never_runs_the_sigv4_credential_chain(monkeypatch): - """The deployment's AWS profile does not exist, so resolving SigV4 credentials - raises; a bearer-token deployment must still sign the request with the - bearer token alone.""" + """The process's default AWS profile does not exist, so resolving SigV4 + credentials raises; a bearer-token deployment must still sign the request + with the bearer token alone.""" monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "env-bearer-token-12345") + monkeypatch.setenv("AWS_PROFILE", "litellm-no-such-aws-profile") request = BedrockImageEdit()._prepare_request( model="amazon.nova-canvas-v1:0", image=[io.BytesIO(b"fake-png")], prompt="make it warmer", - optional_params={"aws_region_name": "us-west-2", "aws_profile_name": "litellm-no-such-aws-profile"}, + optional_params={"aws_region_name": "us-west-2"}, api_base=None, extra_headers=None, logging_obj=Mock(), diff --git a/tests/unit/llms/bedrock/test_base_aws_llm.py b/tests/unit/llms/bedrock/test_base_aws_llm.py index c220e39f4d1..6433c9b190e 100644 --- a/tests/unit/llms/bedrock/test_base_aws_llm.py +++ b/tests/unit/llms/bedrock/test_base_aws_llm.py @@ -768,6 +768,52 @@ def test_get_request_headers_preserves_bearer_payload(from_environment): assert result.method == "POST" +@pytest.mark.parametrize( + ("api_key", "optional_params", "expected"), + [ + (None, {}, "env-bearer-token-12345"), + (None, {"aws_region_name": "us-west-2", "aws_access_key_id": None}, "env-bearer-token-12345"), + (None, {"aws_access_key_id": "AKIAEXPLICIT", "aws_secret_access_key": "secret"}, None), + (None, {"aws_session_token": "session"}, None), + (None, {"aws_profile_name": "deployment-profile"}, None), + (None, {"aws_role_name": "arn:aws:iam::123456789012:role/deployment"}, None), + (None, {"aws_web_identity_token": "oidc-token"}, None), + ("explicit-bearer", {"aws_access_key_id": "AKIAEXPLICIT"}, "explicit-bearer"), + ("", {}, None), + ("", {"aws_access_key_id": "AKIAEXPLICIT"}, None), + ], +) +def test_bedrock_bearer_token_env_token_yields_to_explicit_sigv4_params(monkeypatch, api_key, optional_params, expected): + """The env bearer token is the ambient fallback: explicit SigV4 params on the + deployment turn it off, an explicit api_key still wins over both, and an + explicit empty api_key keeps meaning "no bearer, sign with SigV4".""" + from litellm.llms.bedrock.base_aws_llm import bedrock_bearer_token + from litellm.types.llms.bedrock import AwsAuthParams + + monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "env-bearer-token-12345") + + assert bedrock_bearer_token(api_key, AwsAuthParams.model_validate(optional_params)) == expected + + +def test_get_request_headers_signs_with_resolved_credentials_despite_env_bearer_token(monkeypatch): + """Credentials resolved from the deployment's explicit SigV4 params must sign + the request even when the process carries AWS_BEARER_TOKEN_BEDROCK, which a + Bedrock API key cannot do on the caller's behalf for S3-backed calls.""" + monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "env-bearer-token-12345") + + prepared = BaseAWSLLM().get_request_headers( + credentials=Credentials("test_key", "test_secret", "test_token"), + aws_region_name="us-west-2", + extra_headers=None, + endpoint_url="https://bedrock-runtime.us-west-2.amazonaws.com/async-invoke", + data='{"prompt": "test"}', + headers={"Content-Type": "application/json"}, + ) + + assert prepared.headers["Authorization"].startswith("AWS4-HMAC-SHA256 Credential=test_key/") + assert "Bearer" not in prepared.headers["Authorization"] + + def test_get_request_headers_with_sigv4(): # Setup llm = BaseAWSLLM() diff --git a/tests/unit/proxy/guardrails/guardrail_hooks/test_bedrock_guardrails.py b/tests/unit/proxy/guardrails/guardrail_hooks/test_bedrock_guardrails.py index 1fb56509b7f..0f359a5c4c3 100644 --- a/tests/unit/proxy/guardrails/guardrail_hooks/test_bedrock_guardrails.py +++ b/tests/unit/proxy/guardrails/guardrail_hooks/test_bedrock_guardrails.py @@ -6156,14 +6156,14 @@ async def test_apply_guardrail_debug_log_masks_signed_request_headers(): @pytest.mark.asyncio async def test_bearer_token_never_runs_the_sigv4_credential_chain(monkeypatch): - """The guardrail's AWS profile does not exist, so resolving SigV4 credentials - raises; with a bearer token configured the guardrail must still run, since - the bearer token alone signs the request.""" + """The process's default AWS profile does not exist, so resolving SigV4 + credentials raises; with a bearer token configured the guardrail must still + run, since the bearer token alone signs the request.""" monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "env-bearer-token-12345") + monkeypatch.setenv("AWS_PROFILE", "litellm-no-such-aws-profile") guardrail = BedrockGuardrail( guardrailIdentifier="test-guardrail", guardrailVersion="DRAFT", - aws_profile_name="litellm-no-such-aws-profile", ) mock_response = MagicMock() mock_response.status_code = 200 diff --git a/tests/unit/proxy/guardrails/guardrail_hooks/test_bedrock_invoke_guardrail_checks.py b/tests/unit/proxy/guardrails/guardrail_hooks/test_bedrock_invoke_guardrail_checks.py index 5169d4c9ec6..ef6d408f39b 100644 --- a/tests/unit/proxy/guardrails/guardrail_hooks/test_bedrock_invoke_guardrail_checks.py +++ b/tests/unit/proxy/guardrails/guardrail_hooks/test_bedrock_invoke_guardrail_checks.py @@ -840,14 +840,14 @@ async def test_many_blocks_scanned_at_request_level_and_can_block(): @pytest.mark.asyncio async def test_checks_bearer_token_never_runs_the_sigv4_credential_chain(monkeypatch): - """Same bearer-token rule as ApplyGuardrail: the guardrail's AWS profile does - not exist, yet the InvokeGuardrailChecks call still goes out on the bearer - token and its verdict is enforced.""" + """Same bearer-token rule as ApplyGuardrail: the process's default AWS + profile does not exist, yet the InvokeGuardrailChecks call still goes out on + the bearer token and its verdict is enforced.""" monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "env-bearer-token-12345") + monkeypatch.setenv("AWS_PROFILE", "litellm-no-such-aws-profile") g = BedrockGuardrail( checks=CONTENT_FILTER_CHECKS, content_filter_threshold=0.5, - aws_profile_name="litellm-no-such-aws-profile", ) payload = {"results": {"contentFilter": {"results": [{"category": "VIOLENCE", "severityScore": 0.8}]}}} post = AsyncMock(return_value=_mock_http_response(200, payload))