Skip to content

feat: interactive approval flow for community extensions#3015

Open
DyanGalih wants to merge 3 commits into
github:mainfrom
DyanGalih:feature/interactive-catalog-approval
Open

feat: interactive approval flow for community extensions#3015
DyanGalih wants to merge 3 commits into
github:mainfrom
DyanGalih:feature/interactive-catalog-approval

Conversation

@DyanGalih

Copy link
Copy Markdown
Contributor

Description

This PR introduces an interactive approval flow when users attempt to install an extension from a non-approved catalog (like the community catalog). Previously, users were met with a hard error instructing them to manually edit .specify/extension-catalogs.yml.

Changes Made

  • Interactive Prompt: extension_add now prompts the user with a warning panel if the extension's catalog is not approved. If approved interactively, it updates the config and proceeds with installation.
  • Config Persistence: Added approve_catalog_install in ExtensionCatalog to cleanly serialize and write the updated active catalogs to YAML, preserving the full catalog stack (including defaults).
  • Consistency Updates:
    • Updated extension_search and extension_info CLI output to guide users to run specify extension add instead of manual file editing.
    • Replaced yaml.dump with yaml.safe_dump in all catalog-related commands for consistency and safety.
  • Developer QoL: Added __main__.py to specify_cli so the package can be invoked locally using python -m specify_cli without global installation collisions.
  • Tests: Added 7 new test cases covering prompt ordering, cancellation, duplicate approvals, and fallback behaviors.

@DyanGalih DyanGalih requested a review from mnriem as a code owner June 17, 2026 03:50
Copilot AI review requested due to automatic review settings June 17, 2026 03:50

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

Note

Copilot was unable to run its full agentic suite in this review.

This PR adds an interactive “catalog approval” flow to unblock installing extensions from discovery-only catalogs, and persists that approval into the project’s .specify/extension-catalogs.yml. It also tightens YAML serialization safety and adds a __main__.py entry-point.

Changes:

  • Add ExtensionCatalog.approve_catalog_install() to persist install_allowed: true for an active catalog while preserving the catalog stack.
  • Update extension add UX to prompt for approval before starting any spinner/install work; refresh several related CLI messages.
  • Switch YAML writes to yaml.safe_dump and add src/specify_cli/__main__.py.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
tests/test_extensions.py Adds coverage for approval persistence, symlink safety behavior, and prompt/spinner ordering in extension add.
src/specify_cli/extensions.py Adds catalog approval persistence method and adjusts compatibility version check behavior.
src/specify_cli/main.py Adds module entry-point wrapper calling main().
src/specify_cli/init.py Updates CLI flow for approvals + safer YAML dumping and spinner placement.

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

Comment thread src/specify_cli/extensions.py
Comment thread src/specify_cli/extensions.py Outdated
Comment thread src/specify_cli/__init__.py Outdated
Comment thread src/specify_cli/extensions.py
Comment thread tests/test_extensions.py Outdated
@DyanGalih

Copy link
Copy Markdown
Contributor Author

We have addressed the PR review feedback! 🚀

Updates:

  1. Preserving User-Level Configs: We updated approve_catalog_install to base the serialization on the currently active stack instead of a hardcoded minimal default. This ensures we don't accidentally "freeze" or discard any custom user-level catalogs from ~/.specify/extension-catalogs.yml into the project config when an approval takes place.
  2. Simplified Approval Prompts: We implemented get_installable_extension_info to automatically select the first approved source for a given extension. If you have an approved version of the extension in another catalog, the CLI will now gracefully install it without reprompting you for approval on the blocked catalog.
  3. Test Formatting: Converted the very long with patch(...) blocks in test_extensions.py into multi-line parenthesized context managers for better readability, as requested.

All test suites have been run locally and are passing successfully! Let me know if there's anything else!

Copilot AI review requested due to automatic review settings June 17, 2026 09:51
@DyanGalih DyanGalih force-pushed the feature/interactive-catalog-approval branch from 94dfba1 to 83d8013 Compare June 17, 2026 09:51

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

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

Comment thread src/specify_cli/extensions.py
Comment thread src/specify_cli/__init__.py Outdated
Comment thread tests/test_extensions.py
Comment thread src/specify_cli/extensions.py
Comment thread src/specify_cli/extensions.py Outdated
@DyanGalih

Copy link
Copy Markdown
Contributor Author

I have pushed an additional update to address the remaining feedback points from the review:

  1. Path Checks & Config Safety: Reordered approve_catalog_install so path containment checks (is_relative_to) and symlink safety checks run before reading or creating directories. Also removed duplicate computation of config_path.
  2. Dangling Symlink Logic: In extensions.py, replaced exists() with is_symlink() first when removing backup directories, avoiding rmtree() crashes on broken dangling symlinks.
  3. Graceful CLI Exit on ValidationError: In specify_cli/__init__.py, wrapped the approve_catalog_install call with try...except ValidationError to catch issues (like symlinked catalogs) and gracefully print an error message instead of showing a raw traceback.
  4. Optimized Extension Lookups: Delayed calling catalog.get_installable_extension_info() until after checking if the current extension is blocked (_install_allowed == False), skipping unnecessary fetches on the happy path.
  5. Test Mocking: Added the missing get_installable_extension_info mocks in the test blocks of test_extensions.py so we don't accidentally perform real catalog fetches in those tests.
  6. Note on Prereleases: The prereleases=True flag in the specifier check remains intentional to preserve the ability for contributors developing on main (like 0.11.1.dev0) to successfully test extension installations without failing compatibility tests, which was the original goal of that specific change!

All tests are passing locally. Thanks for the thorough review! ✨

@mnriem

mnriem commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Note this is not necessary at all as a user can add the community catalog as an authorized read/write catalog by using the catalog system. Note that this would mean the entire catalog is available for install so BUYER BEWARE. So can we close this?

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