Skip to content

fix(presets): validate catalog URL port, not just hostname - #4341

Open
Noor-ul-ain001 wants to merge 1 commit into
github:mainfrom
Noor-ul-ain001:fix/preset-catalog-url-port-validation
Open

fix(presets): validate catalog URL port, not just hostname#4341
Noor-ul-ain001 wants to merge 1 commit into
github:mainfrom
Noor-ul-ain001:fix/preset-catalog-url-port-validation

Conversation

@Noor-ul-ain001

Copy link
Copy Markdown
Contributor

Summary

  • PresetCatalog._validate_catalog_url is a standalone reimplementation (PresetCatalog does not inherit CatalogStackBase) of the same guard that exists in specify_cli.catalogs and bundler/services/adapters.py, but it had drifted: it accessed parsed.hostname inside the malformed-URL try/except but never parsed.port.
  • urlparse(url).hostname does not perform port validation — only accessing .port does, lazily. So a catalog URL like https://example.com:99999/catalog.json (or a non-numeric port) sailed straight through this validator with no error at all, and would only fail later, at actual fetch time, with a raw untranslated exception instead of the clean PresetValidationError this function's docstring promises.
  • The sibling preset add --from <url> download-URL guard already probes .port for exactly this reason (see test_preset_add_from_url_out_of_range_port_exits_cleanly) — this catalog-source-URL validator is a different function that just never got the same fix applied to it.
  • Fix: add the same _ = parsed.port probe inside the try/except, matching specify_cli.catalogs._validate_catalog_url and bundler/services/adapters.py::_validate_remote_url.

Test plan

  • Added test_validate_catalog_url_out_of_range_port_rejected to tests/test_presets.py::TestPresetCatalog, next to the existing malformed-IPv6-URL test for the same function.
  • Verified the test fails without the fix (test-the-test): asserted PresetValidationError but got Failed: DID NOT RAISE — the malformed port silently passed validation.
  • Ran TestPresetCatalog/TestPresetCatalogMultiCatalog/TestPresetCatalogEntry/TestPresetCatalogRichMarkup (106 tests) and the full tests/test_presets.py suite (605 passed, 8 pre-existing Windows symlink-elevation failures needing admin rights, unrelated to this change, 2 skipped).

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

https://claude.ai/code/session_01PJHJ2dHP2RVCNncHqN8Qm9

`PresetCatalog._validate_catalog_url` is a standalone reimplementation
(PresetCatalog does not inherit `CatalogStackBase`) of the same guard that
exists in `specify_cli.catalogs` and `bundler/services/adapters.py`, but it
had drifted: it accessed `parsed.hostname` inside the malformed-URL
try/except but never `parsed.port`.

`urlparse(url).hostname` does not perform port validation — only accessing
`.port` does, lazily. So a catalog URL like
`https://example.com:99999/catalog.json` (or a non-numeric port) sailed
straight through this validator with no error at all, and would only fail
later, at actual fetch time, with a raw untranslated exception instead of
the clean `PresetValidationError` this function's docstring promises.

The sibling `preset add --from <url>` download-URL guard already probes
`.port` for exactly this reason (see
`test_preset_add_from_url_out_of_range_port_exits_cleanly`) — this
catalog-*source*-URL validator is a different function that just never
got the same fix applied to it.

Fix: add the same `_ = parsed.port` probe inside the try/except, matching
`specify_cli.catalogs._validate_catalog_url` and
`bundler/services/adapters.py::_validate_remote_url`.

## Test plan
- Added `test_validate_catalog_url_out_of_range_port_rejected` to
  `tests/test_presets.py::TestPresetCatalog`, next to the existing
  malformed-IPv6-URL test for the same function.
- Verified the test fails without the fix (test-the-test): asserted
  `PresetValidationError` but got `Failed: DID NOT RAISE` — the malformed
  port silently passed validation.
- Ran `TestPresetCatalog`/`TestPresetCatalogMultiCatalog`/
  `TestPresetCatalogEntry`/`TestPresetCatalogRichMarkup` (106 tests) and
  the full `tests/test_presets.py` suite (605 passed, 8 pre-existing
  Windows symlink-elevation failures needing admin rights, unrelated to
  this change, 2 skipped).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJHJ2dHP2RVCNncHqN8Qm9
@Noor-ul-ain001
Noor-ul-ain001 requested a review from mnriem as a code owner August 26, 2026 12:49
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.

1 participant