Commit cce47f6
fix(cli): guard lazy .hostname ValueError in extension/preset add --from (#3651)
* fix(cli): guard lazy .hostname ValueError in extension/preset add --from
`extension add --from <url>` and `preset add --from <url>` validated the URL
by reading `parsed.hostname` OUTSIDE their `try/except ValueError` guards. A
bracketed-but-invalid IPv6 authority (e.g. "https://[not-an-ip]/x.zip") parses
cleanly under urlparse() on Python < 3.14 and only raises ValueError lazily on
the first .hostname access. On the interpreters spec-kit supports (>=3.11) that
raw ValueError leaked past the CLI, printing an uncaught traceback instead of
the clean "Invalid URL" error. (The raise moved eager into urlparse() only in
3.14.) Same bug class as the catalog/download fixes #3433/#3435/#3437/#3577.
- extensions/_commands.py: read parsed.hostname inside the existing try and
reuse it for the localhost check.
- presets/_commands.py: guard the up-front `urlparse(from_url).hostname` read
(preserves the "Invalid URL" message), and harden the nested
`_is_allowed_download_url` to take a URL string and parse+read .hostname
inside its own try/except -> returns False on malformed input. This also
covers the redirect-validator and final-URL (post-redirect) checks, where the
URL is server-controlled.
Regression tests for each command: a bracketed-non-IP URL, plus a monkeypatched
lazy-.hostname raiser that reproduces the pre-3.14 shape independently of the
running interpreter (fails with a raw ValueError before the fix, verified via
test-the-test).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* fix(cli): address Copilot review on --from URL guard comments/tests
Copilot's review on #3651 flagged two accuracy problems:
1. The guard comments asserted a specific (and incorrect) CPython version
history -- that "https://[not-an-ip]/..." parses cleanly under urlparse()
on Python < 3.14 and only raises ValueError lazily on the first .hostname
access. In fact the eager bracketed-host check (gh-103848, CVE-2024-11168)
was backported to the 3.11 branch and shipped in 3.11.4, so on every
interpreter spec-kit supports (>=3.11) that URL is rejected eagerly at
urlparse(). Reworded the three source comments to state the guard as a
defensive policy (parsing OR the .hostname read can raise ValueError, guard
both) without asserting version history.
2. The two monkeypatched lazy-.hostname tests were described as reproducing
"the exact production path" / "the Python < 3.14 shape". They are synthetic
defensive cases. Relabeled them as synthetic defensive coverage that does
not reproduce any specific CPython behavior, and dropped the version-history
claims from the bracketed-non-IP test docstrings.
The second-round suggestion (_is_allowed_download_url(final_url) instead of
_is_allowed_download_url(_urlparse(final_url))) was already applied in the
original commit.
Behavior unchanged; comments/docstrings only. URL-guard tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>1 parent e14561f commit cce47f6
3 files changed
Lines changed: 134 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
428 | 428 | | |
429 | 429 | | |
430 | 430 | | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
431 | 438 | | |
432 | 439 | | |
433 | 440 | | |
434 | | - | |
| 441 | + | |
435 | 442 | | |
436 | 443 | | |
437 | 444 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6607 | 6607 | | |
6608 | 6608 | | |
6609 | 6609 | | |
| 6610 | + | |
| 6611 | + | |
| 6612 | + | |
| 6613 | + | |
| 6614 | + | |
| 6615 | + | |
| 6616 | + | |
| 6617 | + | |
| 6618 | + | |
| 6619 | + | |
| 6620 | + | |
| 6621 | + | |
| 6622 | + | |
| 6623 | + | |
| 6624 | + | |
| 6625 | + | |
| 6626 | + | |
| 6627 | + | |
| 6628 | + | |
| 6629 | + | |
| 6630 | + | |
| 6631 | + | |
| 6632 | + | |
| 6633 | + | |
| 6634 | + | |
| 6635 | + | |
| 6636 | + | |
| 6637 | + | |
| 6638 | + | |
| 6639 | + | |
| 6640 | + | |
| 6641 | + | |
| 6642 | + | |
| 6643 | + | |
| 6644 | + | |
| 6645 | + | |
| 6646 | + | |
| 6647 | + | |
| 6648 | + | |
| 6649 | + | |
| 6650 | + | |
| 6651 | + | |
| 6652 | + | |
| 6653 | + | |
| 6654 | + | |
| 6655 | + | |
| 6656 | + | |
| 6657 | + | |
| 6658 | + | |
| 6659 | + | |
| 6660 | + | |
| 6661 | + | |
| 6662 | + | |
| 6663 | + | |
| 6664 | + | |
| 6665 | + | |
| 6666 | + | |
| 6667 | + | |
| 6668 | + | |
| 6669 | + | |
| 6670 | + | |
| 6671 | + | |
| 6672 | + | |
| 6673 | + | |
| 6674 | + | |
| 6675 | + | |
| 6676 | + | |
| 6677 | + | |
| 6678 | + | |
| 6679 | + | |
| 6680 | + | |
| 6681 | + | |
| 6682 | + | |
| 6683 | + | |
6610 | 6684 | | |
6611 | 6685 | | |
6612 | 6686 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5605 | 5605 | | |
5606 | 5606 | | |
5607 | 5607 | | |
| 5608 | + | |
| 5609 | + | |
| 5610 | + | |
| 5611 | + | |
| 5612 | + | |
| 5613 | + | |
| 5614 | + | |
| 5615 | + | |
| 5616 | + | |
| 5617 | + | |
| 5618 | + | |
| 5619 | + | |
| 5620 | + | |
| 5621 | + | |
| 5622 | + | |
| 5623 | + | |
| 5624 | + | |
| 5625 | + | |
| 5626 | + | |
| 5627 | + | |
| 5628 | + | |
| 5629 | + | |
| 5630 | + | |
| 5631 | + | |
| 5632 | + | |
| 5633 | + | |
| 5634 | + | |
| 5635 | + | |
| 5636 | + | |
| 5637 | + | |
| 5638 | + | |
| 5639 | + | |
| 5640 | + | |
| 5641 | + | |
| 5642 | + | |
| 5643 | + | |
| 5644 | + | |
| 5645 | + | |
| 5646 | + | |
| 5647 | + | |
| 5648 | + | |
| 5649 | + | |
| 5650 | + | |
| 5651 | + | |
| 5652 | + | |
| 5653 | + | |
| 5654 | + | |
| 5655 | + | |
| 5656 | + | |
| 5657 | + | |
| 5658 | + | |
| 5659 | + | |
5608 | 5660 | | |
5609 | 5661 | | |
5610 | 5662 | | |
| |||
0 commit comments