This repository currently manages one plugin class: Rust plugins that are built with PyO3/maturin and published to PyPI as Python packages.
Managed plugin path:
plugins/rust/python-package/<slug>/
Every managed plugin must satisfy the catalog contract enforced by tools/plugin_catalog.py:
- distribution name:
cpex-<slug> - Python module:
cpex_<slug> Cargo.tomlis the version source of truthcpex_<slug>/plugin-manifest.yamlversion matchesCargo.tomlcpex_<slug>/plugin-manifest.yamldefines top-levelkindinmodule.objectformpyproject.tomlpublishes the matching plugin class reference under[project.entry-points."cpex.plugins"]inmodule:objectform- plugin
Cargo.tomlrepository metadata points tohttps://github.com/IBM/cpex-plugins - plugin crate is listed in the top-level workspace
Cargo.toml
cd plugins/rust/python-package/rate_limiter
uv sync --dev
make install
make test-allSwap rate_limiter for any other managed plugin slug.
secrets_detection reports one finding per non-overlapping secret span. When
multiple enabled patterns match the same bytes, or overlapping bytes, the scanner
redacts the merged span once and reports the most specific matching detector
type. Distinct non-overlapping secrets in the same payload still count
separately.
This changed older behavior that could count overlapping broad and specific
pattern matches as multiple findings. Operators using min_findings_to_block
values greater than 1 should audit thresholds when upgrading.
make plugins-list
make plugins-validate
make plugin-test PLUGIN=pii_filtermake plugins-validate runs the same convention checks that the repo contract CI workflow runs.
It runs the catalog validator plus the shared repo contract test modules:
tests/test_plugin_catalog.py and tests/test_install_built_wheel.py.
The easiest way to create a new plugin is using the scaffold generator:
make plugin-scaffoldThis interactive tool will:
- Prompt for plugin name, description, author, and version
- Let you select from 12 available hooks across 5 categories
- Generate complete plugin structure with all required files
- Create comprehensive unit tests (Python and Rust)
- Set up build configuration and documentation
For non-interactive mode:
python3 tools/scaffold_plugin.py --non-interactive \
--name my_plugin \
--description "My plugin description" \
--author "Your Name" \
--hooks prompt_pre_fetch,tool_pre_invokeAfter scaffolding:
- Review and customize the generated code in
plugins/rust/python-package/<slug>/ - The crate is automatically added to the workspace
Cargo.toml - Run
make plugins-validateto verify structure - Run
make plugin-test PLUGIN=<slug>to execute the plugin's fullmake ciflow
If you prefer to create a plugin manually:
- Create
plugins/rust/python-package/<slug>/. - Add the required files and package/module names that match the slug conventions.
- Add the crate path to the workspace
memberslist in the top-levelCargo.toml. - Run
make plugins-validate. - Run
make plugin-test PLUGIN=<slug>to execute the plugin's fullmake ciflow.
Releases are per plugin and version-bump driven. Use this process to publish a new version of an existing managed plugin to PyPI.
-
Pick the plugin slug and new version.
The plugin slug is the directory name under
plugins/rust/python-package/<slug>/, for examplerate_limiter. The tag slug is the hyphenated form, for examplerate-limiter. -
Update the version files.
Cargo.tomlis the version source of truth. The plugin manifest and top-level lockfile must stay consistent with it.$EDITOR plugins/rust/python-package/rate_limiter/Cargo.toml $EDITOR plugins/rust/python-package/rate_limiter/cpex_rate_limiter/plugin-manifest.yaml cargo update -p rate_limiter --precise 0.0.5
-
Run local validation.
make plugins-validate make plugin-test PLUGIN=rate_limiter
-
Merge the version bump to
main. -
Let CI create the release tag and publish.
On a
mainpush,.github/workflows/ci-rust-python-package.yamldetects pluginCargo.tomlversion bumps. After the build, security, coverage, and documentation jobs are green, it creates the release tag at the merge commit and invokes.github/workflows/release-rust-python-package.yamlwith PyPI publishing enabled.The workflow uses
GITHUB_TOKENto push release tags. Repository tag protection or rulesets for release tag patterns must allow that token, or the workflow must be updated to use an approved GitHub App or PAT token.Release tags use the hyphenated plugin slug, not the directory/module underscore form. CI creates tags in this form:
rate-limiter-v0.0.5
Examples:
rate_limiter->rate-limiter-v0.0.5secrets_detection->secrets-detection-v0.2.2
Use
make plugins-listto inspect the current managed plugin slugs and package names. Do not create the tag manually for ordinary releases; manual tag pushes are reserved for recovery or explicit release-maintainer action. -
Watch the release workflow and confirm publish success.
gh run list --workflow ci-rust-python-package.yaml --branch main --limit 5 gh run list --workflow release-rust-python-package.yaml --limit 5 gh run watch <run-id> --exit-status
-
Verify the package exists on PyPI at the new version.
uv run python -m pip index versions cpex-rate-limiter
The release page should also exist at
https://pypi.org/project/cpex-rate-limiter/0.0.5/.
The CI workflow creates tags only after the required checks pass. It then calls
the release workflow directly for publishing; it does not rely on a bot-created
tag push to start another workflow run. The release workflow resolves the tag
back to the managed plugin path, validates metadata and versions, then builds
and publishes only that plugin. PyPI publishing is allowed only for release tags
that point at main.
Dependency refresh work is separate from the release process. Track broader dependency or ContextForge updates outside a plugin release PR.