WebAssembly plugin support with end-to-end host invocation#64
Draft
monshri wants to merge 30 commits into
Draft
Conversation
… files (contextforge-org#48) * fix: respect PLUGINS_LOG_LEVEL environment variable in all runtime.py files - Updated grpc/server/runtime.py to check PLUGINS_LOG_LEVEL env var before command-line arg - Updated mcp/server/runtime.py to add logging configuration with PLUGINS_LOG_LEVEL support - Updated unix/server/runtime.py to respect PLUGINS_LOG_LEVEL instead of hardcoded INFO level - All implementations now log to stderr and follow consistent pattern * refactor: use get_settings().log_level instead of hardcoded env var Address PR review feedback to use the settings infrastructure instead of directly accessing environment variables. This approach: - Keeps the env var name defined in one place (PluginsSettings model) - Gets .env file support for free - Stays consistent with how other settings are read in the codebase Changes: - grpc/server/runtime.py: Use get_settings().log_level with fallback to args - mcp/server/runtime.py: Use get_settings().log_level - unix/server/runtime.py: Use get_settings().log_level --------- Co-authored-by: Bogdan-Marius-Catanus <bogdan-marius.catanus@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
* feat: initial revision rust core. Signed-off-by: Teryl Taylor <terylt@ibm.com> * fix: addressed comments in PR. Updated PluginContext to match spec. Signed-off-by: Teryl Taylor <terylt@ibm.com> --------- Signed-off-by: Teryl Taylor <terylt@ibm.com> Co-authored-by: Teryl Taylor <terylt@ibm.com>
* feat: added yaml and routing rule support. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: added example code to show how to load manager and plugins. Signed-off-by: Teryl Taylor <terylt@ibm.com> * fixes: updated plugin errors, configs to more match python. Signed-off-by: Teryl Taylor <terylt@ibm.com> --------- Signed-off-by: Teryl Taylor <terylt@ibm.com> Co-authored-by: Teryl Taylor <terylt@ibm.com>
* feat: initial revision rust core. Signed-off-by: Teryl Taylor <terylt@ibm.com> * fix: addressed comments in PR. Updated PluginContext to match spec. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: added yaml and routing rule support. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: added example code to show how to load manager and plugins. Signed-off-by: Teryl Taylor <terylt@ibm.com> * fixes: updated plugin errors, configs to more match python. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: RUST CMF initial revision. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: added invoke named support, added constants, fixed reviewed code. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: added owned extensions and did some refactoring. Signed-off-by: Teryl Taylor <terylt@ibm.com> --------- Signed-off-by: Teryl Taylor <terylt@ibm.com> Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> Co-authored-by: Teryl Taylor <terylt@ibm.com> Co-authored-by: Frederico Araujo <frederico.araujo@ibm.com>
* feat: initial revision rust core. Signed-off-by: Teryl Taylor <terylt@ibm.com> * fix: addressed comments in PR. Updated PluginContext to match spec. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: added yaml and routing rule support. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: added example code to show how to load manager and plugins. Signed-off-by: Teryl Taylor <terylt@ibm.com> * fixes: updated plugin errors, configs to more match python. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: RUST CMF initial revision. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: added invoke named support, added constants, fixed reviewed code. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: added owned extensions and did some refactoring. Signed-off-by: Teryl Taylor <terylt@ibm.com> * feat: added cgo and golang bindings, examples and readme. Signed-off-by: Teryl Taylor <terylt@ibm.com> * address P0/P1/P2 review findings (except contextforge-org#17) Signed-off-by: Teryl Taylor <terylt@ibm.com> * fix: address remaining P2/P3 review findings + testing gaps Signed-off-by: Teryl Taylor <terylt@ibm.com> * docs: add CPEX Go public API spec Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * docs: renamed document Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * feat(cpex-rust): CGO review passes 1-11 + lint cleanup + Makefile targets Signed-off-by: Teryl Taylor <terylt@ibm.com> * fix: address linting issues, updated makefile to support building examples. Signed-off-by: Teryl Taylor <terylt@ibm.com> * docs: updated the go spec to reflect recent changes. Signed-off-by: Teryl Taylor <terylt@ibm.com> --------- Signed-off-by: Teryl Taylor <terylt@ibm.com> Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> Co-authored-by: Teryl Taylor <terylt@ibm.com> Co-authored-by: Frederico Araujo <frederico.araujo@ibm.com>
Co-authored-by: Teryl Taylor <terylt@ibm.com>
…g#49) Co-authored-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
…g#55) * fix: implement __eq__ and __ne__ for CopyOnWriteDict Fixes equality comparison bug where CopyOnWriteDict compared equal to {} even when containing data. This caused apply_policy() to incorrectly drop valid payload modifications when plugins removed all arguments. Changes: - Add __eq__ and __ne__ methods to CopyOnWriteDict - Add 13 comprehensive equality unit tests - Add policy regression tests for empty args scenario - Add end-to-end integration tests Signed-off-by: prakhar-singh1928 <prakhar.singh1928@ibm.com> * fix: added length check for performance Signed-off-by: prakhar-singh1928 <prakhar.singh1928@ibm.com> * fix: restore deleted assertion and add performance optimization - Restored missing 'assert a not in keys' in test_iteration_order_with_deletions - Added fast-path length check in CopyOnWriteDict.__eq__() for better performance - Performance optimization is safe: if lengths differ, mappings cannot be equal Signed-off-by: prakhar-singh1928 <prakhar.singh1928@ibm.com> * fix: linted memory.py, added assertion to test. --------- Signed-off-by: prakhar-singh1928 <prakhar.singh1928@ibm.com> Co-authored-by: Teryl Taylor <teryl.taylor@gmail.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
…orge-org#31) * chore: provde better examples for PluginPackageInfo constructor Signed-off-by: habeck <habeck@us.ibm.com> * enh: add PluginVersionInfo and PluginVersionRegistry models w/unit tests Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * chore: unit tests and fixtures for plugin isolation via venv. Signed-off-by: habeck <habeck@us.ibm.com> * enh: refactored the invoke_hook method in cpex/framework/isolated/client.py to run async Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * chore: updated unit test test_worker to get coverage to 97%. Signed-off-by: habeck <habeck@us.ibm.com> * enh: The optimization eliminates the overhead of: Forking a new Python process (~1.2ms per fork_exec) Initializing the Python interpreter Loading modules and dependencies Setting up the subprocess communication pipes Signed-off-by: habeck <habeck@us.ibm.com> * fix: fail early plugin_path do not exist, computer .venv path automatically, update cli to support creating an isolated plugin. Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * fix: use the system config file (PLUGINS_CONFIG_FILE) for syspath update (Consistent with how the PluginManager works). Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * chore: Validate plugin_dirs entries against an allowlist Signed-off-by: habeck <habeck@us.ibm.com> * fix: remove hardcoded reference to plugins/config in the cpex/framework/isolated/client.py and update tests. remove methods_to_exclude from validator. Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * enh: Add a maximum line length check before parsing. Add model tests for PluginPackageInfo and PluginVersionRegistry Signed-off-by: habeck <habeck@us.ibm.com> * enh: model updates for PluginManifest, InstalledPluginInfo, and InstalledPluginRegistry Signed-off-by: habeck <habeck@us.ibm.com> * enh: example values for git monorepo installation Signed-off-by: habeck <habeck@us.ibm.com> * enh: add ConfigSaver class to ConfigLoader Signed-off-by: habeck <habeck@us.ibm.com> * enh: plugin installation catalog Signed-off-by: habeck <habeck@us.ibm.com> * enh: add support to enable installation of a plugin using the cli from a git monorepo, or pypi. Signed-off-by: habeck <habeck@us.ibm.com> * chore: doc string fix Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * chore: remove duplicate code Signed-off-by: habeck <habeck@us.ibm.com> * chore: test coverage improvements, remove duplicate code Signed-off-by: habeck <habeck@us.ibm.com> * chore: replace cargo with search for pyproject. Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fixes Signed-off-by: habeck <habeck@us.ibm.com> * enh: use pygithub apis rather than github rest apis, as they provide automatic backoff when github response with too many requests. Signed-off-by: habeck <habeck@us.ibm.com> * enh: add support for uninstall of plugin Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint-fix Signed-off-by: habeck <habeck@us.ibm.com> * fix: use the manifest from the local catalog to pull the kind value of the package to be removed and use that to remove all matching kind entries from plugins/config.yaml unless kind is external or isolated_venv in which case check if the plugin name is a substring of the plugin name. Signed-off-by: habeck <habeck@us.ibm.com> * fix: when installing a plugin via mono-repo or pipi, the cache_root will not exist under the plugins dir, create the directory if it does not exist on plugin startup for venv plugins. Signed-off-by: habeck <habeck@us.ibm.com> * enh: enable package install from both pypi and test-pypi, fix: properly resolve location of requirements.txt while performing pypi installs. Signed-off-by: habeck <habeck@us.ibm.com> * chore: stub for local installation Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * doc: add README for tools Signed-off-by: habeck <habeck@us.ibm.com> * enh: use cached repo object Signed-off-by: habeck <habeck@us.ibm.com> * chore: use rich emoji Signed-off-by: habeck <habeck@us.ibm.com> * ptf: workaround for version mis-match of cpex dependency in plugin Signed-off-by: habeck <habeck@us.ibm.com> * fix: download install targets to a temp folder to avoid installing to incorrect venv. Signed-off-by: habeck <habeck@us.ibm.com> * enh: pass the plugin install path to the update method, as isolated_venv plugins are not installed in the current venv. Signed-off-by: habeck <habeck@us.ibm.com> * enh: the catalog now returns the install path for isolated_venv plugins Signed-off-by: habeck <habeck@us.ibm.com> * chore: unit test updates Signed-off-by: habeck <habeck@us.ibm.com> * misc: type fix Signed-off-by: habeck <habeck@us.ibm.com> * enh: the plugin self installs into the isolated_venv via requirements.txt Signed-off-by: habeck <habeck@us.ibm.com> * chore: increase coverage above 90% Signed-off-by: habeck <habeck@us.ibm.com> * chore: update min_max_framework_version Signed-off-by: habeck <habeck@us.ibm.com> * enh: isolated venv cookiecutter update for install flow Signed-off-by: habeck <habeck@us.ibm.com> * enh: catalog now properly persists all plugin-manifest*.yaml files Signed-off-by: habeck <habeck@us.ibm.com> * enh: upgrade pip before installing requirements Signed-off-by: habeck <habeck@us.ibm.com> * enh: allow the developer provided version registry values to persist, overriding only if they are not present. Improved install path resolution for isolated_venv plugins Signed-off-by: habeck <habeck@us.ibm.com> * enh: only update the catalog when not installing from test-pypi or pypi. Correctly determine the install path for the plugin registry for monorepo installs and isolated_venv plugins. Signed-off-by: habeck <habeck@us.ibm.com> * enh: refactor to reduce duplicate code, fix uninstall for isolated_venv, add install support for type local, Signed-off-by: habeck <habeck@us.ibm.com> * chore: properly format info Signed-off-by: habeck <habeck@us.ibm.com> * chore: update README.md Signed-off-by: habeck <habeck@us.ibm.com> * chore: Add a, "before you begin" section detailing the required .env variable. Signed-off-by: habeck <habeck@us.ibm.com> * fix: P0 fix — tarfile/zip path traversal Signed-off-by: habeck <habeck@us.ibm.com> * enh: add remove_venv method to IsolatedVenvPlugin for uninstall cleanup. Signed-off-by: habeck <habeck@us.ibm.com> * fix: priority 1 items Signed-off-by: habeck <habeck@us.ibm.com> * fix: p2 item 17 search() case-insensitive match broken Signed-off-by: habeck <habeck@us.ibm.com> * chore: add tests for _ver method. Signed-off-by: habeck <habeck@us.ibm.com> * fix: version registry update cleanup Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * chore: add missing doc string, and tests for _ver method. Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * fix: review p2 moderate 21 - list function now uses console.print Signed-off-by: habeck <habeck@us.ibm.com> * chore: fix failing unit test, address non-atomic registry write. Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * chore: claude can't tell the difference between if "rc is False" and "if rc". Signed-off-by: habeck <habeck@us.ibm.com> * fix: cpex/framework/models.py — register_plugin (line 2392): replaced the unconditional append with a filter-then-append. Any existing entry with the same name is removed before the new one is added, so a reinstall upgrades the entry rather than creating a duplicate. One save() call, same atomicity as before. Signed-off-by: habeck <habeck@us.ibm.com> * fix: P2 Issue 20 Implementation Complete: Exit Code Handling Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * fix: list function shadows built-in Signed-off-by: habeck <habeck@us.ibm.com> * chore: logic tweak Signed-off-by: habeck <habeck@us.ibm.com> * fix: p2 issue 23 Signed-off-by: habeck <habeck@us.ibm.com> * fix: P2 issue 19 error handling for corrupted JSON registry Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * fix: P2 issue 24 - Registry file path triplicated Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint-fix Signed-off-by: habeck <habeck@us.ibm.com> * fix: P2 issue 25 Signed-off-by: habeck <habeck@us.ibm.com> * fix: update worker to call cpex.framework.utils.import_module rather than importlib.import_module directly. Signed-off-by: habeck <habeck@us.ibm.com> * enh: add package integrity verification Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * chore: missed commit Signed-off-by: habeck <habeck@us.ibm.com> * fix: if the plugins/config.yaml plugins array is empty, initialize it with the appropriate default from catalog settings. Signed-off-by: habeck <habeck@us.ibm.com> * chore: lint fix Signed-off-by: habeck <habeck@us.ibm.com> * chore: version to '0.1.0 minimum' Signed-off-by: habeck <habeck@us.ibm.com> --------- Signed-off-by: habeck <habeck@us.ibm.com>
Signed-off-by: habeck <habeck@us.ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
…ecker, audit_logger, header_injector Signed-off-by: Shriti Priya <shritip@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
Refactored from multi-feature-flag builds (identity_checker, audit_logger, header_injector as separate .wasm files) into a single plugin.wasm template. Users now write plugin logic in cpex-payload and point lib.rs to their function. - Remove feature flags and per-plugin structs; single Plugin struct with export!() - Remove unused plugin-config from WIT, clean up world.wit - Makefile builds one plugin.wasm; add validate/inspect targets (wasm-tools) - Add README documenting architecture, conversions layer, and plugin authoring steps - Add comments/license headers to all source files - Remove stale .wasm binaries and details.md
Signed-off-by: Shriti Priya <shritip@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
Signed-off-by: Shriti Priya <shritip@ibm.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WASM Plugin End-to-End Support
Resolves #21
Summary
Adds full WebAssembly plugin support using the WASI Component Model, enabling sandboxed plugin execution with fine-grained capability control over filesystem, HTTP, and environment access.
New crates:
cpex-wasm-host(Rust-based host runtime) andcpex-wasm-plugin(reusable plugin template), along with the Python packagecpex-payloadfor a lightweight, WebAssembly-compilable version ofcpex-corethat includes a synchronous plugin implementation (since WebAssembly does not support asynchronous execution).Architecture
cpex-wasm-plugincompiles plugins into a portableplugin.wasmbinary. The host (cpex-wasm-host) loads and executes the WASM plugin inside a sandboxed wasmtime environment. Enforces resource limits (fuel, memory, execution time) and network/filesystem policies. Provides a bridge to cpex-core'sPluginManagerfor integration into the hook pipeline.cpex-wasm-host— Host RuntimeLoads and executes
.wasmplugins inside a sandboxed wasmtime environment with resource limits (fuel, memory, execution time) and network/filesystem policies.sandbox_policykey). Deny-by-default when absent.cpex-coretypes and WIT types (JSON serialization for complex types at the boundary).cpex-core'sPluginFactorytrait:WasmPluginFactory→WasmBridgePlugin→WasmBridgeHandler.Usage Modes
SandboxManager, load a.wasmfile with aSandboxPolicy, callinvoke().WasmPluginFactorywith awasm://scheme, load config, invoke hooks through the standard pipeline.Details: Readme
cpex-wasm-plugin— Plugin TemplateCompiles CPEX plugins into a portable
plugin.wasmbinary, loaded and executed in the host sandbox.wit/world.wit) — Defines the host-plugin contract: a single exportedhandle-hookfunction receiving message payload, extensions, and plugin context; returns allow/deny.src/lib.rs— Plugin entry point implementing theGuesttrait; delegates to plugin logic incpex-payload.src/conversions.rs— Bidirectional type mapping between WIT flat types and rich Rust types.Details: Readme
cpex-payload— Plugin TemplateThis crate includes only the files required for plugin compilation. Compiling the entire cpex-core into a WebAssembly component caused issues, so this separation was necessary.
crates/cpex-payload/src/plugins/identity_checker.rsprovides the implementation of the plugin but withfnvsasync fn, since the WebAssembly Component Model does not yet support asynchronous calls.