diff --git a/litellm/proxy/ui_crud_endpoints/latest_release_endpoints.py b/litellm/proxy/ui_crud_endpoints/latest_release_endpoints.py index ef2a5f88e4e..14d75633100 100644 --- a/litellm/proxy/ui_crud_endpoints/latest_release_endpoints.py +++ b/litellm/proxy/ui_crud_endpoints/latest_release_endpoints.py @@ -1,4 +1,5 @@ import asyncio +import os import re import xml.etree.ElementTree as ET from collections import Counter @@ -88,6 +89,10 @@ def _default_fetch_lock() -> asyncio.Lock: return _latest_release_fetch_lock +def _default_release_check_enabled() -> bool: + return os.getenv("LITELLM_DISABLE_LATEST_RELEASE_CHECK", "").strip().lower() != "true" + + def _bucket_for(line: str) -> _Bucket | None: if _NEW_CONTRIBUTOR_PATTERN.match(line) is not None: return None @@ -224,12 +229,16 @@ async def latest_release_info( client: Annotated[_AsyncGetClient, Depends(_default_client)], cache: Annotated[InMemoryCache, Depends(_default_cache)], fetch_lock: Annotated[asyncio.Lock, Depends(_default_fetch_lock)], + release_check_enabled: Annotated[bool, Depends(_default_release_check_enabled)], ) -> LatestReleaseInfo | None: """ Newest stable release on the LiteLLM changelog, linked to its changelog page, with the PR count of its whole minor line (e.g. v1.105.0 + v1.105.1) from GitHub split into new features, bug fixes and other updates. Returns null when the changelog or GitHub can't be reached so the dashboard upgrade banner simply doesn't render. + Set LITELLM_DISABLE_LATEST_RELEASE_CHECK=true to return null without making any outbound request. """ + if not release_check_enabled: + return None result: Final = await get_latest_release_info(client=client, cache=cache, fetch_lock=fetch_lock) if isinstance(result, LatestReleaseUnavailable): verbose_proxy_logger.warning("LiteLLM: latest release info unavailable: %s", result.reason) diff --git a/tests/unit/proxy/ui_crud_endpoints/test_latest_release_endpoints.py b/tests/unit/proxy/ui_crud_endpoints/test_latest_release_endpoints.py index 47f81fb55d1..d5139263dc3 100644 --- a/tests/unit/proxy/ui_crud_endpoints/test_latest_release_endpoints.py +++ b/tests/unit/proxy/ui_crud_endpoints/test_latest_release_endpoints.py @@ -401,6 +401,25 @@ class TestLatestReleaseInfoEndpoint: assert response.status_code == 200 assert response.json() is None + @pytest.mark.parametrize( + ("flag", "expected_body", "expected_urls"), + [ + ("true", None, []), + (" TRUE ", None, []), + ("false", EXPECTED_INFO, [CHANGELOG_FEED_URL, _tag_url("v1.102.0")]), + ], + ) + def test_disable_flag_skips_every_outbound_request( + self, http_client, monkeypatch, flag, expected_body, expected_urls + ): + monkeypatch.setenv("LITELLM_DISABLE_LATEST_RELEASE_CHECK", flag) + client = _minor_release() + _override_dependencies(client, _fresh_cache(), LitellmUserRoles.PROXY_ADMIN) + response = http_client.get("/get/latest_release_info") + assert response.status_code == 200 + assert response.json() == expected_body + assert client.urls == expected_urls + def test_repeated_requests_reuse_cache(self, http_client): client = _minor_release() _override_dependencies(client, _fresh_cache(), LitellmUserRoles.PROXY_ADMIN) diff --git a/ui/litellm-dashboard/src/lib/http/schema.d.ts b/ui/litellm-dashboard/src/lib/http/schema.d.ts index f3821a2bb46..b27d06b00f0 100644 --- a/ui/litellm-dashboard/src/lib/http/schema.d.ts +++ b/ui/litellm-dashboard/src/lib/http/schema.d.ts @@ -5868,6 +5868,7 @@ export interface paths { * @description Newest stable release on the LiteLLM changelog, linked to its changelog page, with the PR count of its whole * minor line (e.g. v1.105.0 + v1.105.1) from GitHub split into new features, bug fixes and other updates. * Returns null when the changelog or GitHub can't be reached so the dashboard upgrade banner simply doesn't render. + * Set LITELLM_DISABLE_LATEST_RELEASE_CHECK=true to return null without making any outbound request. */ get: operations["latest_release_info_get_latest_release_info_get"]; put?: never;