Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/specify_cli/_github_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions tests/test_github_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down