Summary
Two catalog URL validators reject host-less URLs incorrectly: they check parsed.netloc instead of parsed.hostname. netloc is truthy for URLs like https://:8080 (port only) or https://user@ (userinfo only), which have no actual host. So these slip past validation even though the error message promises "a valid URL with a host".
The workflow, step, and bundler validators already use parsed.hostname (which is None for these inputs), so this is an inconsistency between sibling validators - the base/preset ones are the stragglers.
Affected code
src/specify_cli/catalogs.py CatalogStackBase._validate_catalog_url (the shared base; IntegrationCatalog inherits it)
src/specify_cli/presets/__init__.py PresetCatalog._validate_catalog_url
Reproduction
from urllib.parse import urlparse
p = urlparse("https://:8080")
print(bool(p.netloc), p.hostname) # True None <- netloc truthy, no host
With the current code, _validate_catalog_url("https://:8080") passes (no error raised), then a later fetch fails with a confusing message instead of being rejected up front.
Correct behavior
Already used elsewhere in the same codebase - workflows/catalog.py, the step catalog, and bundler/commands_impl/catalog_config.py all check parsed.hostname. bundler even has a comment explaining why .hostname is the right field. The fix aligns the two stragglers with that.
note: i used an ai assistant to help investigate and write this up.
Summary
Two catalog URL validators reject host-less URLs incorrectly: they check
parsed.netlocinstead ofparsed.hostname.netlocis truthy for URLs likehttps://:8080(port only) orhttps://user@(userinfo only), which have no actual host. So these slip past validation even though the error message promises "a valid URL with a host".The workflow, step, and bundler validators already use
parsed.hostname(which isNonefor these inputs), so this is an inconsistency between sibling validators - the base/preset ones are the stragglers.Affected code
src/specify_cli/catalogs.pyCatalogStackBase._validate_catalog_url(the shared base;IntegrationCataloginherits it)src/specify_cli/presets/__init__.pyPresetCatalog._validate_catalog_urlReproduction
With the current code,
_validate_catalog_url("https://:8080")passes (no error raised), then a later fetch fails with a confusing message instead of being rejected up front.Correct behavior
Already used elsewhere in the same codebase -
workflows/catalog.py, the step catalog, andbundler/commands_impl/catalog_config.pyall checkparsed.hostname.bundlereven has a comment explaining why.hostnameis the right field. The fix aligns the two stragglers with that.note: i used an ai assistant to help investigate and write this up.