fix: change require_byok_credential_store default to False for backwards compat, add DB helper comment

- require_byok_credential_store now defaults to False so existing deployments
  without a database are not broken on upgrade. Set True to opt into the strict
  503-on-no-DB behavior.
- Add comment clarifying that get_user_credential() is the centralized DB helper
  for LiteLLM_MCPUserCredentials, mitigated by 60s in-memory cache.
- Update tests to explicitly set the flag to True when asserting 503 behavior.
This commit is contained in:
Ishaan Jaffer 2026-03-07 10:26:56 -08:00
parent 2db33a10e5
commit 8369b0863e
3 changed files with 25 additions and 9 deletions

View file

@ -160,11 +160,11 @@ langfuse_default_tags: Optional[List[str]] = None
langsmith_batch_size: Optional[int] = None
prometheus_initialize_budget_metrics: Optional[bool] = False
require_auth_for_metrics_endpoint: Optional[bool] = False
# When True (default), BYOK MCP servers raise HTTP 503 if the credential store
# (Prisma DB) is unavailable, rather than silently bypassing the BYOK check.
# Set to False to restore pre-v1.x legacy behaviour for stateless deployments
# that do not use a database.
require_byok_credential_store: Optional[bool] = True
# When True, BYOK MCP servers raise HTTP 503 if the credential store (Prisma DB)
# is unavailable, rather than silently bypassing the BYOK check.
# Defaults to False for backwards compatibility with deployments that do not
# configure a database. Set to True to enforce strict credential-store presence.
require_byok_credential_store: Optional[bool] = False
argilla_batch_size: Optional[int] = None
datadog_use_v1: Optional[bool] = False # if you want to use v1 datadog logged payload.
gcs_pub_sub_use_v1: Optional[bool] = (

View file

@ -1602,6 +1602,10 @@ if MCP_AVAILABLE:
},
)
return None
# `get_user_credential` is the centralized data-access helper for the
# LiteLLM_MCPUserCredentials table (defined in mcp_server/db.py).
# The 60-second in-memory cache (_byok_cred_cache) ensures this is
# called at most once per TTL window, keeping the hot path DB-free.
raw = await get_user_credential(
prisma_client=prisma_client,
user_id=user_id,

View file

@ -536,13 +536,19 @@ async def test_check_byok_credential_raises_503_when_no_db():
# Ensure no cache hit
_byok_cred_cache.pop(("user1", "byok-server"), None)
import litellm
with patch(
"litellm.proxy.proxy_server.prisma_client",
None,
create=True,
):
with pytest.raises(HTTPException) as exc_info:
await _check_byok_credential(mock_server, mock_user)
litellm.require_byok_credential_store = True # type: ignore[attr-defined]
try:
with pytest.raises(HTTPException) as exc_info:
await _check_byok_credential(mock_server, mock_user)
finally:
litellm.require_byok_credential_store = False # type: ignore[attr-defined]
assert exc_info.value.status_code == 503
assert "byok_store_unavailable" in str(exc_info.value.detail)
@ -613,13 +619,19 @@ async def test_get_byok_credential_raises_503_when_no_db():
mock_user = MagicMock(spec=UserAPIKeyAuth)
mock_user.user_id = "user-db-unavail"
import litellm
with patch(
"litellm.proxy.proxy_server.prisma_client",
None,
create=True,
):
with pytest.raises(HTTPException) as exc_info:
await _get_byok_credential(mock_server, mock_user)
litellm.require_byok_credential_store = True # type: ignore[attr-defined]
try:
with pytest.raises(HTTPException) as exc_info:
await _get_byok_credential(mock_server, mock_user)
finally:
litellm.require_byok_credential_store = False # type: ignore[attr-defined]
assert exc_info.value.status_code == 503
assert "byok_store_unavailable" in str(exc_info.value.detail)