From eeb53190d045fb8a6f6be2750313d0f01fee13d5 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 17:06:38 +0000 Subject: [PATCH] fix(bedrock): grant bedrock-mantle:CreateInference in OIDC session policy --- litellm/llms/bedrock/base_aws_llm.py | 9 ++++ .../test_web_identity_session_policy.py | 52 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/litellm/llms/bedrock/base_aws_llm.py b/litellm/llms/bedrock/base_aws_llm.py index f449851b76f..98ddd037e8c 100644 --- a/litellm/llms/bedrock/base_aws_llm.py +++ b/litellm/llms/bedrock/base_aws_llm.py @@ -877,6 +877,15 @@ class BaseAWSLLM: "Resource": "*", "Condition": {"Bool": {"aws:SecureTransport": "true"}}, }, + { + "Sid": "MantleLiteLLM", + "Effect": "Allow", + "Action": [ + "bedrock-mantle:CreateInference", + ], + "Resource": "*", + "Condition": {"Bool": {"aws:SecureTransport": "true"}}, + }, ], } assume_role_params = { diff --git a/tests/test_litellm/llms/bedrock/test_web_identity_session_policy.py b/tests/test_litellm/llms/bedrock/test_web_identity_session_policy.py index 7e9c8a273ae..b5be5aff726 100644 --- a/tests/test_litellm/llms/bedrock/test_web_identity_session_policy.py +++ b/tests/test_litellm/llms/bedrock/test_web_identity_session_policy.py @@ -158,6 +158,58 @@ class TestClaudePlatformActionsCovered: ) +class TestMantleActionsCovered: + """#33094: the bedrock-mantle endpoint (``bedrock_mantle/`` + route) is served under its own ``bedrock-mantle:*`` IAM action + namespace, distinct from both ``bedrock:*`` and + ``aws-external-anthropic:*``. Without a matching statement every + mantle request 403s on OIDC auth with:: + + is not authorized to perform: bedrock-mantle:CreateInference + """ + + def test_mantle_create_inference_present(self): + policy = _captured_policy() + all_actions: set = set() + for stmt in policy["Statement"]: + stmt_actions = stmt.get("Action") + if isinstance(stmt_actions, str): + all_actions.add(stmt_actions) + elif isinstance(stmt_actions, list): + all_actions.update(stmt_actions) + assert "bedrock-mantle:CreateInference" in all_actions, ( + "bedrock-mantle:CreateInference missing from session policy — " + "bedrock_mantle/* requests will 403 on OIDC auth" + ) + + def test_mantle_statement_allows(self): + policy = _captured_policy() + stmt = _statement_by_sid(policy, "MantleLiteLLM") + assert stmt["Effect"] == "Allow" + assert stmt["Resource"] == "*" + + def test_mantle_statement_carries_secure_transport_condition(self): + policy = _captured_policy() + stmt = _statement_by_sid(policy, "MantleLiteLLM") + cond = stmt.get("Condition") or {} + assert cond.get("Bool", {}).get("aws:SecureTransport") == "true", ( + "MantleLiteLLM must require aws:SecureTransport=true " + "to keep parity with the bedrock statement" + ) + + def test_mantle_statement_not_wildcard(self): + """Keep the ceiling tight — don't grant bedrock-mantle:* .""" + policy = _captured_policy() + stmt = _statement_by_sid(policy, "MantleLiteLLM") + actions = stmt["Action"] + if isinstance(actions, str): + actions = [actions] + assert "bedrock-mantle:*" not in actions, ( + "session policy must not grant bedrock-mantle:* — " + "the ceiling should match the documented action set" + ) + + def _make_jwt(payload: dict) -> str: def _segment(data: dict) -> str: return base64.urlsafe_b64encode(json.dumps(data).encode()).rstrip(b"=").decode()