fix(bedrock/base_aws_llm): remove lowercase authorization duplicate after SigV4 override

After the header normalization, the merge loop writes lowercase
'authorization' into request_headers_dict and the Authorization-override
guard then writes uppercase 'Authorization' — both keys survive as
separate entries in the plain dict.

Fix by popping the lowercase key before writing the canonical uppercase
one so HTTP clients only see a single Authorization header.

Add test_sign_request_caller_authorization_overrides_sigv4 to cover
the override branch (fixes Codecov missing-line report) and assert no
duplicate key survives in the returned headers dict.
This commit is contained in:
Connor Graham 2026-05-20 11:13:02 -04:00
parent 1c9af0428a
commit 53832e3ed6
2 changed files with 46 additions and 0 deletions

View file

@ -1524,6 +1524,7 @@ class BaseAWSLLM:
if header_value is not None:
request_headers_dict[header_name] = header_value
if "authorization" in headers: # prevent sigv4 from overwriting the auth header
request_headers_dict.pop("authorization", None)
request_headers_dict["Authorization"] = headers["authorization"]
return request_headers_dict, request.body

View file

@ -539,6 +539,51 @@ def test_sign_request_with_sigv4():
assert result_body == mock_request.body
def test_sign_request_caller_authorization_overrides_sigv4():
"""
When a caller pre-supplies an Authorization header, _sign_request must not
let SigV4's Authorization win. The returned dict should contain exactly one
Authorization key (uppercase, canonical) with the caller's value — no
duplicate lowercase 'authorization' entry alongside it.
"""
llm = BaseAWSLLM()
mock_credentials = Credentials("test_key", "test_secret", "test_token")
mock_sigv4 = MagicMock()
mock_request = MagicMock()
mock_request.headers = {
"Authorization": "AWS4-HMAC-SHA256 Credential=sigv4-generated",
"Content-Type": "application/json",
}
mock_request.body = b'{"prompt": "test"}'
caller_auth = "Bearer caller-supplied-token"
with (
patch("botocore.auth.SigV4Auth", return_value=mock_sigv4),
patch("botocore.awsrequest.AWSRequest", return_value=mock_request),
patch.object(llm, "get_credentials", return_value=mock_credentials),
patch.object(llm, "_get_aws_region_name", return_value="us-west-2"),
):
result_headers, _ = llm._sign_request(
service_name="aws-external-anthropic",
headers={"Authorization": caller_auth, "content-type": "application/json"},
optional_params={"aws_region_name": "us-west-2"},
request_data={"prompt": "test"},
api_base="https://aws-external-anthropic.us-west-2.api.aws/v1/messages",
)
# Caller's value must win over SigV4's generated one
assert result_headers["Authorization"] == caller_auth
# Must not have a separate lowercase 'authorization' duplicate
auth_keys = [k for k in result_headers if k.lower() == "authorization"]
assert len(auth_keys) == 1, (
f"Expected exactly one Authorization key, got {auth_keys}. "
"Duplicate keys can cause unpredictable behaviour in HTTP clients."
)
def test_sign_request_with_api_key_bearer_token():
"""
Test that _sign_request uses the api_key parameter as a bearer token when provided