diff --git a/litellm/main.py b/litellm/main.py index 19bfd356d57..3a768477c42 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -8842,13 +8842,9 @@ def speech( request_azure_ad_token: Final = OPTIONAL_STR.validate_python( optional_params.get("extra_body", {}).pop("azure_ad_token", None) ) - azure_ad_token: Final[str | None] = request_azure_ad_token or get_secret("AZURE_AD_TOKEN") request_kwargs: Final = _REQUEST_KWARGS_ADAPTER.validate_python(kwargs) - request_extra_body: Final = _REQUEST_KWARGS_ADAPTER.validate_python(request_kwargs.get("extra_body") or {}) - uses_entra_id: Final = ( - bool(azure_ad_token) - or bool(request_extra_body.get("azure_ad_token")) - or uses_azure_entra_id_auth(request_kwargs, os.environ, litellm.enable_azure_ad_token_refresh is True) + uses_entra_id: Final = request_azure_ad_token is not None or uses_azure_entra_id_auth( + request_kwargs, os.environ, litellm.enable_azure_ad_token_refresh is True ) api_key = ( @@ -8860,6 +8856,8 @@ def speech( or get_secret("AZURE_API_KEY") ) + azure_ad_token: Final[str | None] = request_azure_ad_token or get_secret("AZURE_AD_TOKEN") + if extra_headers: optional_params["extra_headers"] = extra_headers diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index 578be4f6b6d..bc7e4888313 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -5605,16 +5605,14 @@ def test_speech_azure_ai_keeps_the_deployments_entra_token_over_the_provider_sco ({"AZURE_TENANT_ID": "t", "AZURE_CLIENT_ID": "c", "AZURE_CLIENT_SECRET": "s"}, {}, False), ({"AZURE_CLIENT_SECRET": "s"}, {"tenant_id": "t", "client_id": "c"}, False), ({}, {}, True), - ({"AZURE_AD_TOKEN": "env-entra-token"}, {}, False), - ({}, {"extra_body": {"azure_ad_token": "request-entra-token"}}, False), ], - ids=["service-principal-in-env", "ids-in-config-secret-in-env", "token-refresh", "ad-token-in-env", "ad-token-in-extra-body"], + ids=["service-principal-in-env", "ids-in-config-secret-in-env", "token-refresh"], ) def test_speech_azure_ai_entra_id_setups_keep_the_key_chain_they_had_before_the_provider_key( respx_mock: respx.MockRouter, monkeypatch: pytest.MonkeyPatch, entra_env: dict[str, str], - deployment_params: Mapping[str, object], + deployment_params: dict[str, str], token_refresh: bool, ): _clear_global_tts_keys(monkeypatch) @@ -5625,7 +5623,6 @@ def test_speech_azure_ai_entra_id_setups_keep_the_key_chain_they_had_before_the_ "AZURE_TENANT_ID": None, "AZURE_CLIENT_ID": None, "AZURE_CLIENT_SECRET": None, - "AZURE_AD_TOKEN": None, "AZURE_OPENAI_API_KEY": None, "AZURE_AI_API_KEY": "key-for-another-resource", "AZURE_API_KEY": "generic-azure-key", @@ -5648,6 +5645,49 @@ def test_speech_azure_ai_entra_id_setups_keep_the_key_chain_they_had_before_the_ assert route.calls.last.request.headers["authorization"] == "Bearer generic-azure-key" +@pytest.mark.parametrize( + ("unsent_env", "request_params"), + [ + ({"AZURE_AD_TOKEN": "token-tts-never-sends"}, {}), + ({}, {"extra_body": {"azure_ad_token": "token-tts-never-sends"}}), + ({}, {"extra_body": ["not", "an", "object"]}), + ], + ids=["ad-token-in-env", "ad-token-in-extra-body", "non-object-extra-body"], +) +def test_speech_azure_ai_sends_the_provider_scoped_key_next_to_an_ad_token_tts_never_sends( + respx_mock: respx.MockRouter, + monkeypatch: pytest.MonkeyPatch, + unsent_env: dict[str, str], + request_params: Mapping[str, object], +): + _clear_global_tts_keys(monkeypatch) + _set_or_clear_env( + monkeypatch, + { + "AZURE_AD_TOKEN": None, + "AZURE_OPENAI_API_KEY": None, + "AZURE_API_KEY": None, + "AZURE_AI_API_KEY": "azure-ai-scoped-key", + **unsent_env, + }, + ) + route: Final = respx_mock.post( + url__regex=r"https://foundry\.internal/openai/deployments/tts-1/audio/speech\?api-version=.+" + ).mock(return_value=httpx.Response(200, content=TTS_AUDIO, headers={"content-type": "audio/mpeg"})) + + response: Final = litellm.speech( + model="azure_ai/tts-1", + input="which key goes out", + voice="alloy", + api_base="https://foundry.internal", + api_version="2024-05-01-preview", + **request_params, + ) + + assert response.content == TTS_AUDIO + assert route.calls.last.request.headers["api-key"] == "azure-ai-scoped-key" + + def test_speech_docker_model_runner_placeholder_does_not_beat_a_real_key( respx_mock: respx.MockRouter, monkeypatch: pytest.MonkeyPatch ):