mirror of
https://github.com/github/spec-kit.git
synced 2026-07-14 05:32:07 +08:00
fix(catalogs): raise catalog error, not raw ValueError, on a malformed URL (#3435)
CatalogStackBase._validate_catalog_url read parsed.hostname, which raises ValueError on a malformed authority (e.g. an unclosed ipv6 bracket "https://[::1"). every other reject path raises the class catalog error, so the raw ValueError leaked to the caller. wrap the parse + hostname access and convert ValueError to the normal error via cls._error. twin of the bundler fix in adapters._validate_remote_url.
This commit is contained in:
@@ -71,8 +71,12 @@ class CatalogStackBase:
|
||||
"""Validate that a catalog URL uses HTTPS, except localhost HTTP."""
|
||||
from urllib.parse import urlparse
|
||||
|
||||
parsed = urlparse(url)
|
||||
is_localhost = parsed.hostname in ("localhost", "127.0.0.1", "::1")
|
||||
try:
|
||||
parsed = urlparse(url)
|
||||
hostname = parsed.hostname
|
||||
except ValueError:
|
||||
raise cls._error(f"Catalog URL is malformed: {url}") from None
|
||||
is_localhost = hostname in ("localhost", "127.0.0.1", "::1")
|
||||
if parsed.scheme != "https" and not (parsed.scheme == "http" and is_localhost):
|
||||
raise cls._error(
|
||||
f"Catalog URL must use HTTPS (got {parsed.scheme}://). "
|
||||
@@ -81,7 +85,7 @@ class CatalogStackBase:
|
||||
# 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 (#3209).
|
||||
if not parsed.hostname:
|
||||
if not hostname:
|
||||
raise cls._error("Catalog URL must be a valid URL with a host.")
|
||||
|
||||
def _load_catalog_config(self, config_path: Path) -> list[CatalogEntry] | None:
|
||||
|
||||
@@ -84,6 +84,20 @@ class TestCatalogURLValidation:
|
||||
with pytest.raises(IntegrationCatalogError, match="valid URL"):
|
||||
IntegrationCatalog._validate_catalog_url(url)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"url",
|
||||
[
|
||||
"https://[::1", # unclosed ipv6 bracket
|
||||
"https://[not-an-ip]/c.json", # bracketed non-ip host
|
||||
],
|
||||
)
|
||||
def test_malformed_url_rejected_cleanly(self, url):
|
||||
# A malformed authority makes urlparse/hostname raise ValueError. The
|
||||
# validator must turn that into its normal catalog error, not leak a
|
||||
# raw ValueError to the caller.
|
||||
with pytest.raises(IntegrationCatalogError, match="malformed"):
|
||||
IntegrationCatalog._validate_catalog_url(url)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# IntegrationCatalog — active catalogs
|
||||
|
||||
Reference in New Issue
Block a user