mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
fix(bedrock): respect s3_region_name for batch file uploads (GovCloud fix)
This commit is contained in:
parent
2b61f2a41b
commit
913ccf4983
2 changed files with 118 additions and 1 deletions
|
|
@ -173,7 +173,12 @@ class BedrockFilesConfig(BaseAWSLLM, BaseFilesConfig):
|
|||
"S3 bucket_name is required. Set 's3_bucket_name' in litellm_params or AWS_S3_BUCKET_NAME env var"
|
||||
)
|
||||
|
||||
aws_region_name = self._get_aws_region_name(optional_params, model)
|
||||
s3_region_name = litellm_params.get("s3_region_name") or optional_params.get(
|
||||
"s3_region_name"
|
||||
)
|
||||
aws_region_name = s3_region_name or self._get_aws_region_name(
|
||||
optional_params, model
|
||||
)
|
||||
|
||||
file_data = data.get("file")
|
||||
purpose = data.get("purpose")
|
||||
|
|
@ -398,6 +403,14 @@ class BedrockFilesConfig(BaseAWSLLM, BaseFilesConfig):
|
|||
data=create_file_data,
|
||||
)
|
||||
|
||||
# If s3_region_name is set and aws_region_name is not, propagate it so
|
||||
# SigV4 signing uses the correct region (e.g. GovCloud us-gov-west-1).
|
||||
s3_region_name = litellm_params.get("s3_region_name") or optional_params.get(
|
||||
"s3_region_name"
|
||||
)
|
||||
if s3_region_name and not optional_params.get("aws_region_name"):
|
||||
optional_params = {**optional_params, "aws_region_name": s3_region_name}
|
||||
|
||||
# Sign the request and return a pre-signed request object
|
||||
signed_headers, signed_body = self._sign_s3_request(
|
||||
content=file_content,
|
||||
|
|
|
|||
|
|
@ -272,6 +272,110 @@ class TestBedrockFilesTransformation:
|
|||
assert "messages" in model_input
|
||||
assert "max_tokens" in model_input
|
||||
|
||||
def test_get_complete_file_url_respects_s3_region_name(self):
|
||||
"""
|
||||
s3_region_name in litellm_params must be used when building the S3 URL.
|
||||
Previously the code fell back to us-west-2 even when s3_region_name was set,
|
||||
breaking GovCloud (us-gov-west-1) deployments.
|
||||
"""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from litellm.llms.bedrock.files.transformation import BedrockFilesConfig
|
||||
|
||||
config = BedrockFilesConfig()
|
||||
|
||||
jsonl_content = json.dumps(
|
||||
{
|
||||
"custom_id": "req-1",
|
||||
"method": "POST",
|
||||
"url": "/v1/chat/completions",
|
||||
"body": {
|
||||
"model": "bedrock/amazon.nova-pro-v1:0",
|
||||
"messages": [{"role": "user", "content": "Hello"}],
|
||||
"max_tokens": 10,
|
||||
},
|
||||
}
|
||||
).encode()
|
||||
|
||||
create_file_data = {
|
||||
"file": ("batch.jsonl", jsonl_content, "application/jsonl"),
|
||||
"purpose": "batch",
|
||||
}
|
||||
|
||||
litellm_params = {
|
||||
"s3_bucket_name": "litellm-batch-352026",
|
||||
"s3_region_name": "us-gov-west-1",
|
||||
}
|
||||
|
||||
url = config.get_complete_file_url(
|
||||
api_base=None,
|
||||
api_key=None,
|
||||
model="amazon.nova-pro-v1:0",
|
||||
optional_params={},
|
||||
litellm_params=litellm_params,
|
||||
data=create_file_data,
|
||||
)
|
||||
|
||||
assert "us-gov-west-1" in url, (
|
||||
f"Expected us-gov-west-1 in URL but got: {url}"
|
||||
)
|
||||
assert "us-west-2" not in url, (
|
||||
f"us-west-2 must not appear when s3_region_name is set, got: {url}"
|
||||
)
|
||||
assert "litellm-batch-352026" in url
|
||||
|
||||
def test_transform_create_file_request_injects_s3_region_for_signing(self):
|
||||
"""
|
||||
When s3_region_name is provided, transform_create_file_request must pass
|
||||
that region to _sign_s3_request so SigV4 signatures use the correct region.
|
||||
"""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from litellm.llms.bedrock.files.transformation import BedrockFilesConfig
|
||||
|
||||
config = BedrockFilesConfig()
|
||||
|
||||
jsonl_content = json.dumps(
|
||||
{
|
||||
"custom_id": "req-1",
|
||||
"method": "POST",
|
||||
"url": "/v1/chat/completions",
|
||||
"body": {
|
||||
"model": "bedrock/amazon.nova-pro-v1:0",
|
||||
"messages": [{"role": "user", "content": "Hello"}],
|
||||
"max_tokens": 10,
|
||||
},
|
||||
}
|
||||
).encode()
|
||||
|
||||
create_file_data = {
|
||||
"file": ("batch.jsonl", jsonl_content, "application/jsonl"),
|
||||
"purpose": "batch",
|
||||
}
|
||||
|
||||
litellm_params = {
|
||||
"s3_bucket_name": "litellm-batch-352026",
|
||||
"s3_region_name": "us-gov-west-1",
|
||||
}
|
||||
|
||||
captured_optional_params: dict = {}
|
||||
|
||||
def fake_sign(content, api_base, optional_params):
|
||||
captured_optional_params.update(optional_params)
|
||||
return {"Authorization": "fake"}, content
|
||||
|
||||
with patch.object(config, "_sign_s3_request", side_effect=fake_sign):
|
||||
config.transform_create_file_request(
|
||||
model="amazon.nova-pro-v1:0",
|
||||
create_file_data=create_file_data,
|
||||
optional_params={},
|
||||
litellm_params=litellm_params,
|
||||
)
|
||||
|
||||
assert captured_optional_params.get("aws_region_name") == "us-gov-west-1", (
|
||||
"s3_region_name must be forwarded as aws_region_name for SigV4 signing"
|
||||
)
|
||||
|
||||
def test_openai_passthrough_still_works(self):
|
||||
"""
|
||||
Regression test: ensure OpenAI-compatible models (e.g. gpt-oss)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue