fix(guardrails): add plugin config for runtime loading + firing integration test#131
fix(guardrails): add plugin config for runtime loading + firing integration test#131
Conversation
Without `"plugin": [...]` in opencode.json, the guardrail.ts and team.ts plugins are never loaded at runtime. The scenario tests pass because they call Plugin.trigger() directly, bypassing config-based loading. Verified via: `OPENCODE_CONFIG_DIR=./packages/guardrails/profile opencode debug config --print-logs` → "loading plugin" log entries for both guardrail.ts and team.ts confirmed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verifies the complete plugin lifecycle from config to runtime: 1. Plugin is discovered from profile opencode.json plugin field 2. Config.get() includes plugin references 3. session.created fires and initializes state.json with all fields 4. events.jsonl records session.created 5. Secret file read triggers hard block 6. Test execution tracking (tests_executed flag) 7. shell.env exposes OPENCODE_GUARDRAIL_MODE/ROOT/STATE 20 tests / 208 assertions ALL PASS. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
New PR opened -- automated review will run on the next push. To trigger a manual review, comment |
|
This PR doesn't fully meet our contributing guidelines and PR template. What needs to be fixed:
Please edit this PR description to address the above within 2 hours, or it will be automatically closed. If you believe this was flagged incorrectly, please let a maintainer know. |
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
|
The following comment was made by an LLM, it may be inaccurate: |
There was a problem hiding this comment.
Pull request overview
This PR ensures the Guardrails profile actually loads its plugins at runtime by registering them in the profile’s opencode.json, and adds a scenario integration test intended to validate plugin discovery + guardrail firing behavior end-to-end.
Changes:
- Register Guardrails profile plugins via the
pluginfield inpackages/guardrails/profile/opencode.json. - Add a scenario test that verifies the guardrail plugin is discoverable, initializes state on
session.created, blocks secret reads, tracks test execution, and exports env vars.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/opencode/test/scenario/guardrails.test.ts | Adds an integration-style scenario test to validate guardrail plugin loading and core hook behaviors. |
| packages/guardrails/profile/opencode.json | Registers guardrail/team plugins so they are loadable from config at runtime. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| await withProfile(async () => { | ||
| await using tmp = await tmpdir({ git: true }) | ||
| const files = guard(tmp.path) | ||
|
|
||
| await Instance.provide({ | ||
| directory: tmp.path, | ||
| fn: async () => { | ||
| // 1. Verify plugin is loaded from config | ||
| const plugins = await Plugin.list() |
There was a problem hiding this comment.
This new integration test sets OPENCODE_CONFIG_DIR to the guardrails profile directory via withProfile(). Config will auto-discover and load plugins/*.{ts,js} from every config directory (see packages/opencode/src/config/config.ts:320-330), so the guardrail plugin may be loaded even if the opencode.json plugin field were missing. As a result, the test may not actually validate the PR’s fix (loading via the config plugin list). Consider adjusting this test to load the profile config via OPENCODE_CONFIG (a single file) or a temp config file that includes the plugin list but does not reside in a directory containing plugins/, so the only way the plugin can load is through cfg.plugin resolution.
Summary
"plugin"field to guardrails profileopencode.jsonsoguardrail.tsandteam.tsare loaded at runtimeRoot Cause
The guardrails plugin existed in
plugins/directory but was never registered inopencode.json'spluginfield. Scenario tests passed because they callPlugin.trigger()directly (bypassing config-based loading). At runtime via binary, the plugin was never loaded.Fixes #132
Changes
packages/guardrails/profile/opencode.json: Add"plugin": ["./plugins/guardrail.ts", "./plugins/team.ts"]packages/opencode/test/scenario/guardrails.test.ts: Add integration test (7 assertions):Config.get()includes plugin referencessession.createdfires and initializes state.json with all Wave 8 fieldsevents.jsonlrecords session eventstests_executedflag)shell.envexposesOPENCODE_GUARDRAIL_MODE/ROOT/STATETest plan
bun test test/scenario/guardrails.test.ts— 20/20 PASS (208 assertions)bun turbo typecheck— 13/13 PASSopencode debug config --print-logs🤖 Generated with Claude Code