diff --git a/pkg/agent/plugin_test.go b/pkg/agent/plugin_test.go index 7bbcd3624..c02cf6eaa 100644 --- a/pkg/agent/plugin_test.go +++ b/pkg/agent/plugin_test.go @@ -17,6 +17,10 @@ func (p blockingPlugin) Name() string { return "block-outbound" } +func (p blockingPlugin) APIVersion() string { + return plugin.APIVersion +} + func (p blockingPlugin) Register(r *hooks.HookRegistry) error { r.OnMessageSending("block-all", 0, func(_ context.Context, e *hooks.MessageSendingEvent) error { e.Cancel = true diff --git a/pkg/plugin/demoplugin/policy_demo.go b/pkg/plugin/demoplugin/policy_demo.go index c0b10b932..1b0f56572 100644 --- a/pkg/plugin/demoplugin/policy_demo.go +++ b/pkg/plugin/demoplugin/policy_demo.go @@ -8,6 +8,7 @@ import ( "time" "github.com/sipeed/picoclaw/pkg/hooks" + "github.com/sipeed/picoclaw/pkg/plugin" ) // PolicyDemoConfig controls the demo plugin behavior. @@ -108,6 +109,10 @@ func (p *PolicyDemoPlugin) Name() string { return "policy-demo" } +func (p *PolicyDemoPlugin) APIVersion() string { + return plugin.APIVersion +} + func (p *PolicyDemoPlugin) Snapshot() PolicyDemoStats { p.mu.Lock() defer p.mu.Unlock() diff --git a/pkg/plugin/manager.go b/pkg/plugin/manager.go index 03be959c9..bf671bb20 100644 --- a/pkg/plugin/manager.go +++ b/pkg/plugin/manager.go @@ -22,6 +22,7 @@ const APIVersion = "v1alpha1" // Plugin is the Phase-1 compile-time contract for PicoClaw extensions. type Plugin interface { Name() string + APIVersion() string Register(*hooks.HookRegistry) error } @@ -62,6 +63,17 @@ func (m *Manager) Register(p Plugin) error { if name == "" { return errors.New("plugin name is required") } + if got := strings.TrimSpace(p.APIVersion()); got != APIVersion { + if got == "" { + got = "" + } + return fmt.Errorf( + "plugin %q api version mismatch: got %s, want %s", + name, + got, + APIVersion, + ) + } m.mu.Lock() defer m.mu.Unlock() @@ -85,4 +97,3 @@ func (m *Manager) RegisterAll(plugins ...Plugin) error { } return nil } - diff --git a/pkg/plugin/manager_test.go b/pkg/plugin/manager_test.go index 8684dbc3a..8b8e431e7 100644 --- a/pkg/plugin/manager_test.go +++ b/pkg/plugin/manager_test.go @@ -10,6 +10,7 @@ import ( type testPlugin struct { name string + apiVersion string registerFn func(*hooks.HookRegistry) error } @@ -24,6 +25,13 @@ func (p testPlugin) Register(r *hooks.HookRegistry) error { return nil } +func (p testPlugin) APIVersion() string { + if p.apiVersion == "" { + return APIVersion + } + return p.apiVersion +} + func TestNewManager(t *testing.T) { m := NewManager() if m == nil { @@ -110,3 +118,14 @@ func TestRegisterPropagatesPluginError(t *testing.T) { } } +func TestRegisterRejectsPluginVersionMismatch(t *testing.T) { + m := NewManager() + p := testPlugin{ + name: "old-plugin", + apiVersion: "v0", + } + err := m.Register(p) + if err == nil { + t.Fatal("expected version mismatch error") + } +}