diff --git a/src/specify_cli/authentication/config.py b/src/specify_cli/authentication/config.py index 9f19fbc522..b4a1753d23 100644 --- a/src/specify_cli/authentication/config.py +++ b/src/specify_cli/authentication/config.py @@ -221,12 +221,14 @@ def find_entries_for_url( ) -> list[AuthConfigEntry]: """Return entries whose ``hosts`` match the hostname of *url*.""" # A malformed authority (e.g. an unterminated IPv6 bracket "https://[::1") - # makes urlparse/hostname raise ValueError. Treat that the same as a + # makes urlparse, hostname, or port 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() + parsed = urlparse(url) + hostname = (parsed.hostname or "").lower() + _ = parsed.port except ValueError: return [] if not hostname: diff --git a/tests/test_authentication.py b/tests/test_authentication.py index 6711334a93..97ca1c6ddb 100644 --- a/tests/test_authentication.py +++ b/tests/test_authentication.py @@ -345,7 +345,7 @@ def test_world_readable_warns(self, tmp_path): class TestFindEntriesForUrl: def test_exact_match(self): entry = _github_entry() - result = find_entries_for_url("https://github.com/org/repo", [entry]) + result = find_entries_for_url("https://github.com:443/org/repo", [entry]) assert result == [entry] def test_wildcard_match(self): @@ -409,10 +409,12 @@ def test_empty_url_returns_empty(self): [ "https://[::1", # unterminated ipv6 bracket "https://[not-an-ip]/file", # bracketed non-ip host + "https://github.com:notaport/x", # non-numeric port + "https://github.com:99999/x", # out-of-range port ], ) def test_malformed_url_returns_empty(self, url): - # A malformed authority makes urlparse/hostname raise ValueError. + # A malformed authority makes urlparse, hostname, or port 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.