From 197fd1e799d2210c264ae0d900d50e3364fbe25c Mon Sep 17 00:00:00 2001 From: derhornspieler <15236687+derhornspieler@users.noreply.github.com> Date: Tue, 25 Aug 2026 10:05:26 -0400 Subject: [PATCH] fix: build the reflection candidates in one shot, and resync the generated types Assigning to a Final inside the loop that walked the rendered and percent-decoded candidates was a type error, and it is the reason lint went red. The candidates are built in one shot now, which is the shape the rest of this module already uses. The federation disable sentinel also needed its two registrations following through: the key-set test pins the registered set deliberately so a new key cannot be added without being exercised, and declaring the field on the params model changed the proxy's OpenAPI spec, so the dashboard's generated types are regenerated to match. --- litellm/llms/base_llm/auth/token_exchange.py | 16 ++++++++-------- .../test_get_litellm_params.py | 2 ++ ui/litellm-dashboard/src/lib/http/schema.d.ts | 4 ++++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/litellm/llms/base_llm/auth/token_exchange.py b/litellm/llms/base_llm/auth/token_exchange.py index 6243a97a51a..a6567455490 100644 --- a/litellm/llms/base_llm/auth/token_exchange.py +++ b/litellm/llms/base_llm/auth/token_exchange.py @@ -170,14 +170,14 @@ def _shares_a_credential_run(rendered: str, compacted_secret: str) -> bool: """``unquote`` covers a credential sent form-encoded, without every caller enumerating that shape for itself: percent-escaping is reversible and applies to any field, query string included.""" - for candidate in (rendered, unquote(rendered)): - compacted: Final = _CREDENTIAL_CHARS.sub("", candidate) - if any( - compacted[start : start + _REFLECTION_MIN_RUN] in compacted_secret - for start in range(len(compacted) - _REFLECTION_MIN_RUN + 1) - ): - return True - return False + compacted_candidates: Final = tuple( + _CREDENTIAL_CHARS.sub("", candidate) for candidate in (rendered, unquote(rendered)) + ) + return any( + compacted[start : start + _REFLECTION_MIN_RUN] in compacted_secret + for compacted in compacted_candidates + for start in range(len(compacted) - _REFLECTION_MIN_RUN + 1) + ) def _redact_body_text(body_text: str) -> str: diff --git a/tests/test_litellm/litellm_core_utils/test_get_litellm_params.py b/tests/test_litellm/litellm_core_utils/test_get_litellm_params.py index 3ccb2632fb4..d84bb54eb1a 100644 --- a/tests/test_litellm/litellm_core_utils/test_get_litellm_params.py +++ b/tests/test_litellm/litellm_core_utils/test_get_litellm_params.py @@ -300,6 +300,8 @@ class TestAnthropicWifIdentitySourceKeys: "anthropic_keycloak_auth_method": "client_secret_basic", "anthropic_keycloak_client_secret_ref": "oidc/env/KC_SECRET", "anthropic_keycloak_scope": "anthropic-wif", + # Server-set when a client redirects api_base; carried here so it is not dropped in transit + "anthropic_disable_workload_identity_federation": True, } def test_new_keys_are_exactly_the_non_legacy_registered_set(self): diff --git a/ui/litellm-dashboard/src/lib/http/schema.d.ts b/ui/litellm-dashboard/src/lib/http/schema.d.ts index 678c3e7ae99..aee0c26bd17 100644 --- a/ui/litellm-dashboard/src/lib/http/schema.d.ts +++ b/ui/litellm-dashboard/src/lib/http/schema.d.ts @@ -27463,6 +27463,8 @@ export interface components { allow_client_keepalive_override: boolean | null; /** Annotation Cost Per Page */ annotation_cost_per_page?: number | null; + /** Anthropic Disable Workload Identity Federation */ + anthropic_disable_workload_identity_federation?: boolean | null; /** Anthropic Federation Rule Id */ anthropic_federation_rule_id?: string | null; /** Anthropic Identity Source */ @@ -36781,6 +36783,8 @@ export interface components { allow_client_keepalive_override: boolean | null; /** Annotation Cost Per Page */ annotation_cost_per_page?: number | null; + /** Anthropic Disable Workload Identity Federation */ + anthropic_disable_workload_identity_federation?: boolean | null; /** Anthropic Federation Rule Id */ anthropic_federation_rule_id?: string | null; /** Anthropic Identity Source */