From 74636cc37064c13b5a8d0d54051e6b6fd6b9408d Mon Sep 17 00:00:00 2001 From: jawwad-ali Date: Tue, 7 Jul 2026 01:31:27 +0500 Subject: [PATCH] fix(github-http): return None on malformed GHES port instead of raising MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit resolve_github_release_asset_api_url's is_ghes branch built the authority with 'parsed.port', which raises ValueError on a malformed port (e.g. host:notaport). The function's contract is to resolve or return None, never raise — every other unresolvable case returns None. An allowlisted GHES host with a bad port therefore crashed the caller. Read parsed.port defensively and return None on ValueError. Co-Authored-By: Claude Fable 5 --- src/specify_cli/_github_http.py | 9 ++++++++- tests/test_github_http.py | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/specify_cli/_github_http.py b/src/specify_cli/_github_http.py index 31f6046395..1cfb18f03f 100644 --- a/src/specify_cli/_github_http.py +++ b/src/specify_cli/_github_http.py @@ -127,7 +127,14 @@ def _is_asset_path(segments: list[str]) -> bool: if hostname == "github.com": api_base = "https://api.github.com" elif is_ghes: - authority = hostname if parsed.port is None else f"{hostname}:{parsed.port}" + # ``parsed.port`` raises ValueError on a malformed port (e.g. + # ``host:notaport``); the function's contract is to return None for + # anything it can't resolve, not to raise. + try: + port = parsed.port + except ValueError: + return None + authority = hostname if port is None else f"{hostname}:{port}" api_base = f"{parsed.scheme}://{authority}/api/v3" else: return None diff --git a/tests/test_github_http.py b/tests/test_github_http.py index cd1b651aaa..a03fe9186f 100644 --- a/tests/test_github_http.py +++ b/tests/test_github_http.py @@ -233,6 +233,23 @@ def recording_open(url, timeout=None, extra_headers=None): assert result is None assert called == [] + def test_returns_none_on_malformed_ghes_port(self): + """A malformed port on an allowlisted GHES 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://ghes.example:notaport/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