From ba171d9eb4a96eead01626ac0c80cb17651c5555 Mon Sep 17 00:00:00 2001 From: yassin Date: Mon, 14 Sep 2026 19:06:04 +0000 Subject: [PATCH 1/5] fix(proxy): hide default credentials login hint when UI_PASSWORD is set Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/proxy/auth/auth_utils.py | 12 ++++++ .../ui_discovery_endpoints.py | 7 +--- litellm/proxy/management_endpoints/ui_sso.py | 6 +-- litellm/proxy/proxy_server.py | 6 +-- .../test_ui_discovery_endpoints.py | 40 +++++++++++++++++++ .../proxy/management_endpoints/test_ui_sso.py | 17 ++++++++ .../proxy_server/test_routes_login_sso.py | 12 ++++++ 7 files changed, 87 insertions(+), 13 deletions(-) diff --git a/litellm/proxy/auth/auth_utils.py b/litellm/proxy/auth/auth_utils.py index be65c3b39ec..0f4160d840b 100644 --- a/litellm/proxy/auth/auth_utils.py +++ b/litellm/proxy/auth/auth_utils.py @@ -1446,6 +1446,18 @@ def has_user_setup_sso() -> bool: ) +def should_hide_default_credentials_hint(general_settings: Mapping[str, object]) -> bool: + """ + Whether login pages hide the "admin / MASTER_KEY" hint: explicit opt-in, or a + non-empty UI_PASSWORD, which makes that hint wrong. UI_USERNAME alone keeps it. + """ + return ( + os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" + or general_settings.get("hide_default_credentials_hint", False) is True + or bool(os.getenv("UI_PASSWORD")) + ) + + def _is_google_ready() -> bool: return bool(os.getenv("GOOGLE_CLIENT_ID")) and bool(os.getenv("GOOGLE_CLIENT_SECRET")) diff --git a/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py b/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py index c2053693f2e..07fd04a74fb 100644 --- a/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py +++ b/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py @@ -14,7 +14,7 @@ router: Final = APIRouter() @router.get("/.well-known/litellm-ui-config", response_model=UiDiscoveryEndpoints) @router.get("/litellm/.well-known/litellm-ui-config", response_model=UiDiscoveryEndpoints) # if mounted at root path async def get_ui_config(): - from litellm.proxy.auth.auth_utils import has_user_setup_sso + from litellm.proxy.auth.auth_utils import has_user_setup_sso, should_hide_default_credentials_hint from litellm.proxy.proxy_server import general_settings from litellm.proxy.utils import get_proxy_base_url, get_server_root_path @@ -23,10 +23,7 @@ async def get_ui_config(): or general_settings.get("auto_redirect_ui_login_to_sso", False) is True ) admin_ui_disabled: Final = os.getenv("DISABLE_ADMIN_UI", "false").lower() == "true" - hide_default_credentials_hint: Final = bool( - os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" - or general_settings.get("hide_default_credentials_hint", False) is True - ) + hide_default_credentials_hint: Final = should_hide_default_credentials_hint(general_settings) sso_configured: Final = has_user_setup_sso() diff --git a/litellm/proxy/management_endpoints/ui_sso.py b/litellm/proxy/management_endpoints/ui_sso.py index 1ba90725eff..ab916e8df1b 100644 --- a/litellm/proxy/management_endpoints/ui_sso.py +++ b/litellm/proxy/management_endpoints/ui_sso.py @@ -92,6 +92,7 @@ from litellm.proxy.auth.auth_checks import ExperimentalUIJWTToken, get_user_obje from litellm.proxy.auth.auth_utils import ( _get_request_ip_address, has_user_setup_sso, + should_hide_default_credentials_hint, ) from litellm.proxy.auth.handle_jwt import JWTHandler from litellm.proxy.auth.ip_address_utils import IPAddressUtils @@ -1110,10 +1111,7 @@ async def google_login( from fastapi.responses import HTMLResponse - hide_default_credentials_hint: Final = ( - os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" - or general_settings.get("hide_default_credentials_hint", False) is True - ) + hide_default_credentials_hint: Final = should_hide_default_credentials_hint(general_settings) form_response: Final = HTMLResponse( content=build_ui_login_form( show_deprecation_banner=True, diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index d9f8e04ebda..5b3d6365df4 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -318,6 +318,7 @@ from litellm.proxy.auth.auth_utils import ( check_response_size_is_safe, is_request_body_safe, log_once_if_budget_reservation_disabled, + should_hide_default_credentials_hint, warn_once_if_custom_auth_skips_common_checks, ) from litellm.proxy.auth.fallback_model_access import router_fallback_access_check @@ -15816,10 +15817,7 @@ async def fallback_login(request: Request): from fastapi.responses import HTMLResponse - hide_default_credentials_hint: Final = ( - os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" - or general_settings.get("hide_default_credentials_hint", False) is True - ) + hide_default_credentials_hint: Final = should_hide_default_credentials_hint(general_settings) return HTMLResponse( content=build_ui_login_form( show_deprecation_banner=False, diff --git a/tests/test_litellm/proxy/discovery_endpoints/test_ui_discovery_endpoints.py b/tests/test_litellm/proxy/discovery_endpoints/test_ui_discovery_endpoints.py index c3f7b0100d8..5e3d9c0e43b 100644 --- a/tests/test_litellm/proxy/discovery_endpoints/test_ui_discovery_endpoints.py +++ b/tests/test_litellm/proxy/discovery_endpoints/test_ui_discovery_endpoints.py @@ -340,6 +340,7 @@ def test_ui_discovery_endpoints_hide_default_credentials_hint_default_false(): patch.dict(os.environ, {"DISABLE_ADMIN_UI": "false"}, clear=False), ): os.environ.pop("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", None) + os.environ.pop("UI_PASSWORD", None) response = client.get("/.well-known/litellm-ui-config") @@ -348,6 +349,45 @@ def test_ui_discovery_endpoints_hide_default_credentials_hint_default_false(): assert data["hide_default_credentials_hint"] is False +def test_ui_discovery_endpoints_hide_default_credentials_hint_when_ui_password_set(): + """A non-empty UI_PASSWORD hides the card: 'admin / MASTER_KEY' is no longer the login.""" + app = FastAPI() + app.include_router(router) + client = TestClient(app) + + with patch.dict(os.environ, {"UI_PASSWORD": "s3cret-pass", "DISABLE_ADMIN_UI": "false"}, clear=False): + os.environ.pop("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", None) + + response = client.get("/.well-known/litellm-ui-config") + + assert response.status_code == 200 + assert response.json()["hide_default_credentials_hint"] is True + + +@pytest.mark.parametrize( + "env_overrides", + [ + pytest.param({"UI_USERNAME": "opsadmin"}, id="username_only_keeps_master_key_password"), + pytest.param({"UI_PASSWORD": ""}, id="empty_password_is_not_set"), + ], +) +def test_ui_discovery_endpoints_keeps_default_credentials_hint_without_real_ui_password(env_overrides): + """Only a non-empty UI_PASSWORD counts as custom credentials; the hint stays accurate otherwise.""" + app = FastAPI() + app.include_router(router) + client = TestClient(app) + + with patch.dict(os.environ, {"DISABLE_ADMIN_UI": "false", **env_overrides}, clear=False): + os.environ.pop("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", None) + if "UI_PASSWORD" not in env_overrides: + os.environ.pop("UI_PASSWORD", None) + + response = client.get("/.well-known/litellm-ui-config") + + assert response.status_code == 200 + assert response.json()["hide_default_credentials_hint"] is False + + def test_ui_discovery_endpoints_hide_default_credentials_hint_via_env_var(): """LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT=true hides the login-page credentials card.""" app = FastAPI() diff --git a/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py b/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py index 2050e65d2a1..2e3c2ceffa3 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py +++ b/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py @@ -8334,6 +8334,7 @@ async def _render_legacy_login_page(env_overrides, general_settings): "GOOGLE_CLIENT_ID", "GENERIC_CLIENT_ID", "LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", + "UI_PASSWORD", ): os.environ.pop(var, None) os.environ.update(env_overrides) @@ -8386,6 +8387,22 @@ async def test_legacy_login_page_hides_credentials_hint_via_general_settings(): assert "MASTER_KEY" not in body +@pytest.mark.asyncio +async def test_legacy_login_page_hides_credentials_hint_when_ui_password_set(): + """Regression: the legacy page shares the rule with the discovery endpoint, so a non-empty + UI_PASSWORD hides the now-inaccurate 'admin / MASTER_KEY' hint here too.""" + response = await _render_legacy_login_page( + env_overrides={"UI_PASSWORD": "s3cret-pass"}, + general_settings={}, + ) + + body = response.body.decode() + assert response.status_code == 200 + assert "Default Credentials" not in body + assert "MASTER_KEY" not in body + assert 'name="username"' in body + + @pytest.mark.asyncio async def test_saml_callback_blocked_when_admin_ui_disabled(): """An IdP-initiated assertion must not mint a UI session when the admin UI is diff --git a/tests/test_litellm/proxy/proxy_server/test_routes_login_sso.py b/tests/test_litellm/proxy/proxy_server/test_routes_login_sso.py index 45460dcecf1..1b4f9bc1cfe 100644 --- a/tests/test_litellm/proxy/proxy_server/test_routes_login_sso.py +++ b/tests/test_litellm/proxy/proxy_server/test_routes_login_sso.py @@ -97,6 +97,7 @@ def test_fallback_login_returns_html_form_with_ui_username_set(client, monkeypat def test_fallback_login_shows_credentials_hint_by_default(client, monkeypatch): """Control: without the flag, /fallback/login still renders the hint.""" monkeypatch.delenv("UI_USERNAME", raising=False) + monkeypatch.delenv("UI_PASSWORD", raising=False) monkeypatch.delenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", raising=False) response = client.get("/fallback/login") assert response.status_code == 200 @@ -104,6 +105,17 @@ def test_fallback_login_shows_credentials_hint_by_default(client, monkeypatch): assert "MASTER_KEY" in response.text +def test_fallback_login_hides_credentials_hint_when_ui_password_set(client, monkeypatch): + """Regression: a non-empty UI_PASSWORD means 'admin / MASTER_KEY' is wrong, so the hint must go.""" + monkeypatch.setenv("UI_PASSWORD", "s3cret-pass") + monkeypatch.delenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", raising=False) + response = client.get("/fallback/login") + assert response.status_code == 200 + assert "Default Credentials" not in response.text + assert "MASTER_KEY" not in response.text + assert 'name="username"' in response.text + + def test_fallback_login_hides_credentials_hint_via_env_flag(client, monkeypatch): """Pin: LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT removes the hint on /fallback/login.""" monkeypatch.delenv("UI_USERNAME", raising=False) From 9ff0dea1396e48c302fe203c44f4643f228dc50f Mon Sep 17 00:00:00 2001 From: yassin Date: Mon, 14 Sep 2026 19:25:03 +0000 Subject: [PATCH 2/5] fix(proxy): define credentials hint helper ahead of proxy_server imports Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/proxy/auth/auth_utils.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/litellm/proxy/auth/auth_utils.py b/litellm/proxy/auth/auth_utils.py index 0f4160d840b..d882141fa6f 100644 --- a/litellm/proxy/auth/auth_utils.py +++ b/litellm/proxy/auth/auth_utils.py @@ -552,6 +552,18 @@ def _coerce_metadata_to_dict(value: Any) -> dict[str, Any] | None: return None +def should_hide_default_credentials_hint(general_settings: Mapping[str, object]) -> bool: + """ + Whether login pages hide the "admin / MASTER_KEY" hint: explicit opt-in, or a + non-empty UI_PASSWORD, which makes that hint wrong. UI_USERNAME alone keeps it. + """ + return ( + os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" + or general_settings.get("hide_default_credentials_hint", False) is True + or bool(os.getenv("UI_PASSWORD")) + ) + + async def pre_db_read_auth_checks( request: Request, request_data: dict, @@ -1446,18 +1458,6 @@ def has_user_setup_sso() -> bool: ) -def should_hide_default_credentials_hint(general_settings: Mapping[str, object]) -> bool: - """ - Whether login pages hide the "admin / MASTER_KEY" hint: explicit opt-in, or a - non-empty UI_PASSWORD, which makes that hint wrong. UI_USERNAME alone keeps it. - """ - return ( - os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" - or general_settings.get("hide_default_credentials_hint", False) is True - or bool(os.getenv("UI_PASSWORD")) - ) - - def _is_google_ready() -> bool: return bool(os.getenv("GOOGLE_CLIENT_ID")) and bool(os.getenv("GOOGLE_CLIENT_SECRET")) From f9d0cd64097665f0ab4c872cdc3fe7ffae75d507 Mon Sep 17 00:00:00 2001 From: yassin Date: Mon, 14 Sep 2026 19:29:30 +0000 Subject: [PATCH 3/5] chore(proxy): drop explanatory docstrings from credentials hint helper and tests Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/proxy/auth/auth_utils.py | 4 ---- .../proxy/discovery_endpoints/test_ui_discovery_endpoints.py | 2 -- tests/test_litellm/proxy/management_endpoints/test_ui_sso.py | 2 -- .../test_litellm/proxy/proxy_server/test_routes_login_sso.py | 1 - 4 files changed, 9 deletions(-) diff --git a/litellm/proxy/auth/auth_utils.py b/litellm/proxy/auth/auth_utils.py index d882141fa6f..128b789ee75 100644 --- a/litellm/proxy/auth/auth_utils.py +++ b/litellm/proxy/auth/auth_utils.py @@ -553,10 +553,6 @@ def _coerce_metadata_to_dict(value: Any) -> dict[str, Any] | None: def should_hide_default_credentials_hint(general_settings: Mapping[str, object]) -> bool: - """ - Whether login pages hide the "admin / MASTER_KEY" hint: explicit opt-in, or a - non-empty UI_PASSWORD, which makes that hint wrong. UI_USERNAME alone keeps it. - """ return ( os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" or general_settings.get("hide_default_credentials_hint", False) is True diff --git a/tests/test_litellm/proxy/discovery_endpoints/test_ui_discovery_endpoints.py b/tests/test_litellm/proxy/discovery_endpoints/test_ui_discovery_endpoints.py index 5e3d9c0e43b..64a2eb69325 100644 --- a/tests/test_litellm/proxy/discovery_endpoints/test_ui_discovery_endpoints.py +++ b/tests/test_litellm/proxy/discovery_endpoints/test_ui_discovery_endpoints.py @@ -350,7 +350,6 @@ def test_ui_discovery_endpoints_hide_default_credentials_hint_default_false(): def test_ui_discovery_endpoints_hide_default_credentials_hint_when_ui_password_set(): - """A non-empty UI_PASSWORD hides the card: 'admin / MASTER_KEY' is no longer the login.""" app = FastAPI() app.include_router(router) client = TestClient(app) @@ -372,7 +371,6 @@ def test_ui_discovery_endpoints_hide_default_credentials_hint_when_ui_password_s ], ) def test_ui_discovery_endpoints_keeps_default_credentials_hint_without_real_ui_password(env_overrides): - """Only a non-empty UI_PASSWORD counts as custom credentials; the hint stays accurate otherwise.""" app = FastAPI() app.include_router(router) client = TestClient(app) diff --git a/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py b/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py index 2e3c2ceffa3..1230c548281 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py +++ b/tests/test_litellm/proxy/management_endpoints/test_ui_sso.py @@ -8389,8 +8389,6 @@ async def test_legacy_login_page_hides_credentials_hint_via_general_settings(): @pytest.mark.asyncio async def test_legacy_login_page_hides_credentials_hint_when_ui_password_set(): - """Regression: the legacy page shares the rule with the discovery endpoint, so a non-empty - UI_PASSWORD hides the now-inaccurate 'admin / MASTER_KEY' hint here too.""" response = await _render_legacy_login_page( env_overrides={"UI_PASSWORD": "s3cret-pass"}, general_settings={}, diff --git a/tests/test_litellm/proxy/proxy_server/test_routes_login_sso.py b/tests/test_litellm/proxy/proxy_server/test_routes_login_sso.py index 1b4f9bc1cfe..79c23b11f3e 100644 --- a/tests/test_litellm/proxy/proxy_server/test_routes_login_sso.py +++ b/tests/test_litellm/proxy/proxy_server/test_routes_login_sso.py @@ -106,7 +106,6 @@ def test_fallback_login_shows_credentials_hint_by_default(client, monkeypatch): def test_fallback_login_hides_credentials_hint_when_ui_password_set(client, monkeypatch): - """Regression: a non-empty UI_PASSWORD means 'admin / MASTER_KEY' is wrong, so the hint must go.""" monkeypatch.setenv("UI_PASSWORD", "s3cret-pass") monkeypatch.delenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", raising=False) response = client.get("/fallback/login") From caaf368652f87f73277faa6353cd2e0b4261de6e Mon Sep 17 00:00:00 2001 From: yassin Date: Mon, 14 Sep 2026 19:48:45 +0000 Subject: [PATCH 4/5] fix(proxy): move credentials hint helper into discovery module to break CodeQL import cycle Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/proxy/auth/auth_utils.py | 8 -------- .../discovery_endpoints/ui_discovery_endpoints.py | 11 ++++++++++- litellm/proxy/management_endpoints/ui_sso.py | 2 +- litellm/proxy/proxy_server.py | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/litellm/proxy/auth/auth_utils.py b/litellm/proxy/auth/auth_utils.py index 128b789ee75..be65c3b39ec 100644 --- a/litellm/proxy/auth/auth_utils.py +++ b/litellm/proxy/auth/auth_utils.py @@ -552,14 +552,6 @@ def _coerce_metadata_to_dict(value: Any) -> dict[str, Any] | None: return None -def should_hide_default_credentials_hint(general_settings: Mapping[str, object]) -> bool: - return ( - os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" - or general_settings.get("hide_default_credentials_hint", False) is True - or bool(os.getenv("UI_PASSWORD")) - ) - - async def pre_db_read_auth_checks( request: Request, request_data: dict, diff --git a/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py b/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py index 07fd04a74fb..e0efe9dea2c 100644 --- a/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py +++ b/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py @@ -1,5 +1,6 @@ #### Analytics Endpoints ##### import os +from collections.abc import Mapping from typing import Final from fastapi import APIRouter @@ -11,10 +12,18 @@ from litellm.types.proxy.discovery_endpoints.ui_discovery_endpoints import ( router: Final = APIRouter() +def should_hide_default_credentials_hint(general_settings: Mapping[str, object]) -> bool: + return ( + os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" + or general_settings.get("hide_default_credentials_hint", False) is True + or bool(os.getenv("UI_PASSWORD")) + ) + + @router.get("/.well-known/litellm-ui-config", response_model=UiDiscoveryEndpoints) @router.get("/litellm/.well-known/litellm-ui-config", response_model=UiDiscoveryEndpoints) # if mounted at root path async def get_ui_config(): - from litellm.proxy.auth.auth_utils import has_user_setup_sso, should_hide_default_credentials_hint + from litellm.proxy.auth.auth_utils import has_user_setup_sso from litellm.proxy.proxy_server import general_settings from litellm.proxy.utils import get_proxy_base_url, get_server_root_path diff --git a/litellm/proxy/management_endpoints/ui_sso.py b/litellm/proxy/management_endpoints/ui_sso.py index ab916e8df1b..6a775998f4f 100644 --- a/litellm/proxy/management_endpoints/ui_sso.py +++ b/litellm/proxy/management_endpoints/ui_sso.py @@ -92,7 +92,6 @@ from litellm.proxy.auth.auth_checks import ExperimentalUIJWTToken, get_user_obje from litellm.proxy.auth.auth_utils import ( _get_request_ip_address, has_user_setup_sso, - should_hide_default_credentials_hint, ) from litellm.proxy.auth.handle_jwt import JWTHandler from litellm.proxy.auth.ip_address_utils import IPAddressUtils @@ -107,6 +106,7 @@ from litellm.proxy.common_utils.html_forms.jwt_display_template import ( ) from litellm.proxy.common_utils.html_forms.ui_login import build_ui_login_form from litellm.proxy.common_utils.user_api_key_cache import UserApiKeyCache +from litellm.proxy.discovery_endpoints.ui_discovery_endpoints import should_hide_default_credentials_hint from litellm.proxy.management_endpoints.internal_user_endpoints import new_user from litellm.proxy.management_endpoints.sso import CustomMicrosoftSSO from litellm.proxy.management_endpoints.sso.id_jag_assertion_capture import ( diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 5b3d6365df4..230513d7eb4 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -318,7 +318,6 @@ from litellm.proxy.auth.auth_utils import ( check_response_size_is_safe, is_request_body_safe, log_once_if_budget_reservation_disabled, - should_hide_default_credentials_hint, warn_once_if_custom_auth_skips_common_checks, ) from litellm.proxy.auth.fallback_model_access import router_fallback_access_check @@ -451,6 +450,7 @@ from litellm.proxy.discovery_endpoints import ( agent_skills_discovery_router, ui_discovery_endpoints_router, ) +from litellm.proxy.discovery_endpoints.ui_discovery_endpoints import should_hide_default_credentials_hint from litellm.proxy.fine_tuning_endpoints.endpoints import router as fine_tuning_router from litellm.proxy.fine_tuning_endpoints.endpoints import set_fine_tuning_config from litellm.proxy.google_endpoints.endpoints import router as google_router From c8440b5638881d9eb463ecbc5a17ba4c7351ee3b Mon Sep 17 00:00:00 2001 From: yassin Date: Mon, 14 Sep 2026 20:34:58 +0000 Subject: [PATCH 5/5] fix(proxy): move credentials hint helper into a leaf html_forms module to clear CodeQL cyclic import Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../html_forms/default_credentials_hint.py | 10 ++++++++++ .../discovery_endpoints/ui_discovery_endpoints.py | 10 +--------- litellm/proxy/management_endpoints/ui_sso.py | 2 +- litellm/proxy/proxy_server.py | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 litellm/proxy/common_utils/html_forms/default_credentials_hint.py diff --git a/litellm/proxy/common_utils/html_forms/default_credentials_hint.py b/litellm/proxy/common_utils/html_forms/default_credentials_hint.py new file mode 100644 index 00000000000..e3ed948501b --- /dev/null +++ b/litellm/proxy/common_utils/html_forms/default_credentials_hint.py @@ -0,0 +1,10 @@ +import os +from collections.abc import Mapping + + +def should_hide_default_credentials_hint(general_settings: Mapping[str, object]) -> bool: + return ( + os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" + or general_settings.get("hide_default_credentials_hint", False) is True + or bool(os.getenv("UI_PASSWORD")) + ) diff --git a/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py b/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py index e0efe9dea2c..8b042d18cd0 100644 --- a/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py +++ b/litellm/proxy/discovery_endpoints/ui_discovery_endpoints.py @@ -1,10 +1,10 @@ #### Analytics Endpoints ##### import os -from collections.abc import Mapping from typing import Final from fastapi import APIRouter +from litellm.proxy.common_utils.html_forms.default_credentials_hint import should_hide_default_credentials_hint from litellm.types.proxy.discovery_endpoints.ui_discovery_endpoints import ( UiDiscoveryEndpoints, ) @@ -12,14 +12,6 @@ from litellm.types.proxy.discovery_endpoints.ui_discovery_endpoints import ( router: Final = APIRouter() -def should_hide_default_credentials_hint(general_settings: Mapping[str, object]) -> bool: - return ( - os.getenv("LITELLM_HIDE_DEFAULT_CREDENTIALS_HINT", "false").lower() == "true" - or general_settings.get("hide_default_credentials_hint", False) is True - or bool(os.getenv("UI_PASSWORD")) - ) - - @router.get("/.well-known/litellm-ui-config", response_model=UiDiscoveryEndpoints) @router.get("/litellm/.well-known/litellm-ui-config", response_model=UiDiscoveryEndpoints) # if mounted at root path async def get_ui_config(): diff --git a/litellm/proxy/management_endpoints/ui_sso.py b/litellm/proxy/management_endpoints/ui_sso.py index 6a775998f4f..091dccf1433 100644 --- a/litellm/proxy/management_endpoints/ui_sso.py +++ b/litellm/proxy/management_endpoints/ui_sso.py @@ -101,12 +101,12 @@ from litellm.proxy.common_utils.admin_ui_utils import ( admin_ui_disabled, show_missing_vars_in_env, ) +from litellm.proxy.common_utils.html_forms.default_credentials_hint import should_hide_default_credentials_hint from litellm.proxy.common_utils.html_forms.jwt_display_template import ( jwt_display_template, ) from litellm.proxy.common_utils.html_forms.ui_login import build_ui_login_form from litellm.proxy.common_utils.user_api_key_cache import UserApiKeyCache -from litellm.proxy.discovery_endpoints.ui_discovery_endpoints import should_hide_default_credentials_hint from litellm.proxy.management_endpoints.internal_user_endpoints import new_user from litellm.proxy.management_endpoints.sso import CustomMicrosoftSSO from litellm.proxy.management_endpoints.sso.id_jag_assertion_capture import ( diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 230513d7eb4..fce468aa564 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -365,6 +365,7 @@ from litellm.proxy.common_utils.healthy_model_filter import ( get_hidden_unhealthy_model_names, is_healthy_only_listing_default, ) +from litellm.proxy.common_utils.html_forms.default_credentials_hint import should_hide_default_credentials_hint from litellm.proxy.common_utils.html_forms.ui_login import build_ui_login_form from litellm.proxy.common_utils.http_parsing_utils import ( _read_request_body, @@ -450,7 +451,6 @@ from litellm.proxy.discovery_endpoints import ( agent_skills_discovery_router, ui_discovery_endpoints_router, ) -from litellm.proxy.discovery_endpoints.ui_discovery_endpoints import should_hide_default_credentials_hint from litellm.proxy.fine_tuning_endpoints.endpoints import router as fine_tuning_router from litellm.proxy.fine_tuning_endpoints.endpoints import set_fine_tuning_config from litellm.proxy.google_endpoints.endpoints import router as google_router