Skip to content

feat(extensions): select exact catalog releases - #4726

Open
Doribelove wants to merge 4 commits into
github:mainfrom
Doribelove:feat/4719-extension-version-lookup
Open

Doribelove wants to merge 4 commits into
github:mainfrom
Doribelove:feat/4719-extension-version-lookup

Conversation

@Doribelove

@Doribelove Doribelove commented Sep 24, 2026 •

Copy link
Copy Markdown

Description

An extension catalog currently keeps only its advertised release. Once that entry advances, users cannot select a still-available older archive from the same trusted catalog. In the #4712 reproduction, a bundle pin for 0.4.12 is rejected after the catalog advances to 0.5.1, although the old ZIP still returns HTTP 200. This PR implements the extension-catalog slice of the maintainer's separate-area plan in #4719; bundle pin resolution remains a separate follow-up.

Versioned entries keep the existing top-level version/URL/digest as the current release and may add historical records under releases. specify extension info <id> --versions shows the available versions, and specify extension add <id> --version 0.4.12 selects the exact record from the winning catalog. Both commands use the entry from the initial winning-source lookup, so a later catalog change or failed fetch cannot redirect version selection. PEP 440-equivalent version spellings select the same record while preserving its advertised spelling. Ordinary unqualified installs retain their current behavior. Missing versions do not fall through to lower-priority catalogs; discovery-only catalogs remain non-installable. Historical records need their own URL and SHA-256. The selected record is downloaded directly, then the archive's manifest ID and version are checked before installation. Catalog lookup failures are reported distinctly from missing versions. The reference documentation describes the format and this PR's bundle limitation.

Testing

  • Tested locally with uv run specify --help.

  • Ran existing tests from this working tree's .venv (full results below).

  • Tested with a sample project: a localhost catalog advertised 0.5.1 plus a 0.4.12 historical release; extension add --version 0.4.12 requested the old ZIP and installed version 0.4.12.

  • Focused extension tests on ce44a1d: 177 passed. New tests confirm exact installs and version listings use one catalog snapshot even if a second fetch would return a different entry or fail.

  • Full test suite with LC_ALL=C on ce44a1d: 8,368 passed, 207 skipped (53 warnings). Without the English locale, six unrelated workflow tests compare localized sha256sum output against English strings.

  • The CI-pinned uvx ruff@0.15.0 check src tests and git diff --check passed. The newly added test file passes Ruff format check; the existing command modules are not uniformly Ruff-formatted on main.

  • A direct markdownlint-cli2 run on the edited reference page reports eight existing violations; the same eight appear on the unmodified main version of that page.

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (fill in the disclosure below)

AI disclosure: OpenAI Codex (GPT-6, autonomous mode at the contributor's request; default task settings, with the precise reasoning level not exposed) generated the reproduction, implementation, tests, documentation, and this PR text, then ran the checks listed above. The contributor reports having independently reviewed and tested the initial patch before marking this PR ready for review. The additional review-round changes in 4615cac, 7fb0973, and ce44a1d were generated and validated autonomously by Codex. Subsequent agent-generated review responses will also disclose AI use.

Keep current release metadata compatible with existing catalogs while allowing
trusted catalogs to publish historical release URLs and digests. Add exact
version selection, archive identity and discovery-policy checks, tests, and
documentation.

Refs github#4719; follows up github#4712.

Assisted-by: OpenAI Codex (model: GPT-6, autonomous)
Signed-off-by: 李永祺 <doribelove@gmail.com>
@Doribelove
Doribelove force-pushed the feat/4719-extension-version-lookup branch from a557a7d to b21d936 Compare September 24, 2026 09:13
@Doribelove
Doribelove marked this pull request as ready for review September 24, 2026 09:17
@Doribelove
Doribelove requested a review from mnriem as a code owner September 24, 2026 09:17
@mnriem mnriem added the triage-nice-to-have Verdict: evidence-backed fix or greenlit feature — land after review label Sep 24, 2026
@mnriem

mnriem commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Thanks — this looks like the right first slice of github/spec-kit#4719. The extension-catalog scope is focused and reviewable.

Before approval, could you add tests for the remaining new paths: reject a historical archive with the wrong extension ID or SHA-256 before installation; confirm an unqualified install still selects the advertised current release when releases is present; and cover both a matching and a mismatched packaged version in the bundled exact-version path. The existing tests already cover missing versions, precedence, discovery-only policy, and a wrong archive version.

Posted on behalf of @mnriem by GitHub Copilot (model: GPT-6 Sol, autonomous); comment fully AI-drafted.

Assisted-by: OpenAI Codex (model: GPT-6 Sol, autonomous)
Signed-off-by: 李永祺 <doribelove@gmail.com>
@Doribelove

Copy link
Copy Markdown
Author

I added the review-round regressions in 4615cac: the exact-release CLI now has tests for rejecting a historical archive with the wrong ID or digest before installation, while the ordinary install test confirms it still uses the advertised current release when history is present. The bundled exact-version tests cover both a packaged-version match and mismatch. This commit changes tests only.

Validation: 169 extension tests passed; the full suite passed with LC_ALL=C (8,360 passed, 207 skipped). Ruff lint/format checks and git diff --check passed. I updated the PR description with the current results. The existing review request to @mnriem remains open.

Posted on behalf of @Doribelove by OpenAI Codex (model: GPT-6 Sol, autonomous); comment fully AI-drafted.

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

Version comparison inconsistencies and a misleading catalog-failure message need correction.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 3 Medium severity

Open (3)
What changed in this PR

Adds exact historical extension release selection while preserving current-release behavior and catalog precedence.

Changes:

  • Adds versioned catalog parsing, selection, and secure installation.
  • Adds --version and --versions CLI options.
  • Documents the release-history format and adds regression coverage.
File Description
src/​specify_cli/​extensions/​_catalog_versions.py Validates and selects catalog releases.
src/​specify_cli/​extensions/​__init__.py Downloads selected releases and verifies archive identity.
src/​specify_cli/​extensions/​command_add.py Adds exact-version installation.
src/​specify_cli/​extensions/​command_info.py Lists catalog versions.
tests/​specify_cli/​extensions/​test_catalog_versions.py Covers lookup, policy, integrity, and installation behavior.
docs/​reference/​extensions.md Documents version history and bundle limitations.

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

Comment thread src/specify_cli/extensions/_catalog_versions.py Outdated
Comment thread src/specify_cli/extensions/command_add.py Outdated
Comment thread src/specify_cli/extensions/command_info.py
Assisted-by: OpenAI Codex (model: GPT-6 Sol, autonomous)
Signed-off-by: 李永祺 <doribelove@gmail.com>
@Doribelove

Doribelove commented Sep 25, 2026 •

Copy link
Copy Markdown
Author

The follow-up in 7fb0973 addresses the new review findings. Catalog lookup now compares PEP 440 versions while retaining each release's advertised spelling, and bundled installs use the same comparison. extension info --versions now reports a catalog-fetch error instead of saying that no versions exist. The commit also adds CLI and catalog regressions for these cases and updates the reference page.

Validation: 174 extension tests passed; the full suite passed with LC_ALL=C (8,365 passed, 207 skipped). Ruff lint/format checks passed for the version-selection module and tests; the touched command modules passed lint with only three pre-existing rules excluded. git diff --check passed. The new fork-PR workflows are action_required and have not run yet; they await repository approval. The PR description has the current local results. The existing review request to @mnriem remains open.

Posted on behalf of @Doribelove by OpenAI Codex (model: GPT-6 Sol, autonomous); comment fully AI-drafted.

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

Re-fetching catalogs after resolving the winning entry can incorrectly fall through to another source.

Review effort: Balanced
Findings: 1 High severity

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

In code that hasn't changed since last review

Medium severity Derive versions from resolved entry instead of refetching catalogs

src/​specify_cli/​extensions/​command_info.py:48

The versions view refetches all catalogs after ext_info already resolved the winning entry. A transient failure or catalog update can therefore display versions from a different, lower-priority source—or fail despite the successful lookup—rather than versions belonging to the resolved entry. Derive the list directly from ext_info.

Comment thread src/specify_cli/extensions/command_add.py Outdated
@mnriem

mnriem commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback and fix test & linit errors

Avoid refetching catalogs after resolving the winning extension source. Preserve that snapshot for exact installs and version listings, including when a later fetch would fail or return a lower-priority entry.

Assisted-by: OpenAI Codex (model: GPT-6, autonomous)
Signed-off-by: 李永祺 <doribelove@gmail.com>
@Doribelove

Copy link
Copy Markdown
Author

The catalog-snapshot feedback is addressed in ce44a1d. Exact installs now select the requested release from the entry returned by the initial winning-source lookup, and extension info --versions derives its list from that same entry. The new regressions cover a second lookup returning a different entry or failing; both command paths previously fetched twice.

On the current head, 177 extension tests passed; the full suite with LC_ALL=C reports 8,368 passed and 207 skipped. The CI-pinned uvx ruff@0.15.0 check src tests, test-file format check, and git diff --check passed. I also checked the previous remote run: its Ruff job passed, while the Ubuntu Python 3.13 test job stopped during uv sync after timing out fetching click from PyPI, before test execution. The new head has not reported remote checks yet.

Posted on behalf of @Doribelove by OpenAI Codex (model: GPT-6, autonomous). Codex generated this review-round code, tests, and comment and ran the checks above.

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

Historical digest compatibility and malformed legacy-version handling can reject valid metadata or expose uncaught errors.

Review effort: Balanced
Findings: None

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

In code that hasn't changed since last review

Medium severity Handle invalid expected versions without uncaught InvalidVersion errors

src/​specify_cli/​extensions/​__init__.py:2791

Guard parsing of expected_version. select_release intentionally allows an exact-spelling match for a legacy non-PEP-440 current version (_catalog_versions.py:121-134), but this unguarded conversion then raises InvalidVersion, which is outside the ExtensionError hierarchy caught by the command. Such a catalog produces an uncaught CLI exception instead of a validation error; please add a regression case for it.

Medium severity Normalize historical SHA-256 digests like current release records

src/​specify_cli/​extensions/​_catalog_versions.py:99

Historical records reject the optional sha256: prefix (and surrounding whitespace) that the existing archive verifier explicitly accepts for current releases (src/specify_cli/shared_infra.py:77-89). Moving an otherwise valid current record into releases can therefore make it unusable. Normalize the historical digest with the same rules and cover the prefixed form in the malformed-history tests.

@mnriem

mnriem commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

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

triage-nice-to-have Verdict: evidence-backed fix or greenlit feature — land after review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants