feat(policy): support native PolicyPlugin exports from module files#114
Closed
yxbh wants to merge 3 commits into
Closed
feat(policy): support native PolicyPlugin exports from module files#114yxbh wants to merge 3 commits into
yxbh wants to merge 3 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds first-class support for module-exported “native” PolicyPlugin objects (with lifecycle hooks) alongside existing PolicyConfig-based policies, so policy authors can use the full plugin engine pipeline.
Changes:
- Introduces
isNativePlugin()andvalidateNativePlugin()to detect/validate native plugin exports. - Updates
loadPolicy()andloadPluginChain()to load nativePolicyPluginexports and forcesourceType: "module"+trust: "trusted-code". - Adds tests covering type guards/validation, loading native plugins, and engine execution behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/services/tests/policy-loader.test.ts | Adds end-to-end tests for loading/executing native plugin modules in a plugin chain. |
| src/services/tests/policy-engine-types.test.ts | Adds unit tests for isNativePlugin() and validateNativePlugin(). |
| packages/core/src/services/readiness/index.ts | Guards the legacy resolveChain path against native plugin exports. |
| packages/core/src/services/policy/types.ts | Adds the native plugin type guard + validator helpers. |
| packages/core/src/services/policy/loader.ts | Accepts native plugin exports directly into the engine chain with trusted-code trust. |
| packages/core/src/services/policy/index.ts | Re-exports the new helper APIs from the policy service entrypoint. |
| packages/core/src/services/policy.ts | Expands loadPolicy() to return `PolicyConfig |
Add support for loading native PolicyPlugin exports directly from .js/.mjs module files, enabling policy authors to use the full plugin lifecycle API (afterDetect, beforeRecommend, afterRecommend hooks with SignalPatch and RecommendationPatch) instead of being limited to the criteria.add/disable/ override DSL. Changes: - Add isNativePlugin() type guard and validateNativePlugin() to types.ts - Update loadPolicy() to detect and return native plugin exports - Update loadPluginChain() to add native plugins directly to the chain with trusted-code trust and module sourceType - Guard legacy resolveChain path against native plugin exports - Fix type narrowing in existing policy.test.ts for union return type - Add 20 new tests covering type guard, validation, loading, and end-to-end engine execution of native plugins Native plugins are detected by the presence of a meta property (with meta.name) on the module export, distinguishing them from PolicyConfig objects which have a top-level name string. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
c37df43 to
4c27ac7
Compare
- Tighten isNativePlugin() guard to require absence of root-level name string, preventing misclassification of PolicyConfig exports that happen to include a meta object - Fix Windows import() bug: use pathToFileURL() for local module paths to avoid ERR_UNSUPPORTED_ESM_URL_SCHEME on drive-letter paths (C:\) - Reword legacy path error message to be user-actionable instead of saying 'internal error' - Remove unused pathToFileURL import from test file Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
16f5a47 to
f381220
Compare
f381220 to
bcea5be
Compare
bcea5be to
bd4dc8c
Compare
bd4dc8c to
76e8fdf
Compare
Address Copilot review comments: 1. isNativePlugin() improved doc comment to describe actual detection rules (meta.name required, root-level name rejected). Added validation of meta.sourceType and meta.trust when present. 2. validateNativePlugin() now validates that hooks are functions, that detectors/recommenders are arrays, and that each array element has a valid id (non-empty string) and callable detect/recommend function. Errors are caught at load time with clear messages. 3. loadPolicy() doc comment aligned with actual isNativePlugin() rules. 4. readiness/index.ts auto-enable engine path for native plugins instead of throwing in legacy criteria path. Added 12 new tests (669 total passing). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
76e8fdf to
2552aef
Compare
Contributor
Author
|
Closing to open a clean PR with squashed history. |
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.
Summary
What changed
Add support for loading native
PolicyPluginexports directly from.js/.mjsmodule files. The plugin loader (loadPluginChain) now detects modules that export aPolicyPluginobject (identified by ametaproperty) and adds them directly to the plugin chain withtrusted-codetrust, instead of requiring compilation throughPolicyConfig.Files changed:
packages/core/.../policy/types.tsisNativePlugin()type guard andvalidateNativePlugin()packages/core/.../policy/index.tspackages/core/.../policy.tsloadPolicy()return type toPolicyConfig | PolicyPlugin, detect native exports, fix Windowsimport()withpathToFileURLpackages/core/.../policy/loader.tsloadPluginChain()— add directly to chainpackages/core/.../readiness/index.tsresolveChainpath against native plugin exportssrc/.../__tests__/policy-engine-types.test.tsisNativePluginandvalidateNativePluginsrc/.../__tests__/policy-loader.test.tssrc/.../__tests__/policy.test.tsloadPolicy()union return typeWhy it changed
The plugin engine already supports a rich 5-stage pipeline (
detect → afterDetect → beforeRecommend → recommend → afterRecommend) with immutable patch types (SignalPatch,RecommendationPatch). However,loadPluginChain()only acceptedPolicyConfigobjects and compiled them — module authors could not export a rawPolicyPluginto use the full hook API.This limited what policy modules can do:
Corporate/enterprise policies (e.g., tool governance, MCP server allow/deny lists) need these capabilities.
Example usage
Checklist