Skip to content
Open
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
7 changes: 7 additions & 0 deletions src/specify_cli/presets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4165,6 +4165,13 @@ def _validate_catalog_url(self, url: str) -> None:
try:
parsed = urlparse(url)
hostname = parsed.hostname
# Accessing ``port`` performs urllib's syntax/range validation;
# ``hostname`` alone does not, so a non-numeric or out-of-range
# port would otherwise pass validation here and only fail later,
# at fetch time, as a raw error this function does not translate
# into PresetValidationError. Mirrors specify_cli.catalogs and
# bundler/services/adapters.py's copy of this same guard.
_ = parsed.port
except ValueError:
raise PresetValidationError(f"Catalog URL is malformed: {url}") from None
is_localhost = hostname in ("localhost", "127.0.0.1", "::1")
Expand Down
19 changes: 19 additions & 0 deletions tests/test_presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2086,6 +2086,25 @@ def test_validate_catalog_url_malformed_rejected(self, project_dir):
with pytest.raises(PresetValidationError, match="malformed"):
catalog._validate_catalog_url("https://[::1")

def test_validate_catalog_url_out_of_range_port_rejected(self, project_dir):
"""An out-of-range port raises ValueError lazily on ``.port`` access.

``urlparse(...).hostname`` alone does not validate the port, so
without a ``_ = parsed.port`` probe inside the try/except, a URL like
``https://example.com:99999/catalog.json`` sails through this
validator and only fails later, at fetch time, with a raw
untranslated error instead of a clean ``PresetValidationError``. The
sibling ``preset add --from <url>`` download-URL guard already
catches this shape (see
``test_preset_add_from_url_out_of_range_port_exits_cleanly``); this
catalog-source-URL validator had drifted from it and from the
original guard in ``specify_cli.catalogs``/
``bundler/services/adapters.py``.
"""
catalog = PresetCatalog(project_dir)
with pytest.raises(PresetValidationError, match="malformed"):
catalog._validate_catalog_url("https://example.com:99999/catalog.json")

def test_env_var_catalog_url(self, project_dir, monkeypatch):
"""Test catalog URL from environment variable."""
monkeypatch.setenv("SPECKIT_PRESET_CATALOG_URL", "https://custom.example.com/catalog.json")
Expand Down