From 402ad078943770e174fe9504e8915d7e76584bd5 Mon Sep 17 00:00:00 2001 From: Artem Lytkin Date: Sat, 26 Sep 2026 02:24:40 +0300 Subject: [PATCH] config: Don't panic on plugin JSON files without a plugin entry A .json file in a plugin directory that decodes to an empty list (`[]` or `null`) made NewPluginInfo index info[0] on an empty slice. The panic happens in InitPlugins(), before the recover() in main(), and the deferred exit(0) ends micro silently with status 0 on every start. A file whose first entry has no Name did not crash, but it replaced the plugin name with an empty string, so the plugin was dropped as "not a plugin". Return the existing ErrMissingName in both cases. InitPlugins() already skips files that fail to parse, so the plugin keeps its directory name. --- internal/config/plugin_manager.go | 3 +++ internal/config/plugin_manager_test.go | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/internal/config/plugin_manager.go b/internal/config/plugin_manager.go index 1c5bfd8bd2..2b12167947 100644 --- a/internal/config/plugin_manager.go +++ b/internal/config/plugin_manager.go @@ -38,6 +38,9 @@ func NewPluginInfo(data []byte) (*PluginInfo, error) { if err := json5.Unmarshal(data, &info); err != nil { return nil, err } + if len(info) == 0 || info[0].Name == "" { + return nil, ErrMissingName + } return &info[0], nil } diff --git a/internal/config/plugin_manager_test.go b/internal/config/plugin_manager_test.go index f360469a04..ad26bee400 100644 --- a/internal/config/plugin_manager_test.go +++ b/internal/config/plugin_manager_test.go @@ -21,3 +21,11 @@ func TestNewPluginInfoAllowsJSON5Comments(t *testing.T) { t.Fatalf("expected plugin name %q, got %q", "example", info.Name) } } + +func TestNewPluginInfoRejectsMissingName(t *testing.T) { + for _, data := range []string{`[]`, `null`, `[{}]`, `[{"Description": "no name"}]`} { + if info, err := NewPluginInfo([]byte(data)); err != ErrMissingName { + t.Errorf("NewPluginInfo(%s) = %v, %v; want ErrMissingName", data, info, err) + } + } +}