From b5ea7047619f6af3117265d2db65425ea4a5a8fe Mon Sep 17 00:00:00 2001 From: tachyon-r <291518778+tachyon-r@users.noreply.github.com> Date: Sat, 29 Aug 2026 04:03:32 -0400 Subject: [PATCH 1/2] fix: declare security-guidance hooks in manifest --- plugins/security-guidance/plugin.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/security-guidance/plugin.yaml b/plugins/security-guidance/plugin.yaml index 97567299954b5..0224a28029806 100644 --- a/plugins/security-guidance/plugin.yaml +++ b/plugins/security-guidance/plugin.yaml @@ -2,6 +2,6 @@ name: security-guidance version: "0.1.0" description: "Append security warnings to file-write tool results when the new content contains known-dangerous patterns (pickle.load, yaml.load, eval(, os.system, dangerouslySetInnerHTML, verify=False, ECB, XXE, GitHub Actions injection, ...). 25 regex/substring rules forked from Anthropic's claude-plugins-official under Apache-2.0. Non-blocking — the file is written and the warning rides back to the model in the next turn so it can self-correct." author: "Anthropic (patterns, Apache-2.0) / NousResearch (Hermes plugin port)" -hooks: +provides_hooks: - transform_tool_result - pre_tool_call From 467cad747707f1a29627e4de85c07d7fc4c63da9 Mon Sep 17 00:00:00 2001 From: tachyon-r <291518778+tachyon-r@users.noreply.github.com> Date: Sun, 30 Aug 2026 13:22:43 -0400 Subject: [PATCH 2/2] test(security-guidance): verify declared hooks --- .../plugins/test_security_guidance_plugin.py | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/plugins/test_security_guidance_plugin.py b/tests/plugins/test_security_guidance_plugin.py index a00bafddcde98..47d7dab640ea1 100644 --- a/tests/plugins/test_security_guidance_plugin.py +++ b/tests/plugins/test_security_guidance_plugin.py @@ -262,13 +262,34 @@ def test_blocks_in_block_mode_on_dangerous_pattern(self, monkeypatch): # --------------------------------------------------------------------------- class TestPluginDiscovery: + def test_manifest_declares_registered_hooks(self): + """Manifest metadata must use the field consumed by plugin discovery.""" + import yaml + + plugin_dir = _repo_root() / "plugins" / "security-guidance" + manifest = yaml.safe_load( + (plugin_dir / "plugin.yaml").read_text(encoding="utf-8") + ) + mod = _load_plugin_init() + registered = [] + + class HookContext: + def register_hook(self, name, _callback): + registered.append(name) + + mod.register(HookContext()) + assert set(manifest["provides_hooks"]) == set(registered) + assert "hooks" not in manifest + def test_loads_via_plugin_manager(self, _isolate_env, monkeypatch): """End-to-end: enable in config.yaml and verify the PluginManager picks it up via the standard discovery path.""" import yaml config = {"plugins": {"enabled": ["security-guidance"]}} - (_isolate_env / "config.yaml").write_text(yaml.safe_dump(config)) + (_isolate_env / "config.yaml").write_text( + yaml.safe_dump(config), encoding="utf-8" + ) # Wipe any cached plugin state from earlier tests in this worker. for k in list(sys.modules):