Skip to content
Merged
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
3 changes: 3 additions & 0 deletions src/specify_cli/_github_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def build_github_request(url: str) -> urllib.request.Request:
ValueError: If ``url`` is empty or whitespace-only.
ValueError: If ``url`` does not use the ``http`` or ``https`` scheme.
ValueError: If ``url`` does not include a hostname.
ValueError: If ``url`` includes a malformed explicit port.
"""
headers: Dict[str, str] = {}
url = url.strip()
Expand All @@ -49,6 +50,8 @@ def build_github_request(url: str) -> urllib.request.Request:
raise ValueError(f"url must start with http:// or https://, got: {url!r}")
if not parsed.hostname:
raise ValueError(f"url must include a hostname, got: {url!r}")
# Accessing ``port`` validates any explicit port before request construction.
parsed.port
github_token = (os.environ.get("GITHUB_TOKEN") or "").strip()
gh_token = (os.environ.get("GH_TOKEN") or "").strip()
token = github_token or gh_token or None
Expand Down
18 changes: 18 additions & 0 deletions tests/test_github_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ def test_ftp_url_raises_value_error(self):
with pytest.raises(ValueError, match="url must start with http"):
build_github_request("ftp://github.com/file.zip")

@pytest.mark.parametrize(
"url", ["https://github.com:notaport/file", "https://github.com:65536/file"]
)
def test_malformed_explicit_port_raises_before_request_construction(self, url):
"""Malformed explicit ports are rejected before creating a Request."""
with patch("specify_cli._github_http.urllib.request.Request") as request:
with pytest.raises(ValueError):
build_github_request(url)
request.assert_not_called()

# --- Valid URL Tests ---

def test_valid_https_url_returns_request(self):
Expand All @@ -54,6 +64,14 @@ def test_valid_http_url_returns_request(self):
req = build_github_request("http://example.com/file")
assert req.full_url == "http://example.com/file"

def test_valid_explicit_port_retains_url_method_and_github_auth(self):
"""A valid explicit port retains normal GitHub request behavior."""
with patch.dict(os.environ, {"GITHUB_TOKEN": "test-token", "GH_TOKEN": ""}):
req = build_github_request("https://github.com:8443/github/spec-kit")
assert req.full_url == "https://github.com:8443/github/spec-kit"
assert req.get_method() == "GET"
assert req.get_header("Authorization") == "Bearer test-token"

# --- Auth Header Tests ---

def test_github_token_added_for_github_host(self):
Expand Down