Skip to content

Conversation

@clement-tourriere
Copy link
Contributor

@clement-tourriere clement-tourriere commented Jan 16, 2026

Context

This PR introduces an enterprise plugin system for ggshield, allowing organizations to extend ggshield with additional capabilities through plugins distributed by GitGuardian.

What has been done

New Plugin Commands

Added a new ggshield plugin command group with the following subcommands:

  • ggshield plugin status - Show available plugins for your GitGuardian account based on your plan and entitlements
  • ggshield plugin install - Download and install a plugin from GitGuardian
  • ggshield plugin list - List installed plugins with their version and enabled/disabled status
  • ggshield plugin update [|--all|--check] - Update installed plugins to the latest version
  • ggshield plugin enable - Enable an installed plugin
  • ggshield plugin disable - Disable a plugin without uninstalling
  • ggshield plugin uninstall - Remove an installed plugin

Core Plugin Infrastructure

  • Entitlements client: Fetches available plugins from GitGuardian API based on the user's account/plan
  • Plugin downloader: Securely downloads plugin wheels with SHA256 verification
  • Plugin loader: Discovers and loads plugins from local wheels or pip-installed entry points
  • Enterprise config: Persists plugin settings (enabled/disabled state, versions)
  • Plugin registry: Central registry for loaded plugins to register their capabilities

Validation

PR check list

  • As much as possible, the changes include tests (unit and/or functional)
  • If the changes affect the end user (new feature, behavior change, bug fix) then the PR has a changelog entry (see doc/dev/getting-started.md). If the changes do not affect the end user, then the skip-changelog label has been added to the PR.

@clement-tourriere clement-tourriere self-assigned this Jan 16, 2026
@clement-tourriere clement-tourriere requested a review from a team as a code owner January 16, 2026 07:56
Copy link
Collaborator

@agateau-gg agateau-gg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Started to review but then realized:

  • There is no description
  • CI is red

Can you fix those first? Putting the PR in draft for now.

@agateau-gg agateau-gg marked this pull request as draft January 26, 2026 09:50
@clement-tourriere clement-tourriere force-pushed the poc_plugins branch 4 times, most recently from 9b29a08 to be0a29f Compare January 26, 2026 15:16
@codecov
Copy link

codecov bot commented Jan 26, 2026

Codecov Report

❌ Patch coverage is 94.47236% with 77 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.50%. Comparing base (37820fd) to head (373a19c).

Files with missing lines Patch % Lines
ggshield/cmd/plugin/update.py 85.79% 25 Missing ⚠️
ggshield/core/plugin/downloader.py 93.04% 21 Missing ⚠️
ggshield/core/plugin/loader.py 95.89% 8 Missing ⚠️
ggshield/__main__.py 75.86% 7 Missing ⚠️
ggshield/cmd/plugin/install.py 98.34% 3 Missing ⚠️
ggshield/cmd/utils/context_obj.py 75.00% 3 Missing ⚠️
ggshield/core/plugin/client.py 97.50% 3 Missing ⚠️
ggshield/cmd/plugin/manage.py 97.22% 2 Missing ⚠️
ggshield/core/config/enterprise_config.py 96.49% 2 Missing ⚠️
ggshield/core/plugin/platform.py 94.44% 2 Missing ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1167      +/-   ##
==========================================
+ Coverage   92.05%   92.50%   +0.45%     
==========================================
  Files         144      160      +16     
  Lines        6255     7646    +1391     
==========================================
+ Hits         5758     7073    +1315     
- Misses        497      573      +76     
Flag Coverage Δ
unittests 92.50% <94.47%> (+0.45%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@clement-tourriere clement-tourriere force-pushed the poc_plugins branch 3 times, most recently from a51d3a7 to 19a5e5c Compare February 2, 2026 08:45
@clement-tourriere clement-tourriere force-pushed the poc_plugins branch 3 times, most recently from 6c77613 to ffeb247 Compare February 3, 2026 09:08
@clement-tourriere clement-tourriere marked this pull request as ready for review February 3, 2026 09:13
@clement-tourriere clement-tourriere force-pushed the poc_plugins branch 3 times, most recently from b757666 to abaff2c Compare February 9, 2026 10:15
Add the foundational plugin system for ggshield:
- GGShieldPlugin base class and PluginMetadata
- PluginRegistry for tracking loaded plugins
- PluginLoader for discovering plugins from entry points and wheels
- PluginAPIClient for fetching plugins from GitGuardian API
- PluginDownloader for downloading and installing plugin wheels
- EnterpriseConfig for plugin configuration
- Platform detection utilities for wheel selection
Add ggshield plugin subcommands:
- status: Show available plugins for account
- install: Download and install a plugin
- list: List installed plugins
- enable/disable: Toggle plugin state
- update: Update installed plugins
- uninstall: Remove a plugin

Integrate plugin loading into main entry point.
Add developer documentation for the enterprise plugin system
and update project configuration.
Add --instance option to the root CLI group so it's available to all
subcommands including plugin commands. This allows users to specify
a custom GitGuardian instance URL before any subcommand.
Add support for installing plugins from multiple sources:
- Local wheel files: `ggshield plugin install ./plugin.whl`
- HTTPS URLs with optional SHA256 verification
- GitHub release assets with repo tracking
- GitHub Actions artifacts (requires GITHUB_TOKEN)

Extend update system to track plugin sources in manifest and support
auto-updates for GitGuardian API and GitHub release plugins. Non-updatable
sources (local files, artifacts) are clearly identified.

Includes security warnings for non-GitGuardian sources and HTTPS enforcement.
Plugins with same entry point name from both pip and local wheel were
showing up twice in `plugin list`. Now local wheels are discovered first
and their entry point names are used for deduplication.

Changes:
- Discover local wheels first, extract entry point names from wheels
- Use entry point name (not package name) as plugin identifier
- Skip pip entry points that match local wheel entry point names
- Support lookup by entry point name in downloader (is_installed, uninstall)
When trying to uninstall a pip-installed plugin via `ggshield plugin
uninstall`, show a helpful error message with the pip uninstall command
instead of just saying "not installed".
Python cannot import native extensions (.so/.pyd files) directly from
zip archives. Wheels containing native modules are now extracted to a
directory before loading.

The extracted directory is placed alongside the wheel file and is
automatically re-extracted if the wheel is updated.
Add comprehensive tests for:
- URL download edge cases (invalid scheme, network errors, invalid wheel)
- GitHub artifact success path and error handling
- _get_gh_token helper function
- Non-updatable plugin handling in update command
- GitHub release update checking helper functions
- Error handling in all install source types
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