test(router): cover s3_output_bucket_name surviving the trusted credential snapshot

The field itself landed on staging via 0c5c9c79d7; these are the regression tests from PR #31435 for the retrieval-facing half.

(cherry picked from commit a9a322d63f6d4658b1f28d1622335775e94736a4)
This commit is contained in:
Kent 2026-06-26 19:03:10 +08:00 committed by mateo-berri
parent 7bea4def27
commit 9ff9f77137
2 changed files with 84 additions and 3 deletions

View file

@ -1992,17 +1992,30 @@ class TestBedrockFileContentTransformation:
litellm_params=self._litellm_params(),
)
def _trusted(self, **creds) -> dict:
def _trusted(self, **deployment_litellm_params) -> dict:
"""Build the trusted snapshot the way the proxy does: deployment
litellm_params funneled through ``CredentialLiteLLMParams`` (the strict
allowlist ``get_deployment_credentials_with_provider`` applies) before
retrieval ever sees them. Injecting a raw ``MappingProxyType`` would
bypass that filter and hide whether a bucket field actually survives
into the snapshot in production."""
from types import MappingProxyType
from litellm.types.router import CredentialLiteLLMParams
snapshot = CredentialLiteLLMParams(**deployment_litellm_params).model_dump(
exclude_none=True
)
params = self._litellm_params()
params["_litellm_internal_model_credentials"] = MappingProxyType(dict(creds))
params["_litellm_internal_model_credentials"] = MappingProxyType(snapshot)
return params
def test_retrieves_from_distinct_output_bucket(self, monkeypatch):
"""Batch outputs can land in a separate s3_output_bucket_name. Retrieval
must validate the file id against the output bucket too, not just the
input bucket, or the very outputs the feature serves are unreachable."""
input bucket, or the very outputs the feature serves are unreachable.
The snapshot is built through the production credential filter, so this
fails if s3_output_bucket_name is dropped from that allowlist."""
from litellm.llms.bedrock.files.transformation import BedrockFilesConfig
monkeypatch.delenv("AWS_S3_BUCKET_NAME", raising=False)

View file

@ -143,3 +143,71 @@ class TestRouterCredentialResolution:
assert credentials is not None
assert credentials.get("api_key") == "sk-static-key"
assert "azure_ad_token" not in credentials
class TestRouterCredentialResolutionS3OutputBucket:
"""Same strict-dump trap as azure_ad_token (#30235), for Bedrock batch
file retrieval (#26335). Bedrock batch outputs land in a per-model
``s3_output_bucket_name`` when it differs from the input bucket. The
file-content retrieval path validates a file id against the buckets in the
trusted credential snapshot, and that snapshot is built by round-tripping
the deployment's ``litellm_params`` through ``CredentialLiteLLMParams``. If
the field is undeclared it is dropped, so the output bucket never reaches
retrieval and output-bucket file ids are rejected as foreign."""
def test_credentials_preserve_s3_output_bucket_name(self):
from litellm import Router
deployment_id = "bedrock-batch-output-bucket-fixed-uuid"
router = Router(
model_list=[
{
"model_name": "bedrock-batch",
"litellm_params": {
"model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0",
"s3_bucket_name": "in-bucket",
"s3_output_bucket_name": "out-bucket",
"aws_region_name": "us-west-2",
},
"model_info": {"id": deployment_id},
}
]
)
credentials = router.get_deployment_credentials_with_provider(
model_id=deployment_id
)
assert credentials is not None
assert credentials.get("s3_output_bucket_name") == "out-bucket", (
"Router credential resolution dropped s3_output_bucket_name; "
"Bedrock batch file-content retrieval will reject output-bucket "
"file ids as foreign for model-routed deployments (#26335)"
)
assert credentials.get("s3_bucket_name") == "in-bucket"
def test_credentials_without_output_bucket_unaffected(self):
"""A deployment that configures only the input bucket keeps it and does
not gain a phantom output bucket in the resolved credentials."""
from litellm import Router
deployment_id = "bedrock-batch-input-only-fixed-uuid"
router = Router(
model_list=[
{
"model_name": "bedrock-batch-input-only",
"litellm_params": {
"model": "bedrock/anthropic.claude-3-sonnet-20240229-v1:0",
"s3_bucket_name": "in-bucket",
"aws_region_name": "us-west-2",
},
"model_info": {"id": deployment_id},
}
]
)
credentials = router.get_deployment_credentials_with_provider(
model_id=deployment_id
)
assert credentials is not None
assert credentials.get("s3_bucket_name") == "in-bucket"
assert "s3_output_bucket_name" not in credentials