mirror of
https://github.com/github/spec-kit.git
synced 2026-08-15 14:02:04 +02:00
fix(bundle): surface a clean BundlerError on a malformed bundle download URL (#3586)
`_download_manifest` and its `_require_https` helper parsed the catalog entry's `download_url` with an unguarded `urlparse(url)`. A malformed authority — e.g. an unclosed IPv6 bracket like `https://[::1` — makes `urlparse` (or `.hostname` on older Pythons) raise a raw `ValueError`. The three `bundle` CLI commands (`info`, `install`, `update`) only catch `BundlerError`, so that `ValueError` escaped as an uncaught traceback. Wrap both parse sites in the same `try/except ValueError -> BundlerError` guard already used by the sibling `_validate_remote_url` (and established by the merged catalog-URL fix #3576), so a bad `download_url` reports a clean, actionable error in every mode. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b17c70d6f0
commit
0d780162f9
@@ -765,7 +765,16 @@ def _download_manifest(resolved, *, offline: bool):
|
||||
f"Catalog entry '{resolved.entry.id}' has no download_url; cannot resolve "
|
||||
"its manifest."
|
||||
)
|
||||
parsed = urlparse(url)
|
||||
# A malformed authority (e.g. an unclosed IPv6 bracket ``https://[::1``)
|
||||
# makes urlparse raise ValueError. Surface it as the documented
|
||||
# BundlerError, like the sibling ``_validate_remote_url``, rather than
|
||||
# leaking a raw ValueError past the callers, which only catch BundlerError.
|
||||
try:
|
||||
parsed = urlparse(url)
|
||||
except ValueError:
|
||||
raise BundlerError(
|
||||
f"Catalog entry '{resolved.entry.id}' has a malformed download_url: {url}"
|
||||
) from None
|
||||
scheme = parsed.scheme.lower()
|
||||
|
||||
# ``file://`` URLs and bare filesystem paths (including Windows drive paths
|
||||
@@ -802,8 +811,17 @@ def _download_manifest(resolved, *, offline: bool):
|
||||
def _require_https(label: str, url: str) -> None:
|
||||
from urllib.parse import urlparse
|
||||
|
||||
parsed = urlparse(url)
|
||||
is_localhost = parsed.hostname in ("localhost", "127.0.0.1", "::1")
|
||||
# urlparse / hostname access raise ValueError on a malformed authority;
|
||||
# keep the documented BundlerError contract (older Pythons surface this via
|
||||
# the .hostname access below rather than at the urlparse call).
|
||||
try:
|
||||
parsed = urlparse(url)
|
||||
hostname = parsed.hostname
|
||||
except ValueError:
|
||||
raise BundlerError(
|
||||
f"Refusing to download {label}: 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 BundlerError(
|
||||
f"Refusing to download {label} over non-HTTPS URL: {url}"
|
||||
|
||||
Reference in New Issue
Block a user