vault/command/server_dev_plugin_test.go
Vault Automation 6c198ac93b
add dev flag to override pgp key for plugin signature verification (#13559) (#14240)
* add dev flag to override pgp key for plugin signature verification

-dev-plugin-pgp-key is the path to a PGP public key file to use for
plugin signature verification in dev mode. This prevents developers from
having to manually hard code their own pgp key into vault source code
and rebuild vault to develop and test enterprise plugins.

* fix sync once error handling

* add tests

* remove test

* tests: set random listener addr

* improve error message

* dedupe getVerifyFunc annd verifyPGPSignatureDetached

* accept raw key as well as path

* keep hc key and add custom key to keyring

Co-authored-by: John-Michael Faircloth <fairclothjm@users.noreply.github.com>
2026-04-23 21:16:51 +00:00

221 lines
7.5 KiB
Go

// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: BUSL-1.1
//go:build !race && !hsm
package command
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
)
// testPGPPublicKey is a sample PGP public key for testing purposes
const testPGPPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGB9+xkBEACabYZOWKmgZsHTdRDiyPJxhbuUiKX65GUWkyRMJKi/1dviVxOX
PG6hBPtF48IFnVgxKpIb7G6NjBousAV+CuLlv5yqFKpOZEGC6sBV+Gx8Vu1CICpl
Zm+HpQPcIzwBpN+Ar4l/exCG/f/MZq/oxGgH+TyRF3XcYDjG8dbJCpHO5nQ5Cy9h
QIp3/Bh09kET6lk+4QlofNgHKVT2epV8iK1cXlbQe2tZtfCUtxk+pxvU0UHXp+AB
0xc3/gIhjZp/dePmCOyQyGPJbp5bpO4UeAJ6frqhexmNlaw9Z897ltZmRLGq1p4a
RnWL8FPkBz9SCSKXS8uNyV5oMNVn4G1obCkc106iWuKBTibffYQzq5TG8FYVJKrh
RwWB6piacEB8hl20IIWSxIM3J9tT7CPSnk5RYYCTRHgA5OOrqZhC7JefudrP8n+M
pxkDgNORDu7GCfAuisrf7dXYjLsxG4tu22DBJJC0c/IpRpXDnOuJN1Q5e/3VUKKW
mypNumuQpP5lc1ZFG64TRzb1HR6oIdHfbrVQfdiQXpvdcFx+Fl57WuUraXRV6qfb
4ZmKHX1JEwM/7tu21QE4F1dz0jroLSricZxfaCTHHWNfvGJoZ30/MZUrpSC0IfB3
iQutxbZrwIlTBt+fGLtm3vDtwMFNWM+Rb1lrOxEQd2eijdxhvBOHtlIcswARAQAB
tERIYXNoaUNvcnAgU2VjdXJpdHkgKGhhc2hpY29ycC5jb20vc2VjdXJpdHkpIDxz
ZWN1cml0eUBoYXNoaWNvcnAuY29tPokCVAQTAQoAPhYhBMh0AR8KtAURDQIQVTQ2
XZRy10aPBQJgffsZAhsDBQkJZgGABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJ
EDQ2XZRy10aPtpcP/0PhJKiHtC1zREpRTrjGizoyk4Sl2SXpBZYhkdrG++abo6zs
buaAG7kgWWChVXBo5E20L7dbstFK7OjVs7vAg/OLgO9dPD8n2M19rpqSbbvKYWvp
0NSgvFTT7lbyDhtPj0/bzpkZEhmvQaDWGBsbDdb2dBHGitCXhGMpdP0BuuPWEix+
QnUMaPwU51q9GM2guL45Tgks9EKNnpDR6ZdCeWcqo1IDmklloidxT8aKL21UOb8t
cD+Bg8iPaAr73bW7Jh8TdcV6s6DBFub+xPJEB/0bVPmq3ZHs5B4NItroZ3r+h3ke
VDoSOSIZLl6JtVooOJ2la9ZuMqxchO3mrXLlXxVCo6cGcSuOmOdQSz4OhQE5zBxx
LuzA5ASIjASSeNZaRnffLIHmht17BPslgNPtm6ufyOk02P5XXwa69UCjA3RYrA2P
QNNC+OWZ8qQLnzGldqE4MnRNAxRxV6cFNzv14ooKf7+k686LdZrP/3fQu2p3k5rY
0xQUXKh1uwMUMtGR867ZBYaxYvwqDrg9XB7xi3N6aNyNQ+r7zI2lt65lzwG1v9hg
FG2AHrDlBkQi/t3wiTS3JOo/GCT8BjN0nJh0lGaRFtQv2cXOQGVRW8+V/9IpqEJ1
qQreftdBFWxvH7VJq2mSOXUJyRsoUrjkUuIivaA9Ocdipk2CkP8bpuGz7ZF4
=s1CX
-----END PGP PUBLIC KEY BLOCK-----`
// invalidPGPKey is not a valid PGP key format
const invalidPGPKey = `This is not a valid PGP key`
// testConfig is used to disable prometheus to avoid issues with the
// global prometheus registry in tests
const testConfig = `
storage "inmem" {}
listener "tcp" {
address = "127.0.0.1:0"
tls_disable = true
}
disable_mlock = true
telemetry {
prometheus_retention_time = "0s"
disable_hostname = true
}
`
// TestServer_DevPluginPGPKey_ValidKey tests that the server accepts a valid PGP key file
func TestServer_DevPluginPGPKey_ValidKey(t *testing.T) {
// Create a valid PGP key file
keyPath := filepath.Join(t.TempDir(), "test-pgp-key.asc")
err := os.WriteFile(keyPath, []byte(testPGPPublicKey), 0o644)
require.NoError(t, err)
ui, cmd := testServerCommand(t)
args := []string{
"-dev",
"-dev-plugin-pgp-key=" + keyPath,
"-dev-listen-address=127.0.0.1:0",
"-test-server-config",
}
retCode := cmd.Run(args)
output := ui.ErrorWriter.String() + ui.OutputWriter.String()
// The server should start successfully with a valid key
require.Equal(t, 0, retCode, "expected server to start successfully, output: %s", output)
}
// TestServer_DevPluginPGPKey_InvalidPath tests that the server handles invalid file paths
func TestServer_DevPluginPGPKey_InvalidPath(t *testing.T) {
ui, cmd := testServerCommand(t)
// Use an invalid path with null bytes (not allowed in file paths)
invalidPath := "/tmp/test\x00key.asc"
configPath := filepath.Join(t.TempDir(), "config.hcl")
err := os.WriteFile(configPath, []byte(testConfig), 0o644)
require.NoError(t, err)
args := []string{
"-dev",
"-config=" + configPath,
"-dev-plugin-pgp-key=" + invalidPath,
"-dev-listen-address=127.0.0.1:0",
"-test-server-config",
}
retCode := cmd.Run(args)
output := ui.ErrorWriter.String() + ui.OutputWriter.String()
// The server should fail to start with an invalid path
require.NotEqual(t, 0, retCode, "expected server to fail with invalid path")
require.Contains(t, output, "dev plugin PGP key", "expected error message about PGP key path, output: %s", output)
}
// TestServer_DevPluginPGPKey_NonExistentFile tests that the server handles non-existent key files
func TestServer_DevPluginPGPKey_NonExistentFile(t *testing.T) {
tmpDir := t.TempDir()
// Use a path that doesn't exist
keyPath := filepath.Join(tmpDir, "non-existent-key.asc")
ui, cmd := testServerCommand(t)
configPath := filepath.Join(tmpDir, "config.hcl")
err := os.WriteFile(configPath, []byte(testConfig), 0o644)
require.NoError(t, err)
args := []string{
"-dev",
"-config=" + configPath,
"-dev-plugin-pgp-key=" + keyPath,
"-dev-listen-address=127.0.0.1:0",
"-test-server-config",
}
retCode := cmd.Run(args)
output := ui.ErrorWriter.String() + ui.OutputWriter.String()
// The server should fail to start with a non-existent key file
require.NotEqual(t, 0, retCode, "expected server to fail with non-existent key file")
require.Contains(t, output, "dev plugin PGP key", "expected error message about PGP key path, output: %s", output)
}
// TestServer_DevPluginPGPKey_EmptyFlag tests default behavior when flag is not set
func TestServer_DevPluginPGPKey_EmptyFlag(t *testing.T) {
ui, cmd := testServerCommand(t)
configPath := filepath.Join(t.TempDir(), "config.hcl")
err := os.WriteFile(configPath, []byte(testConfig), 0o644)
require.NoError(t, err)
args := []string{
"-dev",
"-config=" + configPath,
"-dev-listen-address=127.0.0.1:0",
"-test-server-config",
}
retCode := cmd.Run(args)
output := ui.ErrorWriter.String() + ui.OutputWriter.String()
// The server should start successfully without the flag (uses default HashiCorp key)
require.Equal(t, 0, retCode, "expected server to start successfully without flag, output: %s", output)
}
// TestServer_DevPluginPGPKey_InvalidKeyContent tests handling of invalid PGP key content
func TestServer_DevPluginPGPKey_InvalidKeyContent(t *testing.T) {
tmpDir := t.TempDir()
// Create a file with invalid PGP key content
keyPath := filepath.Join(tmpDir, "invalid-key.asc")
err := os.WriteFile(keyPath, []byte(invalidPGPKey), 0o644)
require.NoError(t, err)
ui, cmd := testServerCommand(t)
configPath := filepath.Join(tmpDir, "config.hcl")
err = os.WriteFile(configPath, []byte(testConfig), 0o644)
require.NoError(t, err)
args := []string{
"-dev",
"-config=" + configPath,
"-dev-plugin-pgp-key=" + keyPath,
"-dev-listen-address=127.0.0.1:0",
"-test-server-config",
}
retCode := cmd.Run(args)
output := ui.ErrorWriter.String() + ui.OutputWriter.String()
// The server should start (validation happens when actually using the key)
// but we verify the path was set correctly
require.Equal(t, 0, retCode, "expected server to start (key validation happens at use time), output: %s", output)
}
// TestServer_DevPluginPGPKey_EmptyFile tests handling of an empty key file
func TestServer_DevPluginPGPKey_EmptyFile(t *testing.T) {
tmpDir := t.TempDir()
// Create an empty file
keyPath := filepath.Join(tmpDir, "empty-key.asc")
err := os.WriteFile(keyPath, []byte(""), 0o644)
require.NoError(t, err)
ui, cmd := testServerCommand(t)
configPath := filepath.Join(tmpDir, "config.hcl")
err = os.WriteFile(configPath, []byte(testConfig), 0o644)
require.NoError(t, err)
args := []string{
"-dev",
"-config=" + configPath,
"-dev-plugin-pgp-key=" + keyPath,
"-dev-listen-address=127.0.0.1:0",
"-test-server-config",
}
retCode := cmd.Run(args)
output := ui.ErrorWriter.String() + ui.OutputWriter.String()
// The server should start (validation happens when actually using the key)
require.Equal(t, 0, retCode, "expected server to start (key validation happens at use time), output: %s", output)
}