mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-15 09:12:18 +00:00
Merge 33196c985b into 570f41daad
This commit is contained in:
commit
d18b86d2f4
16 changed files with 196 additions and 41 deletions
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ###
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
[
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue