feat(proxy): add LITELLM_DISABLE_LATEST_RELEASE_CHECK to stop the release check (#48065)

* feat(proxy): add LITELLM_DISABLE_LATEST_RELEASE_CHECK to stop the release check

The dashboard asks the proxy for the latest LiteLLM release, and the proxy fetches it from api.github.com on every cache miss. Deployments that block or audit outbound traffic had no way to turn that off. With LITELLM_DISABLE_LATEST_RELEASE_CHECK=true the endpoint returns null without making a request, which the dashboard already treats as no upgrade banner.

* fix(proxy): regenerate dashboard types for the release check flag

The endpoint docstring feeds the OpenAPI description, so the ui-api-types
check needs schema.d.ts regenerated. The docstring now says the flag skips
every outbound request, which stays true once the changelog feed is read
too

---------

Co-authored-by: Sujit Nirmal <nirmalsujit891@gmail.com>
Co-authored-by: yucheng-berri <293926326+yucheng-berri@users.noreply.github.com>
This commit is contained in:
yucheng-berri 2026-10-23 12:52:27 -07:00 • committed by GitHub
parent e14d2fdc38
commit 013be3eb04
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 29 additions and 0 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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;