✨ feat(proxy): decrypt env vars in get_config for both DB and YAML modes

- call decrypt_value_helper with return_original_value=True for slack and email env vars
- supports DB mode (already plaintext) and YAML mode (still encrypted) gracefully
- update test to use fake_decrypt stub and assert correct decrypt call count
This commit is contained in:
yangdx 2026-03-26 10:55:26 +08:00
parent 9ef938ad75
commit b8adffc932
2 changed files with 26 additions and 3 deletions

View file

@ -12624,7 +12624,11 @@ async def get_config(): # noqa: PLR0915
_value = os.getenv("SLACK_WEBHOOK_URL", None)
_slack_env_vars[_var] = _value
else:
_slack_env_vars[_var] = env_variable
_slack_env_vars[_var] = decrypt_value_helper(
value=env_variable,
key=_var,
return_original_value=True,
)
_alerting_types = proxy_logging_obj.slack_alerting_instance.alert_types
_all_alert_types = (
@ -12658,7 +12662,16 @@ async def get_config(): # noqa: PLR0915
if env_variable is None:
_email_env_vars[_var] = None
else:
_email_env_vars[_var] = env_variable
# Use return_original_value=True so this works for both:
# - DB mode: values already decrypted by _update_config_from_db → decryption
# fails gracefully and returns the original plaintext value
# - YAML mode: values still encrypted in config file → decrypted here
_decrypted_value = decrypt_value_helper(
value=env_variable,
key=_var,
return_original_value=True,
)
_email_env_vars[_var] = _decrypted_value
alerting_data.append(
{

View file

@ -2726,6 +2726,10 @@ async def test_get_config_callbacks_email_and_slack_values_are_not_decrypted_aga
):
"""
Test that /get/config/callbacks returns already-decrypted email/slack values as-is.
decrypt_value_helper is called with return_original_value=True, so for already-plaintext
values (DB mode: decrypted by _update_config_from_db) it returns the original value
unchanged. For encrypted values (YAML mode) it properly decrypts them.
"""
mock_config_data = {
"litellm_settings": {},
@ -2745,10 +2749,15 @@ async def test_get_config_callbacks_email_and_slack_values_are_not_decrypted_aga
proxy_config = getattr(litellm.proxy.proxy_server, "proxy_config")
# Simulate return_original_value=True behaviour: return the value as-is (already plaintext)
def fake_decrypt(value, key, return_original_value=False, **kwargs):
return value
with patch.object(
proxy_config, "get_config", new=AsyncMock(return_value=mock_config_data)
), patch(
"litellm.proxy.proxy_server.decrypt_value_helper",
side_effect=fake_decrypt,
) as decrypt_mock:
response = client_no_auth.get("/get/config/callbacks")
@ -2774,7 +2783,8 @@ async def test_get_config_callbacks_email_and_slack_values_are_not_decrypted_aga
"EMAIL_LOGO_URL": "https://example.com/logo.png",
"EMAIL_SUPPORT_CONTACT": "support@example.com",
}
decrypt_mock.assert_not_called()
# decrypt_value_helper is called once per SMTP var + once for SLACK_WEBHOOK_URL
assert decrypt_mock.call_count == len(mock_config_data["environment_variables"])
@pytest.mark.asyncio