fix(proxy): skip plaintext complexity_router_config in the encryption scanner

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yucheng 2026-10-08 02:41:55 +00:00
parent 45d0264cae
commit 47af50f3de
2 changed files with 43 additions and 0 deletions

View file

@ -476,6 +476,7 @@ _COVERED_TABLE_SPECS: Final = [
("sso_identity_assertion", "litellm_ssoidentityassertion", (), ("assertion_b64",)),
]
_MCP_CREDENTIAL_TABLES: Final = frozenset({"litellm_mcpservertable", "litellm_mcpserveroauthclient"})
_PLAINTEXT_LITELLM_PARAMS: Final = frozenset({"complexity_router_config"})
def _iter_encrypted_strings(obj: object):
@ -518,6 +519,8 @@ def _mcp_encrypted_leaves(col: str, raw: object) -> Iterator[str]:
def _encrypted_leaves(db_attr: str, col: str, raw: object) -> Iterator[str]:
if db_attr in _MCP_CREDENTIAL_TABLES and col in ("credentials", "env_vars"):
return _mcp_encrypted_leaves(col, raw)
if db_attr == "litellm_proxymodeltable" and isinstance(raw, dict):
return _iter_encrypted_strings({k: v for k, v in raw.items() if k not in _PLAINTEXT_LITELLM_PARAMS})
return _iter_encrypted_strings(raw)

View file

@ -159,6 +159,46 @@ async def test_migrate_and_check_refuse_without_pynacl_instead_of_miscounting_le
client.db.litellm_config.update.assert_not_awaited()
@pytest.mark.asyncio
async def test_check_and_rotation_preflight_pass_without_pynacl_when_only_complexity_router_config_is_plaintext(
salt_key, monkeypatch
):
_enable_aes(monkeypatch)
monkeypatch.setitem(sys.modules, "nacl", None)
monkeypatch.setitem(sys.modules, "nacl.secret", None)
client: Final = MagicMock()
_empty_covered_tables(client)
client.db.litellm_teamtable.find_many = AsyncMock(return_value=[])
client.db.litellm_verificationtoken.find_many = AsyncMock(return_value=[])
client.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
client.db.litellm_config.find_unique = AsyncMock(return_value=None)
client.db.litellm_proxymodeltable.find_many = AsyncMock(
return_value=[
SimpleNamespace(
litellm_params={
"api_key": encrypt_value_helper("migrated-secret"),
"complexity_router_config": {
"strong_model": "gpt-5.1",
"opensource_classifier_config": {"api_base": "http://classifier.internal"},
},
}
)
]
)
report: Final = await cm.check_encryption(prisma_client=client)
assert report.residual_legacy == 0, report.to_dict()
assert report.as_dict()["locations"]["model_table"] == {
"scanned": 1,
"migrated": 0,
"already_v2": 1,
"plaintext": 0,
"undecryptable": 0,
"legacy": 0,
}
@pytest.mark.parametrize(
"db_attr, build_row",
[