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
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>
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.
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.
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.
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.
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>
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.
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.
Normalize historical SHA-256 digests like current release records
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.
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
triage-nice-to-haveVerdict: evidence-backed fix or greenlit feature — land after review
3 participants
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
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.12is rejected after the catalog advances to0.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 underreleases.specify extension info <id> --versionsshows the available versions, andspecify extension add <id> --version 0.4.12selects 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.1plus a0.4.12historical release;extension add --version 0.4.12requested the old ZIP and installed version0.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=Conce44a1d: 8,368 passed, 207 skipped (53 warnings). Without the English locale, six unrelated workflow tests compare localizedsha256sumoutput against English strings.The CI-pinned
uvx ruff@0.15.0 check src testsandgit diff --checkpassed. The newly added test file passes Ruff format check; the existing command modules are not uniformly Ruff-formatted onmain.A direct
markdownlint-cli2run on the edited reference page reports eight existing violations; the same eight appear on the unmodifiedmainversion of that page.AI Disclosure
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, andce44a1dwere generated and validated autonomously by Codex. Subsequent agent-generated review responses will also disclose AI use.