You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Implement the preset-catalog slice of #4719. A catalog entry continues to
advertise its current release through the existing top-level version, download_url, digest, and requirements fields. Install-allowed catalogs may
add a releases mapping of historical versions, each with its own URL and
SHA-256 digest. Existing single-version entries and unqualified installs
continue to work.
specify preset info <id> --versions lists the winning catalog entry's
versions, and specify preset add <id> --version <version> selects an exact
release without falling through to a lower-priority catalog. Discovery-only
catalogs remain non-installable. The selected release is downloaded without
re-resolving the ID; download URL and redirects, digest, and the extracted preset.yml ID and version are checked before installation. Malformed,
inconsistent, or duplicate historical records fail validation. Direct --from URL installs retain their existing semantics.
This follows the extension-catalog precedent in #4726 but changes only
presets; bundle pin consumption and other catalog families are separate work.
The reference documentation describes the representation and limits.
Testing
Tested locally with uv run specify --help — passed.
Ran existing tests with uv sync && uv run pytest — used this worktree's
virtualenv instead, as required by AGENTS.md: uv sync --extra test --quiet — passed; LC_ALL=C.UTF-8 .venv/bin/python -m pytest tests -q --tb=short — 9,542 passed,
19 skipped (62 warnings). A prior full run with LC_ALL=C failed 25
unrelated Bash Unicode parity cases because that locale is not UTF-8; the
final UTF-8 run passed them.
Tested with a sample project (if applicable) — a temporary localhost
catalog advertised 2.0.0 with a historical 1.0.0 archive. Both preset info sample --versions and preset add sample --version 1.0.0 succeeded; the installed manifest was 1.0.0.
LC_ALL=C.UTF-8 .venv/bin/python -m pytest -q tests/specify_cli/presets/test_catalog_versions.py — 31 passed, covering
current and exact selection, legacy compatibility, invalid and duplicate
releases, source precedence, discovery-only rejection, download integrity
and redirects, and pre-install manifest identity checks. git diff --check upstream/main...HEAD — passed.
AI Disclosure
I did not use AI assistance for this contribution
I did use AI assistance (fill in the disclosure below)
AI disclosure: GitHub Copilot (GPT-6 Sol, autonomous mode; reasoning-effort
setting not exposed to this session) generated the implementation, tests,
documentation, validation steps, and this PR description. The checks above
were run by the agent. No human line-by-line review or manual testing is
claimed.
Historical releases require and verify a SHA-256 digest; legacy current releases can still omit one. Preserve upstream integration wording after the rebase.
Assisted-by: GitHub Copilot (model: GPT-6 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Reject duplicate catalog keys on network and cache reads, validate historical extension requirements against the manifest, and list versions from one resolved snapshot.
Assisted-by: GitHub Copilot (model: GPT-6 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Addressed the three review findings in 989b4e2037caf8b2c646e60ab06fd9be2aac169c:
Reject duplicate JSON keys on both fetched and cached preset catalogs (including duplicate historical release keys), with raw-JSON regressions for the stack and legacy fetch paths.
Validate each historical requires.extensions record using the preset manifest validator; cover malformed IDs, versions, flags, and valid dependencies.
List versions from the already-resolved winning catalog entry so the version list and discovery-only warning use the same snapshot.
Regression evidence: the new tests failed in 10 cases before the fix and now pass (42/42 focused). LC_ALL=C.UTF-8 .venv/bin/python -m pytest tests -q --tb=short: 9,553 passed, 19 skipped. uvx ruff@0.15.0 check src tests: passed.
Posted on behalf of @mnriem. GitHub Copilot (GPT-6 Sol, autonomous mode) generated the fixes, tests, documentation, and this review-round summary.
Addressed the follow-up review in eae672f7: malformed catalog JSON and invalid payloads now raise a distinct validation error through stack merging and preset lookup, rather than allowing a lower-priority install source to win. An unreachable catalog can still be skipped. The CLI reports invalid content for preset add, preset info, and preset search without downloading or installing an archive.
Regression evidence: three stacked-source cases failed before the change and pass afterward. LC_ALL=C.UTF-8 .venv/bin/python -m pytest tests -q --tb=short: 9,557 passed, 19 skipped. uvx ruff@0.15.0 check src tests: passed.
Posted on behalf of @mnriem. GitHub Copilot (GPT-6 Sol, autonomous mode) generated the code, tests, documentation, and this review-round summary.
Report malformed release history as catalog validation errors
src/specify_cli/presets/_catalog.py:796
Malformed history, such as releases: [], raises ordinary PresetError from select_release(). For a preset that is not installed locally, ordinary preset info <id> catches this at command_info.py:93–94 and reports “not found,” hiding the actual catalog error. Convert entry-validation failures to PresetCatalogValidationError so the dedicated CLI handler displays the cause without changing network-failure handling. Add a regression for ordinary info without --versions.
AI disclosure: GitHub Copilot; model/reasoning settings unavailable; autonomous code review for the requester (identity unavailable).
Normalize prefixed and whitespace-padded SHA-256 digests
This rejects sha256:-prefixed digests and surrounding whitespace, although preset downloads accept both (src/specify_cli/shared_infra.py:78–85), as does extension history validation. Moving an accepted current-release digest into history therefore makes even unqualified lookup fail. Normalize whitespace and the case-insensitive sha256: prefix before checking the hexadecimal value; continue rejecting other algorithm prefixes.
AI disclosure: GitHub Copilot; model/reasoning settings unavailable; autonomous code review for the requester (identity unavailable).
Addressed the latest review in ef2062e7686f549d6705c2cf38b559eb8b3399ed: invalid UTF-8 catalog content now reports a validation error instead of permitting lower-priority installation; malformed release histories surface their actual error in ordinary preset info; historical SHA-256 declarations accept the same whitespace and optional case-insensitive sha256: prefix as archive verification, while still rejecting other algorithms.
The five new regression cases failed before the fixes and now pass. LC_ALL=C.UTF-8 .venv/bin/python -m pytest tests/specify_cli/presets -q --tb=short: 688 passed. uvx ruff@0.15.0 check src tests: passed. A full LC_ALL=C.UTF-8 .venv/bin/python -m pytest tests -q --tb=short run recorded 9,537 passed, 19 skipped, and 26 unrelated PowerShell tests failed: the local pwsh process aborts before executing any script with System.IO.FileLoadException (reproduced with pwsh -NoProfile -NonInteractive -Command 'Write-Output ok'). The previous full run before this review round passed 9,557 tests and skipped 19. The current PR commit's CI checks will provide cross-platform confirmation.
Posted on behalf of @mnriem. GitHub Copilot (GPT-6 Sol, autonomous mode) generated the changes, tests, documentation, and this review-round summary.
preset add sample --version 1.0 --from "" (or --dev "") passes this guard and reaches catalog installation because empty strings are falsey. An empty shell-variable expansion can therefore silently ignore the explicitly selected source. Check dev is not None and from_url is not None, and add regression cases for both empty options.
AI-generated review by GitHub Copilot (model/settings unavailable, automated mode) for the requesting reviewer.
Add tests for bundled version matching and rejection cases
src/specify_cli/presets/command_add.py:351
The new bundled --version branch lacks success and rejection tests. Existing bundled CLI tests only exercise unqualified installs; the new version tests use downloadable archives. Add CLI coverage in tests/specify_cli/presets/test_command_add.py for a matching packaged ID/version installing without a download, and missing packaged files or mismatched IDs/versions failing without installation or download. CONTRIBUTING.md:188–194 requires positive and negative coverage for deterministic changes.
AI-generated review by GitHub Copilot (model/settings unavailable, automated mode) for the requesting reviewer.
Treat present but empty --from and --dev options as incompatible with versioned catalog installs. Exercise matching and mismatched bundled preset versions through the CLI without downloading.
Assisted-by: GitHub Copilot (model: GPT-6 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Addressed the latest review in 702caa0788b591d88241d0e06b57423ada06a7bd: preset add <id> --version now rejects explicitly supplied empty --from and --dev options instead of falling through to catalog installation. New CLI tests cover a matching packaged bundled preset installing without download and missing files or mismatched packaged ID/version refusing installation without download.
The two empty-source regressions failed before the fix and now pass. LC_ALL=C.UTF-8 .venv/bin/python -m pytest tests/specify_cli/presets/test_catalog_versions.py tests/specify_cli/presets/test_command_add.py -q --tb=short: 88 passed. The broader preset run recorded 693 passed and 1 unrelated failure because the local pwsh binary aborts before executing the PowerShell retry-renderer test. uvx ruff@0.15.0 check src tests: passed. CI checks on this head will provide cross-platform confirmation.
Posted on behalf of @mnriem. GitHub Copilot (GPT-6 Sol, autonomous mode) generated the fix, tests, and this review-round summary.
Skip redirect validation when download URL is unchanged
src/specify_cli/presets/_catalog.py:944
The final check applies redirect restrictions even when no redirect occurred. For example, https://dev.localhost/preset.zip passes the initial HTTPS check, but is_safe_download_redirect(url, url) returns false, rejecting a successful direct download. This also affects current installs because download_pack delegates here. Apply the redirect predicate only when the final URL differs, keeping the scheme check and per-hop validation.
AI-generated feedback: GitHub Copilot for the requesting reviewer; model/settings unavailable; automated review and suggested fix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Implement the preset-catalog slice of #4719. A catalog entry continues to
advertise its current release through the existing top-level
version,download_url, digest, and requirements fields. Install-allowed catalogs mayadd a
releasesmapping of historical versions, each with its own URL andSHA-256 digest. Existing single-version entries and unqualified installs
continue to work.
specify preset info <id> --versionslists the winning catalog entry'sversions, and
specify preset add <id> --version <version>selects an exactrelease without falling through to a lower-priority catalog. Discovery-only
catalogs remain non-installable. The selected release is downloaded without
re-resolving the ID; download URL and redirects, digest, and the extracted
preset.ymlID and version are checked before installation. Malformed,inconsistent, or duplicate historical records fail validation. Direct
--fromURL installs retain their existing semantics.This follows the extension-catalog precedent in #4726 but changes only
presets; bundle pin consumption and other catalog families are separate work.
The reference documentation describes the representation and limits.
Testing
uv run specify --help— passed.uv sync && uv run pytest— used this worktree'svirtualenv instead, as required by
AGENTS.md:uv sync --extra test --quiet— passed;LC_ALL=C.UTF-8 .venv/bin/python -m pytest tests -q --tb=short— 9,542 passed,19 skipped (62 warnings). A prior full run with
LC_ALL=Cfailed 25unrelated Bash Unicode parity cases because that locale is not UTF-8; the
final UTF-8 run passed them.
catalog advertised
2.0.0with a historical1.0.0archive. Bothpreset info sample --versionsandpreset add sample --version 1.0.0succeeded; the installed manifest was1.0.0.LC_ALL=C.UTF-8 .venv/bin/python -m pytest -q tests/specify_cli/presets/test_catalog_versions.py— 31 passed, coveringcurrent and exact selection, legacy compatibility, invalid and duplicate
releases, source precedence, discovery-only rejection, download integrity
and redirects, and pre-install manifest identity checks.
git diff --check upstream/main...HEAD— passed.AI Disclosure
AI disclosure: GitHub Copilot (GPT-6 Sol, autonomous mode; reasoning-effort
setting not exposed to this session) generated the implementation, tests,
documentation, validation steps, and this PR description. The checks above
were run by the agent. No human line-by-line review or manual testing is
claimed.