From b8e367db1d2655178c845f60d32cfc65ed52ce36 Mon Sep 17 00:00:00 2001 From: yangdx Date: Thu, 26 Mar 2026 03:13:49 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(proxy=5Fserver):=20remove=20?= =?UTF-8?q?redundant=20decryption=20of=20already-decrypted=20env=20variabl?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - remove duplicate decrypt_value_helper calls for slack and email env vars in get_config - values from environment_variables are already decrypted, no need to decrypt again - add test to verify decrypt_value_helper is not called for slack/email config values --- litellm/proxy/proxy_server.py | 10 +--- tests/proxy_unit_tests/test_proxy_server.py | 58 +++++++++++++++++++++ 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 7d3d2ceb533..923f41fa30c 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -12624,11 +12624,7 @@ async def get_config(): # noqa: PLR0915 _value = os.getenv("SLACK_WEBHOOK_URL", None) _slack_env_vars[_var] = _value else: - # decode + decrypt the value - _decrypted_value = decrypt_value_helper( - value=env_variable, key=_var - ) - _slack_env_vars[_var] = _decrypted_value + _slack_env_vars[_var] = env_variable _alerting_types = proxy_logging_obj.slack_alerting_instance.alert_types _all_alert_types = ( @@ -12662,9 +12658,7 @@ async def get_config(): # noqa: PLR0915 if env_variable is None: _email_env_vars[_var] = None else: - # decode + decrypt the value - _decrypted_value = decrypt_value_helper(value=env_variable, key=_var) - _email_env_vars[_var] = _decrypted_value + _email_env_vars[_var] = env_variable alerting_data.append( { diff --git a/tests/proxy_unit_tests/test_proxy_server.py b/tests/proxy_unit_tests/test_proxy_server.py index 61a2f3055af..36e1b30ce3d 100644 --- a/tests/proxy_unit_tests/test_proxy_server.py +++ b/tests/proxy_unit_tests/test_proxy_server.py @@ -2720,6 +2720,64 @@ async def test_get_config_callbacks_environment_variables(client_no_auth): assert otel_vars["OTEL_HEADERS"] == "key=value" +@pytest.mark.asyncio +async def test_get_config_callbacks_email_and_slack_values_are_not_decrypted_again( + client_no_auth, +): + """ + Test that /get/config/callbacks returns already-decrypted email/slack values as-is. + """ + mock_config_data = { + "litellm_settings": {}, + "environment_variables": { + "SLACK_WEBHOOK_URL": "https://hooks.slack.com/services/test/webhook", + "SMTP_HOST": "10.16.68.20", + "SMTP_PORT": "587", + "SMTP_USERNAME": "smtp-user", + "SMTP_PASSWORD": "smtp-password", + "SMTP_SENDER_EMAIL": "alerts@example.com", + "TEST_EMAIL_ADDRESS": "ops@example.com", + "EMAIL_LOGO_URL": "https://example.com/logo.png", + "EMAIL_SUPPORT_CONTACT": "support@example.com", + }, + "general_settings": {"alerting": ["slack"]}, + } + + proxy_config = getattr(litellm.proxy.proxy_server, "proxy_config") + + with patch.object( + proxy_config, "get_config", new=AsyncMock(return_value=mock_config_data) + ), patch( + "litellm.proxy.proxy_server.decrypt_value_helper", + side_effect=AssertionError("decrypt_value_helper should not be called"), + ) as decrypt_mock: + response = client_no_auth.get("/get/config/callbacks") + + assert response.status_code == 200 + result = response.json() + alerts = result["alerts"] + + slack_alert = next((alert for alert in alerts if alert["name"] == "slack"), None) + assert slack_alert is not None + assert slack_alert["variables"] == { + "SLACK_WEBHOOK_URL": "https://hooks.slack.com/services/test/webhook" + } + + email_alert = next((alert for alert in alerts if alert["name"] == "email"), None) + assert email_alert is not None + assert email_alert["variables"] == { + "SMTP_HOST": "10.16.68.20", + "SMTP_PORT": "587", + "SMTP_USERNAME": "smtp-user", + "SMTP_PASSWORD": "smtp-password", + "SMTP_SENDER_EMAIL": "alerts@example.com", + "TEST_EMAIL_ADDRESS": "ops@example.com", + "EMAIL_LOGO_URL": "https://example.com/logo.png", + "EMAIL_SUPPORT_CONTACT": "support@example.com", + } + decrypt_mock.assert_not_called() + + @pytest.mark.asyncio async def test_update_config_success_callback_normalization(): """