Skip to content

fix(bundler): enforce version pin on bundled preset/extension installs#3377

Open
jawwad-ali wants to merge 2 commits into
github:mainfrom
jawwad-ali:fix/bundler-bundled-version-pin
Open

fix(bundler): enforce version pin on bundled preset/extension installs#3377
jawwad-ali wants to merge 2 commits into
github:mainfrom
jawwad-ali:fix/bundler-bundled-version-pin

Conversation

@jawwad-ali

Copy link
Copy Markdown
Contributor

Description

Bundle manifests pin component versions for reproducibility, enforced by _assert_pinned_version. But the bundled install branch of _PresetKindManager/_ExtensionKindManager returns before that check:

bundled = _locate_bundled_preset(component.id)
if bundled is not None:
    self._manager.install_from_directory(bundled, speckit_version, priority)
    return   # <-- _assert_pinned_version (below) never runs for bundled assets

So a bundle pinning e.g. 2.0.0 silently installs whatever version the bundled asset ships (1.0.0) — the pin is only enforced on the catalog path. Reproduced on main @ 92b7cf7: a ComponentRef(version="2.0.0") against a bundled extension.yml of 1.0.0 installs with no error. (_WorkflowKindManager already enforces the pin unconditionally, so this is an internal inconsistency.)

Fix

Read the bundled asset's own declared version from its manifest (best-effort — None on unreadable/invalid, which _assert_pinned_version treats as "cannot enforce", matching the catalog "advertises no version" escape hatch) and call _assert_pinned_version before install_from_directory in both bundled branches.

Testing

New tests (mirror the existing _assert_pinned_version / bundled-workflow test style):

  • bundled extension & preset with a 2.0.0 pin vs 1.0.0 manifestBundlerError "pinned to version 2.0.0", and install_from_directory is not called;
  • matching pin and unpinned (version=None) → install proceeds.

Mismatch tests fail-before ("DID NOT RAISE", verified by source-stash); full test_bundler_primitives.py: 15 passed. uvx ruff check clean.

AI Disclosure

  • I did use AI assistance (describe below)

Found and fixed with Claude Code (Claude Fable 5) under my direction. AI spotted the early-return bypassing the pin in the bundled branch vs the workflow manager's unconditional enforcement; I reproduced the silent pin violation, verified fail-before/pass-after, and reviewed the diff.

The bundled install branch of _PresetKindManager/_ExtensionKindManager
called install_from_directory and returned before _assert_pinned_version,
so a bundle manifest pinning e.g. 2.0.0 would silently install the
bundled asset's own version (1.0.0) — the pin was only enforced on the
catalog path. _WorkflowKindManager already enforces it unconditionally.
Read the bundled asset's declared version from its manifest (best-effort;
None => cannot enforce, matching the catalog 'advertises no version'
escape hatch) and call _assert_pinned_version before install, in both
bundled branches.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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.

Pull request overview

This PR fixes a reproducibility gap in the bundler’s primitive installers by enforcing bundle-manifest version pins even when presets/extensions are installed from locally bundled assets (previously the bundled early-return path bypassed pin validation, unlike the catalog path and workflow manager).

Changes:

  • Add _bundled_manifest_version() to best-effort read a bundled preset/extension manifest’s declared version.
  • Enforce _assert_pinned_version() in the bundled install branches for presets and extensions before installing from directory.
  • Add unit tests covering bundled extension/preset pin enforcement behavior.
Show a summary per file
File Description
tests/unit/test_bundler_primitives.py Adds unit tests to ensure bundled preset/extension installs respect bundle-manifest version pins and don’t proceed on mismatches.
src/specify_cli/bundler/services/primitives.py Reads bundled manifest versions and enforces version pins for bundled preset/extension installs to match catalog-path behavior.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 3
  • Review effort level: Low

Comment thread src/specify_cli/bundler/services/primitives.py
Comment thread src/specify_cli/bundler/services/primitives.py
Comment thread tests/unit/test_bundler_primitives.py
- Make _assert_pinned_version's error source-agnostic ('resolved version'
  / 'the source') so bundled preset.yml/extension.yml mismatches read
  correctly, not just catalog ones.
- Type-guard _bundled_manifest_version: only a non-empty string version is
  usable; missing/non-string/whitespace -> None ('cannot enforce').
- Add bundled-preset success-path test (matching pin + version=None both
  proceed to install_from_directory), mirroring the extension test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Low

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.

3 participants