From 7e6e2fff09c7013e36aab4f03dc5db9f68a9c742 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 31 May 2026 05:17:28 +0000 Subject: [PATCH 1/6] Studio: fall back to a tokenless release redirect when the llama.cpp REST API is rate limited unsloth studio update discovers the llama.cpp prebuilt through the GitHub REST API, which is rate limited to 60 requests per hour per IP for anonymous callers. Without GH_TOKEN or GITHUB_TOKEN, users on shared, NAT, or cloud IPs hit HTTP 403 and the installer falls back to a slow source build. Keep the REST API as the primary path. When it is unavailable (for example a tokenless 403), fall back to resolving the latest upstream release from the unauthenticated github.com//releases/latest redirect and build deterministic asset download URLs, so the prebuilt path still works with no token. The redirect is only a fallback and is always unauthenticated. Scope is narrow: the fallback only applies to the upstream repo plus latest plus the simple policy path, on platforms whose asset choice is a single deterministic file. Pinned tags, the Linux CUDA manifest path, the token path, and Windows x64 NVIDIA or AMD asset selection are unchanged. Add tests covering redirect parsing, REST first resolution, the redirect fallback on a 403 and on a missing tag, the Windows CUDA opt out, and end to end macOS and Linux latest resolution when the REST API 403s. --- studio/install_llama_prebuilt.py | 184 ++++++++-- .../test_tokenless_release_resolution.py | 319 ++++++++++++++++++ 2 files changed, 479 insertions(+), 24 deletions(-) create mode 100644 tests/studio/install/test_tokenless_release_resolution.py diff --git a/studio/install_llama_prebuilt.py b/studio/install_llama_prebuilt.py index 9443b13fd7..5cec3af8c0 100644 --- a/studio/install_llama_prebuilt.py +++ b/studio/install_llama_prebuilt.py @@ -1106,14 +1106,100 @@ def github_releases( return releases +_RELEASE_TAG_PATH_RE = re.compile(r"/releases/tag/(?P[^/?#]+)") + + +def web_request_headers() -> dict[str, str]: + # github.com release endpoints are not rate-limited like api.github.com, so + # this path is intentionally unauthenticated: no token, no header logging. + return {"User-Agent": "unsloth-studio-llama-prebuilt"} + + +def upstream_release_download_url(repo: str, tag: str, asset_name: str) -> str: + """Deterministic release-asset download URL that needs no REST API call. + + github.com//releases/download// redirects to the release + CDN and is not part of the rate-limited api.github.com surface. + """ + return ( + f"https://github.com/{repo}/releases/download/" + f"{urllib.parse.quote(tag, safe = '')}/{asset_name}" + ) + + +def _tag_from_release_location(location: str | None) -> str | None: + if not location: + return None + try: + path = urllib.parse.urlparse(location).path + except Exception: + return None + match = _RELEASE_TAG_PATH_RE.search(path) + if not match: + return None + tag = urllib.parse.unquote(match.group("tag")).strip() + return tag or None + + +def _resolve_latest_release_tag_via_redirect(repo: str) -> str | None: + """Resolve a repo's latest release tag without the rate-limited REST API. + + github.com//releases/latest 302-redirects to .../releases/tag/; + reading that Location costs none of the anonymous api.github.com budget. + Returns None on failure so callers fall back to the REST listing. + """ + + class _NoFollowRedirect(urllib.request.HTTPRedirectHandler): + def redirect_request(self, *args, **kwargs): # type: ignore[override] + return None + + url = f"https://github.com/{repo}/releases/latest" + opener = urllib.request.build_opener(_NoFollowRedirect) + last_exc: Exception | None = None + for attempt in range(1, JSON_FETCH_ATTEMPTS + 1): + try: + request = urllib.request.Request(url, headers = web_request_headers()) + try: + with opener.open(request, timeout = 30) as response: + location = response.headers.get("Location") + except urllib.error.HTTPError as exc: + # Disabling redirects surfaces the 3xx as an HTTPError whose + # Location header still carries the resolved release-tag URL. + if exc.code in {301, 302, 303, 307, 308}: + location = exc.headers.get("Location") if exc.headers else None + else: + raise + return _tag_from_release_location(location) + except Exception as exc: + last_exc = exc + if attempt >= JSON_FETCH_ATTEMPTS or not is_retryable_url_error(exc): + break + sleep_backoff(attempt, exc = exc) + if last_exc is not None: + log(f"latest-release redirect resolution failed for {repo}: {last_exc}") + return None + + def latest_upstream_release_tag() -> str: - payload = fetch_json(UPSTREAM_RELEASES_API) - tag = payload.get("tag_name") - if not isinstance(tag, str) or not tag: - raise RuntimeError( - f"latest release tag was missing from {UPSTREAM_RELEASES_API}" - ) - return tag + # Primary path is the GitHub REST API; fall back to the github.com release + # redirect (no token, not subject to the anonymous api.github.com 403 rate + # limit) when REST is unavailable or returns no usable tag. + try: + payload = fetch_json(UPSTREAM_RELEASES_API) + tag = payload.get("tag_name") + except (urllib.error.URLError, RuntimeError): + redirect_tag = _resolve_latest_release_tag_via_redirect(UPSTREAM_REPO) + if redirect_tag: + return redirect_tag + raise + if isinstance(tag, str) and tag: + return tag + redirect_tag = _resolve_latest_release_tag_via_redirect(UPSTREAM_REPO) + if redirect_tag: + return redirect_tag + raise RuntimeError( + f"latest release tag was missing from {UPSTREAM_RELEASES_API}" + ) def is_release_tag_like(value: str | None) -> bool: @@ -1138,10 +1224,24 @@ def release_time_sort_key(release: dict[str, Any]) -> tuple[str, int]: return (timestamp, normalized_id) +def _needs_dynamic_asset_enumeration(host: HostInfo | None) -> bool: + # Windows x64 NVIDIA/AMD hosts pick among several CUDA/HIP archives by + # probing a release's actual assets, which the redirect fast path does not + # enumerate. Keep them on the REST listing to avoid a silent CPU downgrade. + if host is None: + return False + return bool( + host.is_windows + and host.is_x86_64 + and (host.has_usable_nvidia or host.has_rocm) + ) + + def iter_release_payloads_by_time( repo: str, published_release_tag: str = "", requested_tag: str = "", + host: HostInfo | None = None, ) -> Iterable[dict[str, Any]]: if published_release_tag: yield github_release(repo, published_release_tag) @@ -1165,15 +1265,41 @@ def iter_release_payloads_by_time( except Exception: raise - releases = [ - release - for release in github_releases( - repo, max_pages = DEFAULT_GITHUB_RELEASE_SCAN_MAX_PAGES - ) - if isinstance(release, dict) - and not release.get("draft") - and not release.get("prerelease") - ] + # Primary: the GitHub REST release listing. Fallback for upstream "latest": + # resolve the tag from the github.com release redirect (no api.github.com + # budget spent) and synthesize a release with deterministic asset URLs, so a + # rate-limited (HTTP 403) REST API does not force a source build. Gated to + # upstream single-asset platforms. + redirect_eligible = ( + repo == UPSTREAM_REPO + and (not requested_tag or requested_tag == "latest") + and not _needs_dynamic_asset_enumeration(host) + ) + try: + releases = [ + release + for release in github_releases( + repo, max_pages = DEFAULT_GITHUB_RELEASE_SCAN_MAX_PAGES + ) + if isinstance(release, dict) + and not release.get("draft") + and not release.get("prerelease") + ] + except (urllib.error.URLError, RuntimeError) as exc: + if redirect_eligible: + redirect_tag = _resolve_latest_release_tag_via_redirect(repo) + if redirect_tag: + log( + f"GitHub REST release listing failed ({exc}); resolved " + f"latest {repo} release {redirect_tag} via release redirect" + ) + yield { + "tag_name": redirect_tag, + "assets": [], + "_unsloth_download_repo": repo, + } + return + raise releases.sort(key = release_time_sort_key, reverse = True) for release in releases: yield release @@ -1375,6 +1501,16 @@ def direct_upstream_release_plan( return None assets = release_asset_map(release) + # Redirect fast-path releases carry no enumerated assets; build URLs from + # the tag instead. Without this sentinel, behavior is unchanged. + download_repo = release.get("_unsloth_download_repo") + + def asset_url_for(asset_name: str) -> str | None: + url = assets.get(asset_name) + if not url and download_repo: + return upstream_release_download_url(download_repo, release_tag, asset_name) + return url + attempts: list[AssetChoice] = [] if host.is_windows and host.is_x86_64: if host.has_usable_nvidia: @@ -1395,7 +1531,7 @@ def direct_upstream_release_plan( if lemonade_choice is not None: attempts.append(lemonade_choice) hip_asset = f"llama-{release_tag}-bin-win-hip-radeon-x64.zip" - hip_url = assets.get(hip_asset) + hip_url = asset_url_for(hip_asset) if hip_url: attempts.append( AssetChoice( @@ -1408,7 +1544,7 @@ def direct_upstream_release_plan( ) ) cpu_asset = f"llama-{release_tag}-bin-win-cpu-x64.zip" - cpu_url = assets.get(cpu_asset) + cpu_url = asset_url_for(cpu_asset) if cpu_url: attempts.append( AssetChoice( @@ -1426,7 +1562,7 @@ def direct_upstream_release_plan( # selector returned 0 attempts and the installer fell back to a # source build on every Windows ARM64 host. cpu_asset = f"llama-{release_tag}-bin-win-cpu-arm64.zip" - cpu_url = assets.get(cpu_asset) + cpu_url = asset_url_for(cpu_asset) if cpu_url: attempts.append( AssetChoice( @@ -1440,7 +1576,7 @@ def direct_upstream_release_plan( ) elif host.is_macos and host.is_arm64: asset_name = f"llama-{release_tag}-bin-macos-arm64.tar.gz" - asset_url = assets.get(asset_name) + asset_url = asset_url_for(asset_name) if asset_url: attempts.append( AssetChoice( @@ -1454,7 +1590,7 @@ def direct_upstream_release_plan( ) elif host.is_macos and host.is_x86_64: asset_name = f"llama-{release_tag}-bin-macos-x64.tar.gz" - asset_url = assets.get(asset_name) + asset_url = asset_url_for(asset_name) if asset_url: attempts.append( AssetChoice( @@ -1468,7 +1604,7 @@ def direct_upstream_release_plan( ) elif host.is_linux and host.is_x86_64 and not host.has_usable_nvidia: asset_name = f"llama-{release_tag}-bin-ubuntu-x64.tar.gz" - asset_url = assets.get(asset_name) + asset_url = asset_url_for(asset_name) if asset_url: attempts.append( AssetChoice( @@ -1487,7 +1623,7 @@ def direct_upstream_release_plan( # source build on every Linux ARM64 host (DGX Spark, Ampere # Altra, GitHub-hosted ubuntu-24.04-arm runners, etc.). asset_name = f"llama-{release_tag}-bin-ubuntu-arm64.tar.gz" - asset_url = assets.get(asset_name) + asset_url = asset_url_for(asset_name) if asset_url: attempts.append( AssetChoice( @@ -1533,7 +1669,7 @@ def resolve_simple_install_release_plans( try: releases = iter_release_payloads_by_time( - repo, published_release_tag, requested_tag + repo, published_release_tag, requested_tag, host ) for release in releases: try: diff --git a/tests/studio/install/test_tokenless_release_resolution.py b/tests/studio/install/test_tokenless_release_resolution.py new file mode 100644 index 0000000000..223fada439 --- /dev/null +++ b/tests/studio/install/test_tokenless_release_resolution.py @@ -0,0 +1,319 @@ +"""Tests for tokenless (no GH_TOKEN) llama.cpp release resolution. + +Cover the github.com release-redirect fallback that resolves the latest upstream +release when the rate-limited api.github.com REST surface is unavailable. +""" + +import sys +import urllib.error +from email.message import Message +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[3] +STUDIO_DIR = ROOT / "studio" +if str(STUDIO_DIR) not in sys.path: + sys.path.insert(0, str(STUDIO_DIR)) + +import install_llama_prebuilt as MOD # noqa: E402 +from install_llama_prebuilt import HostInfo # noqa: E402 + + +def _host(**overrides) -> HostInfo: + base = dict( + system = "Darwin", + machine = "arm64", + is_windows = False, + is_linux = False, + is_macos = True, + is_x86_64 = False, + is_arm64 = True, + nvidia_smi = None, + driver_cuda_version = None, + compute_caps = [], + visible_cuda_devices = None, + has_physical_nvidia = False, + has_usable_nvidia = False, + has_rocm = False, + rocm_gfx_target = None, + ) + base.update(overrides) + return HostInfo(**base) + + +def _linux_cpu(**overrides) -> HostInfo: + return _host( + system = "Linux", + machine = "x86_64", + is_windows = False, + is_linux = True, + is_macos = False, + is_x86_64 = True, + is_arm64 = False, + **overrides, + ) + + +def _win_cuda(**overrides) -> HostInfo: + return _host( + system = "Windows", + machine = "AMD64", + is_windows = True, + is_linux = False, + is_macos = False, + is_x86_64 = True, + is_arm64 = False, + has_physical_nvidia = True, + has_usable_nvidia = True, + **overrides, + ) + + +def _headers(**pairs) -> Message: + message = Message() + for key, value in pairs.items(): + message[key] = value + return message + + +class _FakeRedirectResponse: + def __init__(self, headers: Message): + self._headers = headers + + def __enter__(self): + return self + + def __exit__(self, *exc): + return False + + @property + def headers(self) -> Message: + return self._headers + + +def _rest_403(*args, **kwargs): + # Matches how fetch_json / github_releases surface an anonymous rate limit. + raise RuntimeError( + "GitHub API returned 403 for " + "https://api.github.com/repos/ggml-org/llama.cpp/releases?per_page=100&page=1" + ) + + +# --- pure helpers ----------------------------------------------------------- + + +def test_upstream_release_download_url_is_deterministic(): + url = MOD.upstream_release_download_url( + "ggml-org/llama.cpp", "b9999", "llama-b9999-bin-macos-arm64.tar.gz" + ) + assert url == ( + "https://github.com/ggml-org/llama.cpp/releases/download/" + "b9999/llama-b9999-bin-macos-arm64.tar.gz" + ) + + +def test_tag_from_release_location_parses_tag(): + assert ( + MOD._tag_from_release_location( + "https://github.com/ggml-org/llama.cpp/releases/tag/b9437" + ) + == "b9437" + ) + # URL-encoded tag is decoded. + assert ( + MOD._tag_from_release_location( + "https://github.com/owner/repo/releases/tag/v1.2.3%2Bcuda" + ) + == "v1.2.3+cuda" + ) + + +@pytest.mark.parametrize( + "location", + [None, "", "https://github.com/owner/repo/releases", "not a url at all"], +) +def test_tag_from_release_location_rejects_non_tag_urls(location): + assert MOD._tag_from_release_location(location) is None + + +# --- redirect resolver ------------------------------------------------------ + + +def test_resolve_latest_tag_via_redirect_reads_location(monkeypatch): + captured = {} + + def fake_build_opener(*handlers): + class _Opener: + def open(self, request, timeout = None): + captured["url"] = request.full_url + captured["has_auth"] = "Authorization" in request.headers + return _FakeRedirectResponse( + _headers( + Location = "https://github.com/ggml-org/llama.cpp/releases/tag/b9999" + ) + ) + + return _Opener() + + monkeypatch.setattr(MOD.urllib.request, "build_opener", fake_build_opener) + tag = MOD._resolve_latest_release_tag_via_redirect("ggml-org/llama.cpp") + assert tag == "b9999" + assert captured["url"] == "https://github.com/ggml-org/llama.cpp/releases/latest" + # The redirect call must never be authenticated (no token leakage). + assert captured["has_auth"] is False + + +def test_resolve_latest_tag_via_redirect_handles_httperror_3xx(monkeypatch): + def fake_build_opener(*handlers): + class _Opener: + def open(self, request, timeout = None): + raise urllib.error.HTTPError( + request.full_url, + 302, + "Found", + _headers( + Location = "https://github.com/ggml-org/llama.cpp/releases/tag/b1234" + ), + None, + ) + + return _Opener() + + monkeypatch.setattr(MOD.urllib.request, "build_opener", fake_build_opener) + assert MOD._resolve_latest_release_tag_via_redirect("ggml-org/llama.cpp") == "b1234" + + +def test_resolve_latest_tag_via_redirect_returns_none_on_failure(monkeypatch): + def fake_build_opener(*handlers): + class _Opener: + def open(self, request, timeout = None): + raise urllib.error.URLError("connection reset") + + return _Opener() + + monkeypatch.setattr(MOD.urllib.request, "build_opener", fake_build_opener) + monkeypatch.setattr(MOD, "sleep_backoff", lambda *a, **k: None) + assert MOD._resolve_latest_release_tag_via_redirect("ggml-org/llama.cpp") is None + + +# --- latest_upstream_release_tag: REST first, redirect fallback ------------- + + +def test_latest_upstream_release_tag_uses_rest_first(monkeypatch): + monkeypatch.setattr(MOD, "fetch_json", lambda url: {"tag_name": "b500"}) + + def boom(repo): + raise AssertionError("redirect must not be used when REST succeeds") + + monkeypatch.setattr(MOD, "_resolve_latest_release_tag_via_redirect", boom) + assert MOD.latest_upstream_release_tag() == "b500" + + +def test_latest_upstream_release_tag_falls_back_to_redirect_on_403(monkeypatch): + monkeypatch.setattr(MOD, "fetch_json", _rest_403) + monkeypatch.setattr( + MOD, "_resolve_latest_release_tag_via_redirect", lambda repo: "b600" + ) + assert MOD.latest_upstream_release_tag() == "b600" + + +def test_latest_upstream_release_tag_falls_back_to_redirect_on_missing_tag(monkeypatch): + monkeypatch.setattr(MOD, "fetch_json", lambda url: {}) + monkeypatch.setattr( + MOD, "_resolve_latest_release_tag_via_redirect", lambda repo: "b601" + ) + assert MOD.latest_upstream_release_tag() == "b601" + + +# --- iter_release_payloads_by_time: REST first, redirect fallback ----------- + + +def test_iter_release_payloads_uses_rest_listing_first(monkeypatch): + rest_release = { + "tag_name": "b800", + "assets": [], + "published_at": "2026-01-01T00:00:00Z", + "id": 800, + } + monkeypatch.setattr(MOD, "github_releases", lambda *a, **k: [rest_release]) + + def boom(repo): + raise AssertionError("redirect must not be used when REST succeeds") + + monkeypatch.setattr(MOD, "_resolve_latest_release_tag_via_redirect", boom) + + releases = list( + MOD.iter_release_payloads_by_time(MOD.UPSTREAM_REPO, "", "latest", _host()) + ) + assert releases == [rest_release] + + +def test_iter_release_payloads_falls_back_to_redirect_on_403(monkeypatch): + monkeypatch.setattr(MOD, "github_releases", _rest_403) + monkeypatch.setattr( + MOD, "_resolve_latest_release_tag_via_redirect", lambda repo: "b900" + ) + + releases = list( + MOD.iter_release_payloads_by_time(MOD.UPSTREAM_REPO, "", "latest", _host()) + ) + assert len(releases) == 1 + assert releases[0]["tag_name"] == "b900" + assert releases[0]["assets"] == [] + assert releases[0]["_unsloth_download_repo"] == MOD.UPSTREAM_REPO + + +def test_windows_cuda_host_does_not_use_redirect_fallback(monkeypatch): + win = _win_cuda() + assert MOD._needs_dynamic_asset_enumeration(win) is True + assert MOD._needs_dynamic_asset_enumeration(_host()) is False + + monkeypatch.setattr(MOD, "github_releases", _rest_403) + + def boom(repo): + raise AssertionError("Windows CUDA hosts must not use the redirect fallback") + + monkeypatch.setattr(MOD, "_resolve_latest_release_tag_via_redirect", boom) + + with pytest.raises(RuntimeError): + list(MOD.iter_release_payloads_by_time(MOD.UPSTREAM_REPO, "", "latest", win)) + + +# --- end to end: REST 403 falls back to a redirect-resolved prebuilt -------- + + +def test_macos_latest_prebuilt_via_redirect_when_rest_403(monkeypatch): + monkeypatch.setattr(MOD, "github_releases", _rest_403) + monkeypatch.setattr( + MOD, "_resolve_latest_release_tag_via_redirect", lambda repo: "b9999" + ) + + requested_tag, plans = MOD.resolve_simple_install_release_plans( + "latest", _host(), "ggml-org/llama.cpp", "" + ) + assert requested_tag == "latest" + assert len(plans) == 1 + plan = plans[0] + assert plan.llama_tag == "b9999" + assert len(plan.attempts) == 1 + assert plan.attempts[0].url == ( + "https://github.com/ggml-org/llama.cpp/releases/download/" + "b9999/llama-b9999-bin-macos-arm64.tar.gz" + ) + assert plan.attempts[0].name == "llama-b9999-bin-macos-arm64.tar.gz" + + +def test_linux_cpu_latest_prebuilt_via_redirect_when_rest_403(monkeypatch): + monkeypatch.setattr(MOD, "github_releases", _rest_403) + monkeypatch.setattr( + MOD, "_resolve_latest_release_tag_via_redirect", lambda repo: "b9999" + ) + + _requested, plans = MOD.resolve_simple_install_release_plans( + "latest", _linux_cpu(), "ggml-org/llama.cpp", "" + ) + assert plans[0].attempts[0].url == ( + "https://github.com/ggml-org/llama.cpp/releases/download/" + "b9999/llama-b9999-bin-ubuntu-x64.tar.gz" + ) From 3e743f515b76c8fb10e981e3c55f6c99380cbf2d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 05:46:46 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- studio/install_llama_prebuilt.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/studio/install_llama_prebuilt.py b/studio/install_llama_prebuilt.py index 5cec3af8c0..ba0ff35598 100644 --- a/studio/install_llama_prebuilt.py +++ b/studio/install_llama_prebuilt.py @@ -1197,9 +1197,7 @@ def latest_upstream_release_tag() -> str: redirect_tag = _resolve_latest_release_tag_via_redirect(UPSTREAM_REPO) if redirect_tag: return redirect_tag - raise RuntimeError( - f"latest release tag was missing from {UPSTREAM_RELEASES_API}" - ) + raise RuntimeError(f"latest release tag was missing from {UPSTREAM_RELEASES_API}") def is_release_tag_like(value: str | None) -> bool: @@ -1231,9 +1229,7 @@ def _needs_dynamic_asset_enumeration(host: HostInfo | None) -> bool: if host is None: return False return bool( - host.is_windows - and host.is_x86_64 - and (host.has_usable_nvidia or host.has_rocm) + host.is_windows and host.is_x86_64 and (host.has_usable_nvidia or host.has_rocm) ) From d8c3784aff44ea8ef9891b1462c8cef138ce55e3 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 31 May 2026 07:05:01 +0000 Subject: [PATCH 3/6] Studio: fail closed on bad redirect tag and report both failures (PR #5886) Harden the tokenless llama.cpp release-redirect fallback: - Guard the redirect-resolved tag with is_release_tag_like so an unexpected redirect target fails closed to the REST/source path instead of building a 404-bound download URL. - When the REST listing and the redirect both fail, raise a chained error that names both causes instead of only the REST 403. - Drop a no-op except branch in the specific-tag path and clarify the synthetic-release comment. Add negative tests: both paths failing, a pinned tag never using the redirect, a malformed redirect target being rejected, and a real REST asset URL taking precedence over the synthetic one. --- .../test_tokenless_release_resolution.py | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/tests/studio/install/test_tokenless_release_resolution.py b/tests/studio/install/test_tokenless_release_resolution.py index 223fada439..3c674db6c0 100644 --- a/tests/studio/install/test_tokenless_release_resolution.py +++ b/tests/studio/install/test_tokenless_release_resolution.py @@ -317,3 +317,114 @@ def test_linux_cpu_latest_prebuilt_via_redirect_when_rest_403(monkeypatch): "https://github.com/ggml-org/llama.cpp/releases/download/" "b9999/llama-b9999-bin-ubuntu-x64.tar.gz" ) + + +# --- negative paths: fail closed and asset precedence ---------------------- + + +def test_resolve_latest_tag_via_redirect_rejects_non_release_tag(monkeypatch): + class _Resp: + def __init__(self, location): + self.headers = {"Location": location} + + def __enter__(self): + return self + + def __exit__(self, *a): + return False + + def fake_build_opener(handler): + class _Op: + def open(self, request, timeout=None): + return _Resp( + "https://github.com/ggml-org/llama.cpp/releases/tag/nightly" + ) + + return _Op() + + monkeypatch.setattr(MOD.urllib.request, "build_opener", fake_build_opener) + # A non b1234 redirect target must fail closed to the REST/source path. + assert ( + MOD._resolve_latest_release_tag_via_redirect("ggml-org/llama.cpp") is None + ) + + +def test_iter_release_payloads_both_paths_fail_raises(monkeypatch): + def boom(repo, max_pages=5): + raise RuntimeError("GitHub API returned 403") + + monkeypatch.setattr(MOD, "github_releases", boom) + monkeypatch.setattr( + MOD, "_resolve_latest_release_tag_via_redirect", lambda repo: None + ) + with pytest.raises(RuntimeError) as excinfo: + list(MOD.iter_release_payloads_by_time(MOD.UPSTREAM_REPO, "", "latest")) + message = str(excinfo.value) + assert "release redirect fallback" in message + assert "also failed" in message + + +def test_iter_release_payloads_pinned_tag_never_uses_redirect(monkeypatch): + def missing(repo, tag): + raise urllib.error.HTTPError( + f"https://api.github.com/repos/{repo}/releases/tags/{tag}", + 404, + "Not Found", + None, + None, + ) + + def listing_403(repo, max_pages=5): + raise RuntimeError("GitHub API returned 403") + + monkeypatch.setattr(MOD, "github_release", missing) + monkeypatch.setattr(MOD, "github_releases", listing_403) + monkeypatch.setattr( + MOD, + "_resolve_latest_release_tag_via_redirect", + lambda repo: (_ for _ in ()).throw(AssertionError("redirect used")), + ) + # A pinned tag is not "latest", so the redirect fast path must never run. + with pytest.raises(RuntimeError): + list(MOD.iter_release_payloads_by_time(MOD.UPSTREAM_REPO, "", "b1234")) + + +def test_direct_release_real_asset_takes_precedence_over_redirect(monkeypatch): + host = _host( + system = "Darwin", + machine = "arm64", + is_windows = False, + is_linux = False, + is_macos = True, + is_x86_64 = False, + is_arm64 = True, + ) + custom_url = "https://cdn.example.test/custom-macos-arm64.tar.gz" + release = { + "tag_name": "b1234", + "assets": [ + { + "name": "llama-b1234-bin-macos-arm64.tar.gz", + "browser_download_url": custom_url, + } + ], + } + monkeypatch.setattr(MOD, "github_releases", lambda repo, max_pages=5: [release]) + monkeypatch.setattr( + MOD, + "fetch_json", + lambda *a, **k: (_ for _ in ()).throw(AssertionError("fetch_json used")), + ) + monkeypatch.setattr( + MOD, + "_resolve_latest_release_tag_via_redirect", + lambda repo: (_ for _ in ()).throw(AssertionError("redirect used")), + ) + plans = MOD.resolve_simple_install_release_plans( + "latest", host, "ggml-org/llama.cpp", "" + ) + assert plans + attempt_urls = [a.url for p in plans for a in p.attempts] + # The real REST asset URL wins; the synthetic redirect URL is additive only. + assert custom_url in attempt_urls + assert all("releases/download/b1234" not in u for u in attempt_urls) From 522b156a3414f4133fca01dbfed8ea577e0011d2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 07:05:28 +0000 Subject: [PATCH 4/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../install/test_tokenless_release_resolution.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/studio/install/test_tokenless_release_resolution.py b/tests/studio/install/test_tokenless_release_resolution.py index 3c674db6c0..77b71ffa4c 100644 --- a/tests/studio/install/test_tokenless_release_resolution.py +++ b/tests/studio/install/test_tokenless_release_resolution.py @@ -335,7 +335,7 @@ def test_resolve_latest_tag_via_redirect_rejects_non_release_tag(monkeypatch): def fake_build_opener(handler): class _Op: - def open(self, request, timeout=None): + def open(self, request, timeout = None): return _Resp( "https://github.com/ggml-org/llama.cpp/releases/tag/nightly" ) @@ -344,13 +344,11 @@ def test_resolve_latest_tag_via_redirect_rejects_non_release_tag(monkeypatch): monkeypatch.setattr(MOD.urllib.request, "build_opener", fake_build_opener) # A non b1234 redirect target must fail closed to the REST/source path. - assert ( - MOD._resolve_latest_release_tag_via_redirect("ggml-org/llama.cpp") is None - ) + assert MOD._resolve_latest_release_tag_via_redirect("ggml-org/llama.cpp") is None def test_iter_release_payloads_both_paths_fail_raises(monkeypatch): - def boom(repo, max_pages=5): + def boom(repo, max_pages = 5): raise RuntimeError("GitHub API returned 403") monkeypatch.setattr(MOD, "github_releases", boom) @@ -374,7 +372,7 @@ def test_iter_release_payloads_pinned_tag_never_uses_redirect(monkeypatch): None, ) - def listing_403(repo, max_pages=5): + def listing_403(repo, max_pages = 5): raise RuntimeError("GitHub API returned 403") monkeypatch.setattr(MOD, "github_release", missing) @@ -409,7 +407,7 @@ def test_direct_release_real_asset_takes_precedence_over_redirect(monkeypatch): } ], } - monkeypatch.setattr(MOD, "github_releases", lambda repo, max_pages=5: [release]) + monkeypatch.setattr(MOD, "github_releases", lambda repo, max_pages = 5: [release]) monkeypatch.setattr( MOD, "fetch_json", From 89127970fab1eddea1b28ceb4954c9f3da71794f Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 31 May 2026 07:13:16 +0000 Subject: [PATCH 5/6] Studio: harden tokenless release redirect fallback (PR #5886) Implement the hardening the added tests cover: - Guard the redirect-resolved tag with is_release_tag_like so an unexpected redirect target fails closed to the REST/source path instead of building a 404-bound download URL. - When the REST listing and the redirect both fail, raise a chained error that names both causes instead of only the REST 403. - Drop a no-op except branch in the specific-tag path and clarify the synthetic-release comment. - Unpack the (requested_tag, plans) return in the asset-precedence test. --- studio/install_llama_prebuilt.py | 17 +++++++++++------ .../test_tokenless_release_resolution.py | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/studio/install_llama_prebuilt.py b/studio/install_llama_prebuilt.py index ba0ff35598..792176bf29 100644 --- a/studio/install_llama_prebuilt.py +++ b/studio/install_llama_prebuilt.py @@ -1169,7 +1169,10 @@ def _resolve_latest_release_tag_via_redirect(repo: str) -> str | None: location = exc.headers.get("Location") if exc.headers else None else: raise - return _tag_from_release_location(location) + tag = _tag_from_release_location(location) + # Accept only upstream-style tags (b1234); any other redirect target + # is unexpected, so fail closed to the REST/source path. + return tag if is_release_tag_like(tag) else None except Exception as exc: last_exc = exc if attempt >= JSON_FETCH_ATTEMPTS or not is_retryable_url_error(exc): @@ -1258,14 +1261,12 @@ def iter_release_payloads_by_time( ) else: raise - except Exception: - raise # Primary: the GitHub REST release listing. Fallback for upstream "latest": # resolve the tag from the github.com release redirect (no api.github.com - # budget spent) and synthesize a release with deterministic asset URLs, so a - # rate-limited (HTTP 403) REST API does not force a source build. Gated to - # upstream single-asset platforms. + # budget spent) and synthesize a release whose sentinel lets the planner + # build deterministic download URLs, so a rate-limited (HTTP 403) REST API + # does not force a source build. Gated to upstream single-asset platforms. redirect_eligible = ( repo == UPSTREAM_REPO and (not requested_tag or requested_tag == "latest") @@ -1295,6 +1296,10 @@ def iter_release_payloads_by_time( "_unsloth_download_repo": repo, } return + # Both REST and the redirect fallback failed; surface both causes. + raise RuntimeError( + f"{exc}; release redirect fallback for {repo} also failed" + ) from exc raise releases.sort(key = release_time_sort_key, reverse = True) for release in releases: diff --git a/tests/studio/install/test_tokenless_release_resolution.py b/tests/studio/install/test_tokenless_release_resolution.py index 77b71ffa4c..989dd7a109 100644 --- a/tests/studio/install/test_tokenless_release_resolution.py +++ b/tests/studio/install/test_tokenless_release_resolution.py @@ -418,7 +418,7 @@ def test_direct_release_real_asset_takes_precedence_over_redirect(monkeypatch): "_resolve_latest_release_tag_via_redirect", lambda repo: (_ for _ in ()).throw(AssertionError("redirect used")), ) - plans = MOD.resolve_simple_install_release_plans( + _requested, plans = MOD.resolve_simple_install_release_plans( "latest", host, "ggml-org/llama.cpp", "" ) assert plans From bbec4f6deb92661201534d3f3dc9340859b46df6 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 31 May 2026 07:36:02 +0000 Subject: [PATCH 6/6] Studio: tidy redirect handler signature and align test import (PR #5886) --- studio/install_llama_prebuilt.py | 3 ++- tests/studio/install/test_tokenless_release_resolution.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/studio/install_llama_prebuilt.py b/studio/install_llama_prebuilt.py index 792176bf29..8b979b092d 100644 --- a/studio/install_llama_prebuilt.py +++ b/studio/install_llama_prebuilt.py @@ -1150,7 +1150,8 @@ def _resolve_latest_release_tag_via_redirect(repo: str) -> str | None: """ class _NoFollowRedirect(urllib.request.HTTPRedirectHandler): - def redirect_request(self, *args, **kwargs): # type: ignore[override] + def redirect_request(self, req, fp, code, msg, headers, newurl): + # Never follow the redirect; read the tag from the 3xx Location. return None url = f"https://github.com/{repo}/releases/latest" diff --git a/tests/studio/install/test_tokenless_release_resolution.py b/tests/studio/install/test_tokenless_release_resolution.py index 989dd7a109..2b824859fd 100644 --- a/tests/studio/install/test_tokenless_release_resolution.py +++ b/tests/studio/install/test_tokenless_release_resolution.py @@ -16,9 +16,11 @@ STUDIO_DIR = ROOT / "studio" if str(STUDIO_DIR) not in sys.path: sys.path.insert(0, str(STUDIO_DIR)) -import install_llama_prebuilt as MOD # noqa: E402 +import install_llama_prebuilt as INSTALL_LLAMA_PREBUILT # noqa: E402 from install_llama_prebuilt import HostInfo # noqa: E402 +MOD = INSTALL_LLAMA_PREBUILT + def _host(**overrides) -> HostInfo: base = dict(