fix: reject host-less catalog URLs in base and preset validators (#3209) (#3227)

`CatalogStackBase._validate_catalog_url` (inherited by `IntegrationCatalog`)
and `PresetCatalog._validate_catalog_url` checked `parsed.netloc`, which is
truthy for host-less URLs like `https://:8080` (port only) or `https://user@`
(userinfo only). Such URLs slipped past validation despite the error message
promising "a valid URL with a host", then failed later with a confusing fetch
error.

Switch both validators to `parsed.hostname` (None for those inputs), matching
the workflow, step, and bundler catalog validators that already do this.

Add regression tests covering port-only and userinfo-only URLs for both
validators.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Noor ul ain
2026-06-30 17:18:39 +05:00
committed by GitHub
parent 8025481eca
commit cb7c36c95b
4 changed files with 14 additions and 12 deletions

View File

@@ -70,16 +70,17 @@ class TestCatalogURLValidation:
@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)

View File

@@ -1427,14 +1427,15 @@ class TestPresetCatalog:
@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