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
2 changes: 1 addition & 1 deletion src/specify_cli/catalogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def _validate_catalog_url(cls, url: str) -> None:
)
# Check hostname, not netloc: netloc is truthy for host-less URLs like
# "https://:8080" or "https://user@", so the host guarantee this error
# promises would not actually hold. hostname is None in those cases.
# promises would not actually hold. hostname is None in those cases (#3209).
if not parsed.hostname:
raise cls._error("Catalog URL must be a valid URL with a host.")

Expand Down
2 changes: 1 addition & 1 deletion src/specify_cli/presets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1863,7 +1863,7 @@ def _validate_catalog_url(self, url: str) -> None:
)
# Check hostname, not netloc: netloc is truthy for host-less URLs like
# "https://:8080" or "https://user@", so the host guarantee this error
# promises would not actually hold. hostname is None in those cases.
# promises would not actually hold. hostname is None in those cases (#3209).
if not parsed.hostname:
raise PresetValidationError(
"Catalog URL must be a valid URL with a host."
Expand Down
11 changes: 6 additions & 5 deletions tests/integrations/test_integration_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,17 @@ def test_missing_host_rejected(self):
@pytest.mark.parametrize(
"url",
[
"https://:8080", # port only, no host
"https://:0", # port only, no host
"https://user@", # userinfo only, no host
"https://user:pw@", # userinfo only, no host
"https://:8080", # port only, no host
"https://:8080/catalog.json", # port only, with path
"https://:0", # port only, no host
"https://user@", # userinfo only, no host
"https://user:pass@", # userinfo only, no host
],
)
def test_hostless_url_with_truthy_netloc_rejected(self, url):
# These have a truthy netloc (":8080", "user@") but no actual host,
# so a netloc-based check would wrongly accept them despite the
# "valid URL with a host" promise. hostname is None for all of them.
# "valid URL with a host" promise. hostname is None for all of them (#3209).
with pytest.raises(IntegrationCatalogError, match="valid URL"):
IntegrationCatalog._validate_catalog_url(url)

Expand Down
11 changes: 6 additions & 5 deletions tests/test_presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1427,14 +1427,15 @@ def test_validate_catalog_url_localhost_http_allowed(self, project_dir):
@pytest.mark.parametrize(
"url",
[
"https://:8080", # port only, no host
"https://:0", # port only, no host
"https://user@", # userinfo only, no host
"https://user:pw@", # userinfo only, no host
"https://:8080", # port only, no host
"https://:8080/catalog.json", # port only, with path
"https://:0", # port only, no host
"https://user@", # userinfo only, no host
"https://user:pass@", # userinfo only, no host
],
)
def test_validate_catalog_url_hostless_rejected(self, project_dir, url):
"""Reject host-less URLs whose netloc is truthy but hostname is None.
"""Reject host-less URLs whose netloc is truthy but hostname is None (#3209).
``urlparse('https://:8080').netloc`` is ``':8080'`` (truthy) but its
``hostname`` is ``None``, so a netloc-based check would accept a URL
Expand Down