fix: validate URL scheme in build_github_request#2449
fix: validate URL scheme in build_github_request#2449ayesha-aziz123 wants to merge 6 commits intogithub:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR improves specify_cli._github_http.build_github_request() by validating the url argument up-front so invalid/empty URLs fail fast with a clear ValueError, rather than surfacing confusing errors from deep inside urllib.
Changes:
- Add early
ValueErrorvalidation for empty/whitespace-only URLs and non-HTTP(S) schemes inbuild_github_request(). - Add a new pytest module covering URL validation and Authorization header behavior for GitHub vs non-GitHub hosts.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/_github_http.py |
Adds early URL validation before constructing a urllib.request.Request. |
tests/test_github_http.py |
Adds test coverage for URL validation and token-based Authorization header behavior. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 1
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 1
mnriem
left a comment
There was a problem hiding this comment.
Please address Copilot feedback
There was a problem hiding this comment.
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 2
|
Please address Copilot feedback |
There was a problem hiding this comment.
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (1)
tests/test_github_http.py:75
- There is trailing whitespace on the blank line here (line appears to contain spaces). Please remove the extra whitespace to avoid lint/format churn.
req = build_github_request("https://github.com/github/spec-kit")
assert req.get_header("Authorization") is None
def test_missing_hostname_raises_value_error(self):
- Files reviewed: 2/2 changed files
- Comments generated: 2
| if not url or not url.strip(): | ||
| raise ValueError("url must not be empty") | ||
| url = url.strip() | ||
| parsed = urlparse(url) | ||
| if parsed.scheme not in {"http", "https"}: | ||
| 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}") |
| import os | ||
| from unittest.mock import patch | ||
| import pytest | ||
|
|
||
| from specify_cli._github_http import ( | ||
| build_github_request, | ||
| ) |
|
Please address Copilot feedback |
4b4360e to
64d2624
Compare
|
@mnriem Thanks, I’ve addressed the feedback and updated the PR. CI should be passing now—please take another look. |
There was a problem hiding this comment.
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (1)
tests/test_github_http.py:74
- Most existing tests in this repo use pytest’s
monkeypatchfixture for environment variables (e.g., the GitHub token tests intests/test_extensions.py). Usingpatch.dict(os.environ, ...)here is slightly inconsistent and (withoutclear=True) can allow unrelated env vars to leak into the test context. Consider switching these env var tests tomonkeypatch.setenv/delenvfor consistency and isolation.
def test_github_token_added_for_github_host(self):
"""Authorization header is set when GITHUB_TOKEN is present."""
with patch.dict(os.environ, {"GITHUB_TOKEN": "test-token", "GH_TOKEN": ""}):
req = build_github_request("https://github.com/github/spec-kit")
assert req.get_header("Authorization") == "Bearer test-token"
def test_gh_token_used_as_fallback(self):
"""GH_TOKEN is used when GITHUB_TOKEN is absent."""
with patch.dict(os.environ, {"GITHUB_TOKEN": "", "GH_TOKEN": "fallback-token"}):
req = build_github_request("https://github.com/github/spec-kit")
assert req.get_header("Authorization") == "Bearer fallback-token"
def test_no_auth_header_for_non_github_host(self):
"""Authorization header must NOT be set for non-GitHub URLs."""
with patch.dict(os.environ, {"GITHUB_TOKEN": "test-token"}):
req = build_github_request("https://example.com/file")
assert req.get_header("Authorization") is None
def test_no_auth_header_when_no_token(self):
"""No Authorization header when no token is set in environment."""
with patch.dict(os.environ, {}, clear=True):
req = build_github_request("https://github.com/github/spec-kit")
assert req.get_header("Authorization") is None
- Files reviewed: 2/2 changed files
- Comments generated: 2
| if not url or not url.strip(): | ||
| raise ValueError("url must not be empty") | ||
| url = url.strip() | ||
| parsed = urlparse(url) |
| class TestBuildGithubRequest: | ||
| """Tests for build_github_request() URL validation and auth handling.""" |
|
Please address Copilot feedback |
|
Addressed all Copilot feedback. Ready for re-review. |
What does this PR do?
build_github_request()accepted any string as aurlparameter andpassed it directly to
urllib.request.Request(). When an empty stringor a non-HTTP URL was passed, the error originated deep inside urllib
with a confusing message (
unknown url type: '') rather than at thecall site with a clear explanation.
This PR adds early validation that raises a descriptive
ValueErrorbefore the request object is constructed.
Changes
ValueError("url must not be empty")whenurlis empty or whitespace-onlyValueErrorwhenurldoes not start withhttp://orhttps://tests/test_github_http.pycovering URL validation and auth header behaviourCloses
Fixes the confusing
unknown url typeerror raised by urllib internalswhen an invalid URL is passed to
build_github_request().Testing
uv run python -m pytest tests/test_github_http.py -v # 10 passed in 0.90sAI Disclosure
I used Claude (Anthropic) to help identify this issue via static analysis of the repository.
The fix and tests were manually verified and applied by me.