Skip to content

Plugin signing#1180

Open
clement-tourriere wants to merge 2 commits intomainfrom
plugin-signing
Open

Plugin signing#1180
clement-tourriere wants to merge 2 commits intomainfrom
plugin-signing

Conversation

@clement-tourriere
Copy link
Copy Markdown
Member

Context

The plugin system shipped in 1.48.0 used a --force flag to skip security warnings when installing from non-GitGuardian sources. This was a placeholder — it displayed a text warning but performed no actual
cryptographic verification.

This PR replaces that mechanism with real sigstore-based signature verification for plugin wheels, using OIDC identity-based trust (keyless). It also fixes a bug where the verification mode was not forwarded
through the GitHub release and artifact download paths.

What has been done

  • Add ggshield.core.plugin.signature module: keyless signature verification using sigstore bundles. Wheels are verified against a configurable set of trusted GitHub Actions workflow identities (OIDC). Three modes:
    STRICT (block unsigned/invalid), WARN (log and continue), DISABLED (skip).
  • Replace --force with --allow-unsigned: the new flag downgrades verification from STRICT to WARN instead of silently skipping a text warning. Verification mode is also configurable via plugin_signature_mode in
    enterprise config.
  • Forward signature_mode through all download paths: download_from_github_release and download_from_github_artifact now accept and forward signature_mode. The artifact path also calls verify_wheel_signature before
    writing the manifest (was missing entirely).
  • Show signature status in plugin status: installed plugins now display their signature status (e.g. valid (GitGuardian/satori), missing).
  • Suppress signature/loader log noise at startup: logger levels are temporarily raised during plugin loading in main.py to avoid noisy output before logging is configured.
  • Collapse repetitive tests in test_install.py: 12 near-duplicate error-handling tests reduced to 4 parameterized tests + 1 standalone. Merged the two test_install_unavailable_plugin variants into a single
    parameterized test.
  • Add sigstore dependency to pyproject.toml.

Validation

pdm run pytest tests/unit/core/plugin/ tests/unit/cmd/plugin/ -x -q

All 246 tests pass. To manually test signature verification:

  • ggshield plugin install tokenscanner — should verify signature in STRICT mode (default)
  • ggshield plugin install tokenscanner --allow-unsigned — should warn but proceed
  • ggshield plugin install ./unsigned.whl — should fail in STRICT mode with a clear error pointing to --allow-unsigned
  • ggshield plugin status — should show signature status for installed plugins

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 requested review from a team as code owners February 19, 2026 15:02
@codecov
Copy link
Copy Markdown

codecov bot commented Feb 19, 2026

Codecov Report

❌ Patch coverage is 95.67100% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.14%. Comparing base (e653e78) to head (69d06b7).

Files with missing lines Patch % Lines
ggshield/core/plugin/downloader.py 88.88% 9 Missing ⚠️
ggshield/core/plugin/loader.py 91.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1180      +/-   ##
==========================================
+ Coverage   92.91%   93.14%   +0.23%     
==========================================
  Files         171      172       +1     
  Lines        8329     8525     +196     
==========================================
+ Hits         7739     7941     +202     
+ Misses        590      584       -6     
Flag Coverage Δ
unittests 93.14% <95.67%> (+0.23%) ⬆️

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.

sevbch
sevbch previously requested changes Feb 24, 2026
Copy link
Copy Markdown
Collaborator

@sevbch sevbch left a comment

Choose a reason for hiding this comment

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

I only reviewed files outside of **/plugin/* paths, since those will be reviewed by @GitGuardian/nhi-governance

Comment thread ggshield/core/config/enterprise_config.py
Comment thread ggshield/core/config/enterprise_config.py Outdated
Comment thread ggshield/core/config/enterprise_config.py
Comment thread changelog.d/20260219_155531_clement.tourriere_plugin_signing.md
Comment thread ggshield/__main__.py Outdated
@sevbch sevbch removed their request for review February 24, 2026 14:30
@clement-tourriere clement-tourriere force-pushed the plugin-signing branch 3 times, most recently from c34beee to d94d897 Compare April 15, 2026 13:11
@6d7a 6d7a requested review from 6d7a and mattisdalleau-gg April 15, 2026 15:03
Comment thread ggshield/core/plugin/signature.py
Comment thread ggshield/core/plugin/signature.py Outdated
Comment thread ggshield/core/plugin/downloader.py
Comment thread ggshield/core/config/enterprise_config.py Outdated
Copy link
Copy Markdown
Contributor

@6d7a 6d7a left a comment

Choose a reason for hiding this comment

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

I guess Mattis was faster than me 😁
Just one additional suggestion.

Comment thread ggshield/core/plugin/downloader.py
@clement-tourriere clement-tourriere force-pushed the plugin-signing branch 2 times, most recently from f8ee146 to 2ab66c9 Compare April 16, 2026 06:49
Comment thread ggshield/cmd/plugin/install.py
Copy link
Copy Markdown
Contributor

@6d7a 6d7a left a comment

Choose a reason for hiding this comment

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

LGTM. Thank you for the changes!

…re_mode

Add keyless signature verification for plugin wheels using sigstore
bundles with OIDC identity-based trust. Replace --force flag with
--allow-unsigned and enterprise config signature mode support.

Forward signature_mode through all download paths (GitHub release,
GitHub artifact, URL, local wheel). Collapse repetitive install error
tests into parametrized ones.
@clement-tourriere clement-tourriere dismissed sevbch’s stale review April 16, 2026 14:34

Everything has been taken into account :)

@clement-tourriere clement-tourriere requested a review from 6d7a April 16, 2026 14:34
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.

4 participants