fix(github-http): return None on malformed host in resolve_github_release_asset_api_url (#3715)

Accessing the parsed authority (via urlparse/.hostname) raises ValueError
on a malformed bracketed host, e.g. https://[not-an-ip]/..., mirroring
the existing .port guard below. download_url is server-controlled (a
catalog download_url payload), so the function's resolve-or-return-None
contract must hold rather than leaking a raw traceback to the caller.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Noor ul ain
2026-07-24 19:58:24 +05:00
committed by GitHub
parent 391cc0dff8
commit 36754522f7
2 changed files with 28 additions and 2 deletions

View File

@@ -102,8 +102,17 @@ def resolve_github_release_asset_api_url(
from specify_cli._download_security import read_response_limited
parsed = urlparse(download_url)
hostname = (parsed.hostname or "").lower()
# Accessing ``.hostname`` (like ``.port`` below) raises ValueError on a
# malformed authority, e.g. an invalid bracketed IPv6 host
# ``https://[not-an-ip]/...``. The function's contract is to return None for
# anything it can't resolve, not to raise, so guard the read. ``download_url``
# is server-controlled here (a catalog ``download_url`` payload), so a
# malformed value must not leak a raw traceback past the caller.
try:
parsed = urlparse(download_url)
hostname = (parsed.hostname or "").lower()
except ValueError:
return None
parts = [unquote(part) for part in parsed.path.strip("/").split("/")]
is_ghes = (

View File

@@ -292,6 +292,23 @@ class TestResolveGitHubReleaseAssetApiUrl:
assert result is None
assert called == []
def test_returns_none_on_malformed_host(self):
"""A malformed authority (e.g. an invalid bracketed IPv6 host) returns
None, not a ValueError (contract: resolve or return None, never raise)."""
called = []
def open_never(url, timeout=None, extra_headers=None):
called.append(url)
raise AssertionError("open_url_fn must not be called")
result = resolve_github_release_asset_api_url(
"https://[not-an-ip]/o/r/releases/download/v1/ext.zip",
open_never,
github_hosts=("ghes.example",),
)
assert result is None
assert called == []
def test_passthrough_for_unlisted_ghes_api_asset_url(self):
"""A direct GHES /api/v3 asset URL passes through even when the host is
not allowlisted: passthrough issues no API request, and the download