Skip to content

fix(bundle): surface a clean BundlerError on a malformed bundle download URL#3586

Merged
mnriem merged 1 commit into
github:mainfrom
chuenchen309:fix/bundle-malformed-download-url
Jul 17, 2026
Merged

fix(bundle): surface a clean BundlerError on a malformed bundle download URL#3586
mnriem merged 1 commit into
github:mainfrom
chuenchen309:fix/bundle-malformed-download-url

Conversation

@chuenchen309

Copy link
Copy Markdown
Contributor

Description

_download_manifest (and its _require_https helper) in
src/specify_cli/commands/bundle/__init__.py 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 Python versions) raise a raw ValueError.

The three bundle CLI commands (info, install, update) wrap
_download_manifest in except BundlerError only, so that ValueError
escaped as an uncaught traceback instead of the clean error the rest of the
bundle subsystem produces.

This wraps both parse sites in the same try/except ValueError -> BundlerError
guard already used by the sibling _validate_remote_url
(bundler/services/adapters.py), whose comment names this exact https://[::1
case, and established by the merged catalog-URL fix #3576. _require_https is
guarded too because on older Pythons the ValueError surfaces at .hostname
rather than at urlparse, so both are needed to keep the contract across the
CI Python matrix.

Repro on main (no network reached — offline=True):

from types import SimpleNamespace
from specify_cli.commands.bundle import _download_manifest
resolved = SimpleNamespace(entry=SimpleNamespace(id="b", download_url="https://[::1"))
_download_manifest(resolved, offline=True)   # main: ValueError: Invalid IPv6 URL
                                             # fixed: BundlerError: ... malformed download_url

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest
  • Tested with a sample project (if applicable)

I ran the affected-area tests rather than the full (slow, integration-heavy)
suite:

  • New unit test tests/unit/test_bundle_download_url.py (4 cases) covering both
    _download_manifest and _require_https against https://[::1 and
    https://[not-an-ip]/…. It fails on main (raw ValueError) and passes with
    this change (I verified red→green by stashing the fix).
  • tests/contract/test_bundle_cli.py + tests/unit/test_bundler_adapters.py
    (the direct CLI callers and the guarded sibling) — 45 passed, no
    regression. The guard is a no-op for well-formed URLs (urlparse doesn't
    raise), so existing valid-URL paths are unchanged.
  • ruff check src/ clean.

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (describe below)

This contribution is fully AI-authored and autonomous (Claude Code, acting on
this account). An AI found the bug, wrote and ran the repro, wrote the fix and
the tests, and wrote this description; the human operator of this account did
not hand-review the diff or run the tests. The verification above is real and
re-runnable from the diff — it was just done by the AI, not a person. The fix
mirrors an existing guarded sibling rather than inventing a new pattern. If
autonomous AI contributions aren't something you want to accept, say so and
I'll close this.

…oad URL

`_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 github#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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds domain-specific error handling for malformed bundle download URLs, preventing raw ValueError tracebacks.

Changes:

  • Converts URL parsing failures into clean BundlerError messages.
  • Adds regression coverage for malformed IPv6 authorities.
Show a summary per file
File Description
src/specify_cli/commands/bundle/__init__.py Guards URL parsing and hostname validation.
tests/unit/test_bundle_download_url.py Tests malformed URLs across both affected helpers.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Medium

@mnriem
mnriem merged commit 0d78016 into github:main Jul 17, 2026
12 checks passed
@mnriem

mnriem commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants