mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-04 00:03:59 +00:00
fix(plugin): DisablePlugin 禁止禁用未安装插件,防止脏写 disabled_plugins
问题:POST /api/v1/plugins/<name>/disable 对不存在的插件也会把它写进 disabled_plugins 表(registry.go DisablePlugin 无条件 AddDisabledPlugin), 产生脏数据堆积,且同名插件日后真实安装会被误判为已禁用。 修复: - registry.go 新增 pluginInstalled(name):已加载 / 已注册工厂(内置) / 插件目录存在, 任一命中视为已安装 - DisablePlugin 开头校验:未安装返回 'plugin X not installed',不写 disabled_plugins - webui handler:未安装→404,已禁用→409(原都返回500);enable 失败含'failed'→404 - 新增 registry_disable_test.go:覆盖未安装拒绝/内置判定/目录存在判定/普通文件不算 本机端到端验证:disable 不存在插件返回404且表无脏数据;真实插件 disable/enable 正常
This commit is contained in:
74
internal/plugin/registry_disable_test.go
Normal file
74
internal/plugin/registry_disable_test.go
Normal file
@ -0,0 +1,74 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
sdk "gitcode.com/JianFeeeee/HomeAgent/internal/sdk"
|
||||
)
|
||||
|
||||
// TestDisablePluginNotInstalled 验证 DisablePlugin 对未安装插件的拒绝:
|
||||
// 修复前会把任意名字写进 disabled_plugins 表(脏数据),修复后应直接报错。
|
||||
func TestDisablePluginNotInstalled(t *testing.T) {
|
||||
r := &Registry{
|
||||
plugins: make(map[string]sdk.Plugin),
|
||||
factories: make(map[string]NativeFactory),
|
||||
knownDisabled: make(map[string]bool),
|
||||
plgDir: t.TempDir(),
|
||||
}
|
||||
err := r.DisablePlugin("nonexistent_test_xyz", "test")
|
||||
if err == nil {
|
||||
t.Fatal("DisablePlugin should reject a plugin that is not installed")
|
||||
}
|
||||
if err.Error() != "plugin nonexistent_test_xyz not installed" {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if r.knownDisabled["nonexistent_test_xyz"] {
|
||||
t.Fatal("knownDisabled must not contain a non-installed plugin")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPluginInstalledFactory 内置插件(工厂注册,无物理目录)应视为已安装。
|
||||
func TestPluginInstalledFactory(t *testing.T) {
|
||||
r := &Registry{
|
||||
plugins: make(map[string]sdk.Plugin),
|
||||
factories: map[string]NativeFactory{"builtin_demo": nil},
|
||||
knownDisabled: make(map[string]bool),
|
||||
plgDir: t.TempDir(),
|
||||
}
|
||||
if !r.pluginInstalled("builtin_demo") {
|
||||
t.Fatal("factory-registered builtin plugin should be considered installed")
|
||||
}
|
||||
if r.pluginInstalled("no_such_plugin") {
|
||||
t.Fatal("unknown plugin should not be considered installed")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPluginInstalledDir 外部插件按 plgDir/<name> 目录存在判定已安装。
|
||||
func TestPluginInstalledDir(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
if err := os.MkdirAll(filepath.Join(dir, "external_demo"), 0o755); err != nil {
|
||||
t.Fatalf("mkdir: %v", err)
|
||||
}
|
||||
r := &Registry{
|
||||
plugins: make(map[string]sdk.Plugin),
|
||||
factories: make(map[string]NativeFactory),
|
||||
knownDisabled: make(map[string]bool),
|
||||
plgDir: dir,
|
||||
}
|
||||
if !r.pluginInstalled("external_demo") {
|
||||
t.Fatal("plugin with an existing directory should be considered installed")
|
||||
}
|
||||
// 同名普通文件(非目录)不算已安装
|
||||
if err := os.WriteFile(filepath.Join(dir, "just_a_file"), []byte("x"), 0o644); err != nil {
|
||||
t.Fatalf("write: %v", err)
|
||||
}
|
||||
if r.pluginInstalled("just_a_file") {
|
||||
t.Fatal("a regular file must not count as an installed plugin")
|
||||
}
|
||||
// 空名兜底
|
||||
if r.pluginInstalled("") {
|
||||
t.Fatal("empty plugin name must not be considered installed")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user