diff --git a/changelog/23171.txt b/changelog/23171.txt new file mode 100644 index 0000000000..75bd32d4cd --- /dev/null +++ b/changelog/23171.txt @@ -0,0 +1,6 @@ +```release-note:bug +plugins: Runtime catalog returns 404 instead of 500 when reading a runtime that does not exist +``` +```release-note:bug +plugins: `vault plugin runtime list` can successfully list plugin runtimes with GET +``` diff --git a/vault/logical_system.go b/vault/logical_system.go index 49353b838c..fea383a6af 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -869,7 +869,7 @@ func (b *SystemBackend) handlePluginRuntimeCatalogRead(ctx context.Context, _ *l } conf, err := b.Core.pluginRuntimeCatalog.Get(ctx, runtimeName, runtimeType) - if err != nil { + if err != nil && !errors.Is(err, ErrPluginRuntimeNotFound) { return nil, err } if conf == nil { diff --git a/vault/logical_system_paths.go b/vault/logical_system_paths.go index 94edd873a6..8aedee519e 100644 --- a/vault/logical_system_paths.go +++ b/vault/logical_system_paths.go @@ -2224,6 +2224,21 @@ func (b *SystemBackend) pluginsRuntimesCatalogCRUDPath() *framework.Path { } func (b *SystemBackend) pluginsRuntimesCatalogListPaths() []*framework.Path { + handler := &framework.PathOperation{ + Callback: b.handlePluginRuntimeCatalogList, + Responses: map[int][]framework.Response{ + http.StatusOK: {{ + Description: "OK", + Fields: map[string]*framework.FieldSchema{ + "runtimes": { + Type: framework.TypeSlice, + Description: "List of all plugin runtimes in the catalog", + Required: true, + }, + }, + }}, + }, + } return []*framework.Path{ { Pattern: "plugins/runtimes/catalog/?$", @@ -2235,21 +2250,8 @@ func (b *SystemBackend) pluginsRuntimesCatalogListPaths() []*framework.Path { }, Operations: map[logical.Operation]framework.OperationHandler{ - logical.ListOperation: &framework.PathOperation{ - Callback: b.handlePluginRuntimeCatalogList, - Responses: map[int][]framework.Response{ - http.StatusOK: {{ - Description: "OK", - Fields: map[string]*framework.FieldSchema{ - "runtimes": { - Type: framework.TypeSlice, - Description: "List of all plugin runtimes in the catalog", - Required: true, - }, - }, - }}, - }, - }, + logical.ReadOperation: handler, + logical.ListOperation: handler, }, HelpSynopsis: strings.TrimSpace(sysHelp["plugin-runtime-catalog-list-all"][0]), diff --git a/vault/logical_system_test.go b/vault/logical_system_test.go index 5e45e468ad..45b8a8eb02 100644 --- a/vault/logical_system_test.go +++ b/vault/logical_system_test.go @@ -6122,17 +6122,19 @@ func TestSystemBackend_pluginRuntimeCRUD(t *testing.T) { } // List the plugin runtimes (untyped or all) - req = logical.TestRequest(t, logical.ListOperation, "plugins/runtimes/catalog") - resp, err = b.HandleRequest(namespace.RootContext(nil), req) - if err != nil { - t.Fatalf("err: %v", err) - } + for _, op := range []logical.Operation{logical.ListOperation, logical.ReadOperation} { + req = logical.TestRequest(t, op, "plugins/runtimes/catalog") + resp, err = b.HandleRequest(namespace.RootContext(nil), req) + if err != nil { + t.Fatalf("err: %v", err) + } - listExp := map[string]interface{}{ - "runtimes": []map[string]any{readExp}, - } - if !reflect.DeepEqual(resp.Data, listExp) { - t.Fatalf("got: %#v expect: %#v", resp.Data, listExp) + listExp := map[string]interface{}{ + "runtimes": []map[string]any{readExp}, + } + if !reflect.DeepEqual(resp.Data, listExp) { + t.Fatalf("got: %#v expect: %#v", resp.Data, listExp) + } } // Delete the plugin runtime @@ -6156,8 +6158,8 @@ func TestSystemBackend_pluginRuntimeCRUD(t *testing.T) { // Read the plugin runtime (deleted) req = logical.TestRequest(t, logical.ReadOperation, "plugins/runtimes/catalog/container/foo") resp, err = b.HandleRequest(namespace.RootContext(nil), req) - if err == nil { - t.Fatal("expected a read error after the runtime was deleted") + if err != nil { + t.Fatal("expected a 404") } if resp != nil { t.Fatalf("bad: %#v", resp) @@ -6170,7 +6172,7 @@ func TestSystemBackend_pluginRuntimeCRUD(t *testing.T) { t.Fatalf("err: %v", err) } - listExp = map[string]interface{}{} + listExp := map[string]interface{}{} if !reflect.DeepEqual(resp.Data, listExp) { t.Fatalf("got: %#v expect: %#v", resp.Data, listExp) } diff --git a/vault/plugin_runtime_catalog.go b/vault/plugin_runtime_catalog.go index 87cae43a1b..9ce5a6e844 100644 --- a/vault/plugin_runtime_catalog.go +++ b/vault/plugin_runtime_catalog.go @@ -56,10 +56,10 @@ func (c *PluginRuntimeCatalog) Get(ctx context.Context, name string, prt consts. defer c.lock.RUnlock() entry, err := c.catalogView.Get(ctx, storageKey) if err != nil { - return nil, fmt.Errorf("failed to retrieve plugin runtime %q %q: %w", prt.String(), name, err) + return nil, fmt.Errorf("failed to retrieve %s plugin runtime %q: %w", prt.String(), name, err) } if entry == nil { - return nil, fmt.Errorf("failed to retrieve plugin %q %q: %w", prt.String(), name, err) + return nil, fmt.Errorf("failed to retrieve %s plugin runtime %q: %w", prt.String(), name, ErrPluginRuntimeNotFound) } runner := new(pluginruntimeutil.PluginRuntimeConfig) if err := jsonutil.DecodeJSON(entry.Value, runner); err != nil {