Skip to content

Commit a307894

Browse files
jawwad-aliclaude
andauthored
fix(github-http): return None on malformed GHES port instead of raising (#3379)
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 <noreply@anthropic.com>
1 parent 10d4bca commit a307894

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

‎src/specify_cli/_github_http.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,14 @@ def _is_asset_path(segments: list[str]) -> bool:
127127
if hostname == "github.com":
128128
api_base = "https://api.github.com"
129129
elif is_ghes:
130-
authority = hostname if parsed.port is None else f"{hostname}:{parsed.port}"
130+
# ``parsed.port`` raises ValueError on a malformed port (e.g.
131+
# ``host:notaport``); the function's contract is to return None for
132+
# anything it can't resolve, not to raise.
133+
try:
134+
port = parsed.port
135+
except ValueError:
136+
return None
137+
authority = hostname if port is None else f"{hostname}:{port}"
131138
api_base = f"{parsed.scheme}://{authority}/api/v3"
132139
else:
133140
return None

‎tests/test_github_http.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,23 @@ def recording_open(url, timeout=None, extra_headers=None):
233233
assert result is None
234234
assert called == []
235235

236+
def test_returns_none_on_malformed_ghes_port(self):
237+
"""A malformed port on an allowlisted GHES host returns None, not a
238+
ValueError (contract: resolve or return None, never raise)."""
239+
called = []
240+
241+
def open_never(url, timeout=None, extra_headers=None):
242+
called.append(url)
243+
raise AssertionError("open_url_fn must not be called")
244+
245+
result = resolve_github_release_asset_api_url(
246+
"https://ghes.example:notaport/o/r/releases/download/v1/ext.zip",
247+
open_never,
248+
github_hosts=("ghes.example",),
249+
)
250+
assert result is None
251+
assert called == []
252+
236253
def test_passthrough_for_unlisted_ghes_api_asset_url(self):
237254
"""A direct GHES /api/v3 asset URL passes through even when the host is
238255
not allowlisted: passthrough issues no API request, and the download

0 commit comments

Comments
 (0)