add -download enterprise command option to plugin register CLI (#31187)

This commit is contained in:
Thy Ton 2025-07-03 16:58:55 -07:00 committed by GitHub
parent 33a0c7b3ff
commit e9b04fc0df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 98 additions and 4 deletions

View file

@ -33,6 +33,7 @@ type PluginRegisterCommand struct {
flagOCIImage string
flagRuntime string
flagEnv []string
flagDownload bool
}
func (c *PluginRegisterCommand) Synopsis() string {
@ -59,6 +60,12 @@ Usage: vault plugin register [options] TYPE NAME
-args=--with-glibc,--with-cgo \
auth my-custom-plugin
Register a plugin with -download (enterprise only):
$ vault plugin register \
-version=v0.17.0+ent \
-download=true \
secret vault-plugin-secrets-keymgmt
` + c.Flags().Help()
return strings.TrimSpace(helpText)
@ -127,6 +134,14 @@ func (c *PluginRegisterCommand) Flags() *FlagSets {
"flag can be specified multiple times to specify multiple environment variables.",
})
f.BoolVar(&BoolVar{
Name: "download",
Target: &c.flagDownload,
Completion: complete.PredictAnything,
Usage: "Enterprise only. If set, Vault will automatically download plugins from" +
"releases.hashicorp.com",
})
return set
}
@ -198,6 +213,7 @@ func (c *PluginRegisterCommand) Run(args []string) int {
OCIImage: c.flagOCIImage,
Runtime: c.flagRuntime,
Env: c.flagEnv,
Download: c.flagDownload,
})
if err != nil {
c.UI.Error(fmt.Sprintf("Error registering plugin %s: %s", pluginName, err))

View file

@ -142,7 +142,3 @@ func (e extendedSystemViewImpl) DeregisterWellKnownRedirect(ctx context.Context,
func (e extendedSystemViewImpl) GetPinnedPluginVersion(ctx context.Context, pluginType consts.PluginType, pluginName string) (*pluginutil.PinnedVersion, error) {
return e.core.pluginCatalog.GetPinnedVersion(ctx, pluginType, pluginName)
}
func (e extendedSystemViewImpl) DownloadExtractVerifyPlugin(_ context.Context, _ *pluginutil.PluginRunner) error {
return fmt.Errorf("cannot call DownloadExtractVerifyPlugin from a plugin backend")
}

View file

@ -538,6 +538,10 @@ func (b *SystemBackend) handlePluginCatalogUpdate(ctx context.Context, _ *logica
return logical.ErrorResponse("version %q is not allowed because 'builtin' is a reserved metadata identifier", pluginVersion), nil
}
if download := d.Get("download").(bool); download {
return logical.ErrorResponse("download is an enterprise only feature"), nil
}
sha256 := d.Get("sha256").(string)
if sha256 == "" {
sha256 = d.Get("sha_256").(string)
@ -6923,6 +6927,11 @@ Must already be present on the machine.`,
`The Vault plugin runtime to use when running the plugin.`,
"",
},
"plugin-catalog_download": {
`Automatically downloads official HashiCorp plugins
from releases.hashicorp.com (beta)`,
"",
},
"plugin-catalog-pins": {
"Configures pinned plugin versions from the plugin catalog",
`

View file

@ -0,0 +1,69 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
//go:build !enterprise
package vault
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/logical"
)
// TestSystemBackend_PluginCatalog_Update_Download_Should_Fail tests the update failure
// cases when download is true
func TestSystemBackend_PluginCatalog_Update_Download_Should_Fail(t *testing.T) {
const expectedErrStr = "download is an enterprise only feature"
sym, err := filepath.EvalSymlinks(os.TempDir())
if err != nil {
t.Fatalf("error: %v", err)
}
c, _, _ := TestCoreUnsealedWithConfig(t, &CoreConfig{
PluginDirectory: sym,
})
b := c.systemBackend
tests := []struct {
pluginType consts.PluginType
pluginVersion string
pluginName string
}{
{
pluginName: "vault-plugin-database-redis",
pluginVersion: "v0.6.0",
pluginType: consts.PluginTypeDatabase,
},
{
pluginName: "vault-plugin-secrets-kv",
pluginVersion: "v0.24.0",
pluginType: consts.PluginTypeSecrets,
},
{
pluginName: "vault-plugin-auth-jwt",
pluginVersion: "v0.24.1",
pluginType: consts.PluginTypeCredential,
},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%s %s", tt.pluginName, tt.pluginVersion), func(t *testing.T) {
req := logical.TestRequest(t, logical.UpdateOperation,
"plugins/catalog/"+tt.pluginType.String()+"/"+tt.pluginName)
req.Data["version"] = tt.pluginVersion
req.Data["download"] = true
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
if err != nil || resp.Error() == nil {
t.Fatalf("expected error when download is true, got resp: %v, err: %v", resp, err)
} else if !strings.Contains(resp.Error().Error(), expectedErrStr) {
t.Fatalf("expected error %q, got resp: %v", expectedErrStr, resp)
}
})
}
}

View file

@ -1891,6 +1891,10 @@ func (b *SystemBackend) pluginsCatalogCRUDPath() *framework.Path {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["plugin-catalog_version"][0]),
},
"download": {
Type: framework.TypeBool,
Description: strings.TrimSpace(sysHelp["plugin-catalog_download"][0]),
},
},
Operations: map[logical.Operation]framework.OperationHandler{