Skip to content

feat(presets): select exact catalog releases - #4823

Open
mnriem wants to merge 6 commits into
github:mainfrom
mnriem:mnriem-feat-4719-preset-catalog-releases
Open

mnriem wants to merge 6 commits into
github:mainfrom
mnriem:mnriem-feat-4719-preset-catalog-releases

Conversation

@mnriem

@mnriem mnriem commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator

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 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.

mnriem and others added 2 commits October 2, 2026 14:15
Keep the top-level advertised release stable while validating historical records, selecting version-specific metadata, and verifying the selected archive before installation. Preserve legacy and direct-URL paths.

Assisted-by: GitHub Copilot (model: GPT-6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 20:08

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.

Copilot review overview

🟡 Changes recommended

Unresolved catalog validation and version-listing consistency defects need correction.

Review effort: Balanced
Findings: 1 High severity · 2 Medium severity

Open (3)
What changed in this PR

Adds exact-release selection to Specify CLI’s preset catalogs, implementing the preset-only portion of #4719.

Changes:

  • Adds historical release metadata, validation, and exact-version lookup.
  • Adds info --versions and add --version, with selected-archive integrity and identity checks.
  • Documents the format and adds regression coverage.

AI-generated review for the requester: GitHub Copilot (automated analysis; model/settings unavailable).

File Description
tests/​specify_cli/​presets/​test_catalog_versions.py Tests selection, validation, downloads, and CLI behavior.
src/​specify_cli/​presets/​command_info.py Adds catalog version listing.
src/​specify_cli/​presets/​command_add.py Adds exact-version installation.
src/​specify_cli/​presets/​_manager.py Checks archive identity before installation.
src/​specify_cli/​presets/​_catalog.py Adds selected-release downloads and redirect validation.
src/​specify_cli/​presets/​_catalog_versions.py Validates and selects release metadata.
docs/​reference/​presets.md Documents versioned catalogs and CLI options.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

) from None

seen = {current_version}
for release_version, record in releases.items():
Comment thread src/specify_cli/presets/_catalog_versions.py Outdated
Comment thread src/specify_cli/presets/command_info.py Outdated
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>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 20:33
@mnriem

mnriem commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

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.

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.

Copilot review overview

🟡 Changes recommended

Duplicate-history validation failures can bypass a higher-priority catalog’s installation policy.

Review effort: Balanced
Findings: 1 High severity · 1 Medium severity

Open (2)
Resolved since last review (2)

Comment thread src/specify_cli/presets/_catalog.py
Preserve unavailable-source fallback while surfacing malformed catalog JSON and payloads through lookup and CLI commands, so lower-priority installation cannot bypass discovery-only policy.

Assisted-by: GitHub Copilot (model: GPT-6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 20:59
@mnriem

mnriem commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

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.

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.

Copilot review overview

🟡 Changes recommended

Malformed catalog encoding can bypass discovery-only installation policy.

Review effort: Balanced
Findings: 2 High severity

Open (2)
Resolved since last review (1)
Previously missed (2)

In code that hasn't changed since last review

Medium severity 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).

Medium severity Normalize prefixed and whitespace-padded SHA-256 digests

src/​specify_cli/​presets/​_catalog_versions.py:82

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).

Comment thread src/specify_cli/presets/_catalog.py
Surface invalid UTF-8 and release histories as catalog validation errors, and accept the SHA-256 digest forms already supported by archive verification.

Assisted-by: GitHub Copilot (model: GPT-6 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 21:35
@mnriem

mnriem commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

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.

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.

Copilot review overview

🔵 Needs a closer look

Empty source options bypass validation, and the bundled exact-version installation path lacks required success and rejection tests.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Resolved since last review (1)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Empty source options bypass explicit source selection

src/​specify_cli/​presets/​command_add.py:170

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.

Medium severity 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>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 21:54
@mnriem

mnriem commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

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.

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.

Copilot review overview

🟡 Changes recommended

Catalog fallback can bypass installation policy, and redirect checks reject some permitted direct downloads.

Review effort: Balanced
Findings: 2 High severity

Open (2)
Previously missed (1)

In code that hasn't changed since last review

Medium severity 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.

read_response_limited(
response,
max_bytes=MAX_JSON_CATALOG_BYTES,
error_type=PresetError,

This branch has not been deployed

No deployments
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.

2 participants