Skip to content

Commit 3d7955f

Browse files
fix(auth): return no matches, not raw ValueError, for a malformed URL
find_entries_for_url did (urlparse(url).hostname or "").lower() unguarded. a malformed authority (e.g. an unterminated ipv6 bracket "https://[::1") makes urlparse/hostname raise ValueError, so instead of the empty list the function already returns for a host-less url, a raw ValueError leaked out of the shared http client (build_request / open_url call this before any url validation). no auth entry can match such a url, so treat it like the host-less case and return no matches. added a regression test over an unterminated bracket and a bracketed non-ip host; confirmed it fails on the pre-fix code.
1 parent 3f7392a commit 3d7955f

2 files changed

Lines changed: 23 additions & 1 deletion

File tree

src/specify_cli/authentication/config.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,15 @@ def find_entries_for_url(
196196
url: str, entries: list[AuthConfigEntry]
197197
) -> list[AuthConfigEntry]:
198198
"""Return entries whose ``hosts`` match the hostname of *url*."""
199-
hostname = (urlparse(url).hostname or "").lower()
199+
# A malformed authority (e.g. an unterminated IPv6 bracket "https://[::1")
200+
# makes urlparse/hostname raise ValueError. Treat that the same as a
201+
# host-less URL: no entry can match, so return no matches rather than
202+
# leaking a raw ValueError out of the shared HTTP client (build_request /
203+
# open_url call this before any URL validation).
204+
try:
205+
hostname = (urlparse(url).hostname or "").lower()
206+
except ValueError:
207+
return []
200208
if not hostname:
201209
return []
202210
return [

tests/test_authentication.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,20 @@ def test_no_match_for_lookalike_host(self):
315315
def test_empty_url_returns_empty(self):
316316
assert find_entries_for_url("", [_github_entry()]) == []
317317

318+
@pytest.mark.parametrize(
319+
"url",
320+
[
321+
"https://[::1", # unterminated ipv6 bracket
322+
"https://[not-an-ip]/file", # bracketed non-ip host
323+
],
324+
)
325+
def test_malformed_url_returns_empty(self, url):
326+
# A malformed authority makes urlparse/hostname raise ValueError.
327+
# Since no entry can match such a URL, this must return no matches
328+
# (like a host-less URL) rather than leaking a raw ValueError out of
329+
# the shared HTTP client.
330+
assert find_entries_for_url(url, [_github_entry()]) == []
331+
318332
def test_empty_entries_returns_empty(self):
319333
assert find_entries_for_url("https://github.com/org/repo", []) == []
320334

0 commit comments

Comments
 (0)