// 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 }