fix(auth): return no matches, not raw ValueError, for a malformed URL (#3437)

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.
This commit is contained in:
Quratulain-bilal
2026-07-10 23:45:44 +05:00
committed by GitHub
parent 14fa3ada08
commit 74d03a2814
2 changed files with 23 additions and 1 deletions

View File

@@ -196,7 +196,15 @@ def find_entries_for_url(
url: str, entries: list[AuthConfigEntry]
) -> list[AuthConfigEntry]:
"""Return entries whose ``hosts`` match the hostname of *url*."""
hostname = (urlparse(url).hostname or "").lower()
# A malformed authority (e.g. an unterminated IPv6 bracket "https://[::1")
# makes urlparse/hostname raise ValueError. Treat that the same as a
# host-less URL: no entry can match, so return no matches rather than
# leaking a raw ValueError out of the shared HTTP client (build_request /
# open_url call this before any URL validation).
try:
hostname = (urlparse(url).hostname or "").lower()
except ValueError:
return []
if not hostname:
return []
return [

View File

@@ -315,6 +315,20 @@ class TestFindEntriesForUrl:
def test_empty_url_returns_empty(self):
assert find_entries_for_url("", [_github_entry()]) == []
@pytest.mark.parametrize(
"url",
[
"https://[::1", # unterminated ipv6 bracket
"https://[not-an-ip]/file", # bracketed non-ip host
],
)
def test_malformed_url_returns_empty(self, url):
# A malformed authority makes urlparse/hostname raise ValueError.
# Since no entry can match such a URL, this must return no matches
# (like a host-less URL) rather than leaking a raw ValueError out of
# the shared HTTP client.
assert find_entries_for_url(url, [_github_entry()]) == []
def test_empty_entries_returns_empty(self):
assert find_entries_for_url("https://github.com/org/repo", []) == []