mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
fix(proxy): keep an empty credential value empty after decryption
This commit is contained in:
parent
56cf0cd223
commit
1caa2fa9c1
4 changed files with 54 additions and 5 deletions
|
|
@ -23,13 +23,16 @@ from litellm.types.router import (
|
|||
from litellm.types.utils import CredentialItem
|
||||
|
||||
|
||||
def decrypted_or_stored(key: str, value: str) -> str:
|
||||
"""The stored value decrypted, or as stored when it was never encrypted (a config.yaml value)."""
|
||||
decrypted: Final = decrypt_value_helper(value=value, key=key)
|
||||
return value if decrypted is None else decrypted
|
||||
|
||||
|
||||
def _decrypted(db_credential: CredentialItem) -> CredentialItem:
|
||||
"""The stored credential with every value decrypted, leaving already-plaintext values alone."""
|
||||
decrypted_values: Final = MappingProxyType(
|
||||
{
|
||||
key: decrypt_value_helper(value=value, key=key) or value
|
||||
for key, value in db_credential.credential_values.items()
|
||||
}
|
||||
{key: decrypted_or_stored(key, value) for key, value in db_credential.credential_values.items()}
|
||||
)
|
||||
return CredentialItem(
|
||||
credential_name=db_credential.credential_name,
|
||||
|
|
|
|||
|
|
@ -335,6 +335,7 @@ from litellm.proxy.common_utils.auth_cache_invalidation_pubsub import (
|
|||
)
|
||||
from litellm.proxy.common_utils.callback_utils import initialize_callbacks_on_proxy
|
||||
from litellm.proxy.common_utils.config_sync_pubsub import ConfigSyncSubscriber
|
||||
from litellm.proxy.common_utils.credential_hydration import decrypted_or_stored
|
||||
from litellm.proxy.common_utils.debug_utils import init_verbose_loggers
|
||||
from litellm.proxy.common_utils.debug_utils import router as debugging_endpoints_router
|
||||
from litellm.proxy.common_utils.encrypt_decrypt_utils import (
|
||||
|
|
@ -7933,7 +7934,7 @@ class ProxyConfig:
|
|||
|
||||
decrypted_credential_values: Final = {}
|
||||
for k, v in credential_object.credential_values.items():
|
||||
decrypted_credential_values[k] = decrypt_value_helper(value=v, key=k) or v
|
||||
decrypted_credential_values[k] = decrypted_or_stored(k, v)
|
||||
|
||||
credential_object.credential_values = decrypted_credential_values
|
||||
return credential_object
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
import litellm
|
||||
from litellm.proxy.common_utils.credential_hydration import hydrate_named_credential_authoritative
|
||||
from litellm.proxy.common_utils.encrypt_decrypt_utils import encrypt_value_helper
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_authoritative_hydrate_returns_an_encrypted_empty_value_as_empty(monkeypatch):
|
||||
monkeypatch.setenv("LITELLM_SALT_KEY", "sk-hydration-test-salt")
|
||||
row = {
|
||||
"credential_name": "openai-wif",
|
||||
"credential_values": {
|
||||
"api_base": encrypt_value_helper(""),
|
||||
"openai_service_account_id": encrypt_value_helper("user-1"),
|
||||
},
|
||||
"credential_info": {"custom_llm_provider": "openai"},
|
||||
}
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_credentialstable.find_unique = AsyncMock(return_value=row)
|
||||
|
||||
with patch.object(litellm, "credential_list", []): # test-quality-ok: the row under test must win over memory
|
||||
resolved = await hydrate_named_credential_authoritative("openai-wif", prisma)
|
||||
|
||||
assert resolved is not None
|
||||
assert resolved.credential_values == {"api_base": "", "openai_service_account_id": "user-1"}
|
||||
|
|
@ -2345,6 +2345,23 @@ def test_ProxyConfig__add_deployment_resolves_env_refs_on_arbitrary_field(monkey
|
|||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_ProxyConfig_decrypt_credentials_returns_an_encrypted_empty_value_as_empty(monkeypatch):
|
||||
from litellm.proxy.common_utils.encrypt_decrypt_utils import encrypt_value_helper
|
||||
|
||||
monkeypatch.setenv("LITELLM_SALT_KEY", "sk-decrypt-credentials-test-salt")
|
||||
decrypted = ProxyConfig().decrypt_credentials(
|
||||
{
|
||||
"credential_name": "openai-wif",
|
||||
"credential_values": {
|
||||
"api_base": encrypt_value_helper(""),
|
||||
"openai_service_account_id": encrypt_value_helper("user-1"),
|
||||
},
|
||||
"credential_info": {"custom_llm_provider": "openai"},
|
||||
}
|
||||
)
|
||||
assert decrypted.credential_values == {"api_base": "", "openai_service_account_id": "user-1"}
|
||||
|
||||
|
||||
def test_ProxyConfig_decrypt_model_list_from_db_returns_decrypted(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"litellm.proxy.proxy_server.decrypt_value_helper",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue