fix(proxy): keep long first-write config values without PyNaCl instead of storing null

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yucheng 2026-10-08 01:51:51 +00:00
parent a7c350faee
commit a6a968b9fb
3 changed files with 15 additions and 3 deletions

View file

@ -269,6 +269,15 @@ def legacy_unreadable(value: object) -> bool:
return needs_legacy_reader(value) and not legacy_encryption_available()
def decrypt_for_rewrite(value: str, key: str) -> str | None:
"""Decrypt a value a config writer submitted for storage: ciphertext read back from the store or a first-write
plaintext. Without PyNaCl an unprefixed value cannot be told apart from plaintext, so it is kept as submitted
instead of being dropped."""
if legacy_unreadable(value):
return value
return decrypt_value_helper(value=value, key=key, return_original_value=True)
def require_legacy_reader_for(values: Iterable[object], purpose: str) -> None:
"""Refuse a decrypt-then-rewrite pass when PyNaCl is missing and one of the values is unprefixed: it would
read as unreadable and be dropped, double wrapped or miscounted as plaintext. Versioned gcm and non string

View file

@ -419,6 +419,7 @@ 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.discoverable_model_filter import discoverable_rows, undiscoverable_model_names
from litellm.proxy.common_utils.encrypt_decrypt_utils import (
decrypt_for_rewrite,
decrypt_value_helper,
encrypt_value_helper,
)
@ -7794,7 +7795,7 @@ class ProxyConfig:
_decrypt_and_set_db_env_variables): this is a write path, and
loading values into os.environ is the read path's responsibility.
"""
decrypted_env_vars: Final = self._decrypt_db_variables(environment_variables)
decrypted_env_vars: Final = {k: decrypt_for_rewrite(value=v, key=k) for k, v in environment_variables.items()}
return self._encrypt_env_variables(
environment_variables=decrypted_env_vars,
new_encryption_key=new_encryption_key,

View file

@ -3755,11 +3755,13 @@ def test_ProxyConfig__encrypt_env_variables_for_db_without_pynacl_encrypts_new_p
monkeypatch.setitem(sys.modules, "nacl.secret", None)
pc = ProxyConfig()
saved = pc._encrypt_env_variables_for_db({"A": v3, "B": "first-write-plaintext"})
assert saved["B"].startswith("v3:gcm:") and saved["B"] != "first-write-plaintext"
long_plaintext = "A" * 56
saved = pc._encrypt_env_variables_for_db({"A": v3, "B": "first-write-plaintext", "C": long_plaintext})
assert all(v.startswith("v3:gcm:") for v in saved.values())
assert {k: decrypt_value_helper(v, key=k) for k, v in saved.items()} == {
"A": "already-migrated",
"B": "first-write-plaintext",
"C": long_plaintext,
}