blob: 9eb8077b8923033b75f137b6abca3f5a213437c7 [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package versions
import (
"fmt"
"runtime/debug"
"strings"
"sync"
semver "github.com/hashicorp/go-version"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/version"
)
const (
BuiltinMetadata = "builtin"
)
var (
buildInfoOnce sync.Once // once is used to ensure we only parse build info once.
buildInfo *debug.BuildInfo
DefaultBuiltinVersion = fmt.Sprintf("v%s+%s.vault", version.GetVersion().Version, BuiltinMetadata)
)
func GetBuiltinVersion(pluginType consts.PluginType, pluginName string) string {
buildInfoOnce.Do(func() {
buildInfo, _ = debug.ReadBuildInfo()
})
// Should never happen, means the binary was built without Go modules.
// Fall back to just the Vault version.
if buildInfo == nil {
return DefaultBuiltinVersion
}
// Vault builtin plugins are all either:
// a) An external repo within the hashicorp org - return external repo version with +builtin
// b) Within the Vault repo itself - return Vault version with +builtin.vault
//
// The repo names are predictable, but follow slightly different patterns
// for each plugin type.
t := pluginType.String()
switch pluginType {
case consts.PluginTypeDatabase:
// Database plugin built-ins are registered as e.g. "postgresql-database-plugin"
pluginName = strings.TrimSuffix(pluginName, "-database-plugin")
case consts.PluginTypeSecrets:
// Repos use "secrets", pluginType.String() is "secret".
t = "secrets"
}
pluginModulePath := fmt.Sprintf("github.com/hashicorp/vault-plugin-%s-%s", t, pluginName)
for _, dep := range buildInfo.Deps {
if dep.Path == pluginModulePath {
return dep.Version + "+" + BuiltinMetadata
}
}
return DefaultBuiltinVersion
}
// IsBuiltinVersion checks for the "builtin" metadata identifier in a plugin's
// semantic version. Vault rejects any plugin registration requests with this
// identifier, so we can be certain it's a builtin plugin if it's present.
func IsBuiltinVersion(v string) bool {
semanticVersion, err := semver.NewSemver(v)
if err != nil {
return false
}
metadataIdentifiers := strings.Split(semanticVersion.Metadata(), ".")
for _, identifier := range metadataIdentifiers {
if identifier == BuiltinMetadata {
return true
}
}
return false
}