Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e6ff1d8cc |
@@ -25,22 +25,36 @@ https://git.eeqj.de/sneak/secret/milestone/12
|
|||||||
`vault import`, `vault remove` and `version list`, `promote` and `rm` wrap
|
`vault import`, `vault remove` and `version list`, `promote` and `rm` wrap
|
||||||
the `vault` errors. `errUnsupportedUnlockerType` is removed: `secret
|
the `vault` errors. `errUnsupportedUnlockerType` is removed: `secret
|
||||||
unlocker add` gives `errInvalidUnlockerType` for an unknown type, whichever
|
unlocker add` gives `errInvalidUnlockerType` for an unknown type, whichever
|
||||||
check rejects it. Messages are unchanged, except that `secret decrypt`
|
check rejects it. Off macOS, adding a keychain or Secure Enclave unlocker
|
||||||
of a missing secret says "not found", as `secret get` does, not "does not
|
returns the `secret` package's error for it, not an `internal/cli` copy; on
|
||||||
exist". Every error of `secret.ReadPassphrase` wraps
|
macOS, the check that the system is macOS is gone, as it could never fail.
|
||||||
`secret.ErrPassphraseNotRead`, which supplies the words "failed to read
|
`secret vault import` gives `errInvalidMnemonicPhrase` for an invalid
|
||||||
passphrase" that its callers used to add themselves; so two passphrases
|
mnemonic, as `init` and `vault create` do. `secret generate secret` gives
|
||||||
that differ now give only "passphrases do not match", the words now follow
|
`errLengthTooSmall` for a length below 1 wherever it is checked, and
|
||||||
"failed to read mnemonic:" and "failed to read passphrase confirmation:",
|
`errUnsupportedSecretType` for `--type mnemonic` too. `secret import` of a
|
||||||
and a terminal read error no longer repeats them. A GPG key the keyring
|
file over 100MB wraps `errSecretTooLarge`, as `secret add` returns it.
|
||||||
does not hold gives `secret.ErrGPGKeyNotFound`, found by gpg's status line
|
`vault.ErrNilValueBuffer` is replaced by `secret.ErrNilValueBuffer`, which
|
||||||
for "No public key"; before, the message repeated "failed to resolve GPG
|
`secret` already returned under another name. Messages are unchanged,
|
||||||
key fingerprint" and ended in gpg's exit status. The keychain unlocker
|
except that `secret decrypt` of a missing secret says "not found", as
|
||||||
returns `errNilDataBuffer` for nil data; this and its test build only on
|
`secret get` does, not "does not exist"; `vault import` of an invalid
|
||||||
macOS with cgo and were only read. `bip85.ErrPasswordTooShort` and
|
mnemonic says "invalid BIP39 mnemonic phrase"; `--type mnemonic` says
|
||||||
`ErrEncodedTooShort` are removed with their checks: 64 bytes of entropy
|
"unsupported type: mnemonic (use 'secret generate mnemonic' instead)"; and
|
||||||
always give 86 Base64 or 80 Base85 characters, the most a password length
|
a file too large to import says
|
||||||
may ask for. Tests that matched these errors' text use `errors.Is`.
|
`failed to read secret from file <path>: secret too large: exceeds 100MB limit`.
|
||||||
|
Every error of `secret.ReadPassphrase` wraps `secret.ErrPassphraseNotRead`,
|
||||||
|
which supplies the words "failed to read passphrase" that its callers used
|
||||||
|
to add themselves; so two passphrases that differ now give only
|
||||||
|
"passphrases do not match", the words now follow "failed to read mnemonic:"
|
||||||
|
and "failed to read passphrase confirmation:", and a terminal read error no
|
||||||
|
longer repeats them. A GPG key the keyring does not hold gives
|
||||||
|
`secret.ErrGPGKeyNotFound`, found by gpg's status line for "No public key";
|
||||||
|
before, the message repeated "failed to resolve GPG key fingerprint" and
|
||||||
|
ended in gpg's exit status. The keychain unlocker returns `errNilDataBuffer`
|
||||||
|
for nil data; this and its test build only on macOS with cgo and were only
|
||||||
|
read. `bip85.ErrPasswordTooShort` and `ErrEncodedTooShort` are removed with
|
||||||
|
their checks: 64 bytes of entropy always give 86 Base64 or 80 Base85
|
||||||
|
characters, the most a password length may ask for. Tests that matched
|
||||||
|
these errors' text use `errors.Is`.
|
||||||
- 2026-10-04: Tests check which error a failure returns with `errors.Is`,
|
- 2026-10-04: Tests check which error a failure returns with `errors.Is`,
|
||||||
not by matching words of its message
|
not by matching words of its message
|
||||||
(https://git.eeqj.de/sneak/secret/issues/49). Every exported error that
|
(https://git.eeqj.de/sneak/secret/issues/49). Every exported error that
|
||||||
|
|||||||
@@ -20,11 +20,7 @@ const (
|
|||||||
|
|
||||||
// Sentinel errors for secret generation
|
// Sentinel errors for secret generation
|
||||||
var (
|
var (
|
||||||
errLengthTooSmall = errors.New("length must be at least 1")
|
errLengthTooSmall = errors.New("length must be at least 1")
|
||||||
errLengthNotPositive = errors.New("length must be positive")
|
|
||||||
errMnemonicTypeNotSupported = errors.New(
|
|
||||||
"mnemonic type not supported for secret generation, " +
|
|
||||||
"use 'secret generate mnemonic' instead")
|
|
||||||
errUnsupportedSecretType = errors.New("unsupported type")
|
errUnsupportedSecretType = errors.New("unsupported type")
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -148,7 +144,8 @@ func (cli *Instance) GenerateSecret(
|
|||||||
case "alnum":
|
case "alnum":
|
||||||
secretValue, err = generateRandomAlnum(length)
|
secretValue, err = generateRandomAlnum(length)
|
||||||
case "mnemonic":
|
case "mnemonic":
|
||||||
return errMnemonicTypeNotSupported
|
return fmt.Errorf("%w: mnemonic (use 'secret generate mnemonic' instead)",
|
||||||
|
errUnsupportedSecretType)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: %s (supported: base58, alnum)",
|
return fmt.Errorf("%w: %s (supported: base58, alnum)",
|
||||||
errUnsupportedSecretType, secretType)
|
errUnsupportedSecretType, secretType)
|
||||||
@@ -204,8 +201,8 @@ func generateRandomAlnum(length int) (string, error) {
|
|||||||
// generateRandomString generates a random string of the specified length
|
// generateRandomString generates a random string of the specified length
|
||||||
// using the given character set
|
// using the given character set
|
||||||
func generateRandomString(length int, charset string) (string, error) {
|
func generateRandomString(length int, charset string) (string, error) {
|
||||||
if length <= 0 {
|
if length < 1 {
|
||||||
return "", errLengthNotPositive
|
return "", errLengthTooSmall
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]byte, length)
|
result := make([]byte, length)
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
//nolint:testpackage // white-box test of unexported internals
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.eeqj.de/sneak/secret/internal/vault"
|
||||||
|
"github.com/awnumar/memguard"
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestInvalidMnemonicError checks that every command that takes a mnemonic
|
||||||
|
// returns errInvalidMnemonicPhrase for one that is not valid BIP39. The vault
|
||||||
|
// "other" has no long-term key, as vault import needs.
|
||||||
|
func TestInvalidMnemonicError(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
command string
|
||||||
|
run func(c *Instance) error
|
||||||
|
}{
|
||||||
|
{"secret init", func(c *Instance) error { return c.Init(c.cmd) }},
|
||||||
|
{"secret vault create work", func(c *Instance) error {
|
||||||
|
return c.CreateVault(c.cmd, "work")
|
||||||
|
}},
|
||||||
|
{"secret vault import other", func(c *Instance) error {
|
||||||
|
return c.VaultImport(c.cmd, "other")
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.command, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
fs := afero.NewMemMapFs()
|
||||||
|
_, err := vault.CreateVault(fs, listTestStateDir, "other", nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
instance, _ := newTestInstance(fs)
|
||||||
|
instance.Mnemonic = memguard.NewBufferFromBytes([]byte("not a mnemonic"))
|
||||||
|
t.Cleanup(instance.Mnemonic.Destroy)
|
||||||
|
|
||||||
|
require.ErrorIs(t, tt.run(instance), errInvalidMnemonicPhrase)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGenerateSecretErrors checks that `secret generate secret` gives one
|
||||||
|
// error for a length below 1 and one for a type it cannot generate.
|
||||||
|
func TestGenerateSecretErrors(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
instance, cmd := newTestInstance(afero.NewMemMapFs())
|
||||||
|
|
||||||
|
err := instance.GenerateSecret(cmd, "x", 0, "base58", false)
|
||||||
|
require.ErrorIs(t, err, errLengthTooSmall)
|
||||||
|
|
||||||
|
_, err = generateRandomString(0, "ab")
|
||||||
|
require.ErrorIs(t, err, errLengthTooSmall)
|
||||||
|
|
||||||
|
err = instance.GenerateSecret(cmd, "x", defaultSecretLength, "mnemonic", false)
|
||||||
|
require.ErrorIs(t, err, errUnsupportedSecretType)
|
||||||
|
|
||||||
|
err = instance.GenerateSecret(cmd, "x", defaultSecretLength, "hex", false)
|
||||||
|
require.ErrorIs(t, err, errUnsupportedSecretType)
|
||||||
|
}
|
||||||
@@ -32,9 +32,7 @@ const (
|
|||||||
|
|
||||||
// Sentinel errors for secret operations
|
// Sentinel errors for secret operations
|
||||||
var (
|
var (
|
||||||
errSecretTooLarge = errors.New("secret too large: exceeds 100MB limit")
|
errSecretTooLarge = errors.New("secret too large: exceeds 100MB limit")
|
||||||
errSecretFileTooLarge = errors.New(
|
|
||||||
"secret file too large: exceeds 100MB limit")
|
|
||||||
errCrossVaultSourceUnqualified = errors.New(
|
errCrossVaultSourceUnqualified = errors.New(
|
||||||
"source must specify vault (e.g., vault:secret) for cross-vault move")
|
"source must specify vault (e.g., vault:secret) for cross-vault move")
|
||||||
errMoveOntoItself = errors.New("cannot be moved onto itself")
|
errMoveOntoItself = errors.New("cannot be moved onto itself")
|
||||||
@@ -669,10 +667,6 @@ func (cli *Instance) ImportSecret(
|
|||||||
|
|
||||||
buffers, totalSize, err := readSecretFromReader(file)
|
buffers, totalSize, err := readSecretFromReader(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, errSecretTooLarge) {
|
|
||||||
return errSecretFileTooLarge
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("failed to read secret from file %s: %w", sourceFile, err)
|
return fmt.Errorf("failed to read secret from file %s: %w", sourceFile, err)
|
||||||
}
|
}
|
||||||
defer destroyBuffers(buffers)
|
defer destroyBuffers(buffers)
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ func TestImportSecretVariousSizes(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "101MB file - should fail",
|
name: "101MB file - should fail",
|
||||||
size: 101 * 1024 * 1024,
|
size: 101 * 1024 * 1024,
|
||||||
wantErr: errSecretFileTooLarge,
|
wantErr: errSecretTooLarge,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,10 +39,6 @@ var (
|
|||||||
errInvalidUnlockerType = errors.New("invalid unlocker type")
|
errInvalidUnlockerType = errors.New("invalid unlocker type")
|
||||||
errKeyIDOnlyForPGP = errors.New(
|
errKeyIDOnlyForPGP = errors.New(
|
||||||
"--keyid flag is only valid for PGP unlockers")
|
"--keyid flag is only valid for PGP unlockers")
|
||||||
errKeychainMacOSOnly = errors.New(
|
|
||||||
"keychain unlockers are only supported on macOS")
|
|
||||||
errSecureEnclaveMacOSOnly = errors.New(
|
|
||||||
"secure enclave unlockers are only supported on macOS")
|
|
||||||
// errGPGKeyAlreadyUnlocker carries only the message tail; the caller
|
// errGPGKeyAlreadyUnlocker carries only the message tail; the caller
|
||||||
// composes "GPG key <id> is already added as an unlocker".
|
// composes "GPG key <id> is already added as an unlocker".
|
||||||
errGPGKeyAlreadyUnlocker = errors.New(
|
errGPGKeyAlreadyUnlocker = errors.New(
|
||||||
@@ -493,10 +489,6 @@ func (cli *Instance) addPassphraseUnlocker(cmd *cobra.Command) error {
|
|||||||
|
|
||||||
// addKeychainUnlocker creates a macOS Keychain unlocker in the current vault
|
// addKeychainUnlocker creates a macOS Keychain unlocker in the current vault
|
||||||
func (cli *Instance) addKeychainUnlocker(cmd *cobra.Command) error {
|
func (cli *Instance) addKeychainUnlocker(cmd *cobra.Command) error {
|
||||||
if runtime.GOOS != platformDarwin {
|
|
||||||
return errKeychainMacOSOnly
|
|
||||||
}
|
|
||||||
|
|
||||||
keychainUnlocker, err := secret.CreateKeychainUnlocker(
|
keychainUnlocker, err := secret.CreateKeychainUnlocker(
|
||||||
cli.fs, cli.stateDir, cli.Mnemonic, cli.UnlockPassphrase)
|
cli.fs, cli.stateDir, cli.Mnemonic, cli.UnlockPassphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -524,10 +516,6 @@ func (cli *Instance) addKeychainUnlocker(cmd *cobra.Command) error {
|
|||||||
// addSecureEnclaveUnlocker creates a Secure Enclave unlocker in the
|
// addSecureEnclaveUnlocker creates a Secure Enclave unlocker in the
|
||||||
// current vault
|
// current vault
|
||||||
func (cli *Instance) addSecureEnclaveUnlocker(cmd *cobra.Command) error {
|
func (cli *Instance) addSecureEnclaveUnlocker(cmd *cobra.Command) error {
|
||||||
if runtime.GOOS != platformDarwin {
|
|
||||||
return errSecureEnclaveMacOSOnly
|
|
||||||
}
|
|
||||||
|
|
||||||
seUnlocker, err := secret.CreateSecureEnclaveUnlocker(
|
seUnlocker, err := secret.CreateSecureEnclaveUnlocker(
|
||||||
cli.fs, cli.stateDir, cli.Mnemonic, cli.UnlockPassphrase)
|
cli.fs, cli.stateDir, cli.Mnemonic, cli.UnlockPassphrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import (
|
|||||||
var (
|
var (
|
||||||
errMnemonicEmpty = errors.New("mnemonic cannot be empty")
|
errMnemonicEmpty = errors.New("mnemonic cannot be empty")
|
||||||
errInvalidMnemonicPhrase = errors.New("invalid BIP39 mnemonic phrase")
|
errInvalidMnemonicPhrase = errors.New("invalid BIP39 mnemonic phrase")
|
||||||
errInvalidMnemonic = errors.New("invalid BIP39 mnemonic")
|
|
||||||
errVaultHasLongTermKey = errors.New(
|
errVaultHasLongTermKey = errors.New(
|
||||||
"already has a long-term key configured")
|
"already has a long-term key configured")
|
||||||
errMnemonicEnvNotSet = errors.New(
|
errMnemonicEnvNotSet = errors.New(
|
||||||
@@ -381,7 +380,7 @@ func (cli *Instance) vaultImportPreflight(
|
|||||||
secret.Debug("Validating BIP39 mnemonic", "word_count", len(mnemonicWords))
|
secret.Debug("Validating BIP39 mnemonic", "word_count", len(mnemonicWords))
|
||||||
|
|
||||||
if !bip39.IsMnemonicValid(mnemonic) {
|
if !bip39.IsMnemonicValid(mnemonic) {
|
||||||
return "", "", "", errInvalidMnemonic
|
return "", "", "", errInvalidMnemonicPhrase
|
||||||
}
|
}
|
||||||
|
|
||||||
return vaultDir, pubKeyPath, mnemonic, nil
|
return vaultDir, pubKeyPath, mnemonic, nil
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"filippo.io/age"
|
"filippo.io/age"
|
||||||
@@ -39,8 +38,6 @@ const (
|
|||||||
var keychainItemNameRegex = regexp.MustCompile(`^[A-Za-z0-9._-]+$`)
|
var keychainItemNameRegex = regexp.MustCompile(`^[A-Za-z0-9._-]+$`)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNotMacOS = errors.New(
|
|
||||||
"keychain unlockers are only supported on macOS")
|
|
||||||
errKeychainItemNameEmpty = errors.New("keychain item name cannot be empty")
|
errKeychainItemNameEmpty = errors.New("keychain item name cannot be empty")
|
||||||
errInvalidKeychainItemName = errors.New("invalid keychain item name format")
|
errInvalidKeychainItemName = errors.New("invalid keychain item name format")
|
||||||
errUnsupportedCurrentUnlocker = errors.New(
|
errUnsupportedCurrentUnlocker = errors.New(
|
||||||
@@ -394,12 +391,6 @@ func deriveLongTermPrivateKey(
|
|||||||
func CreateKeychainUnlocker(
|
func CreateKeychainUnlocker(
|
||||||
fs afero.Fs, stateDir string, mnemonic, passphrase *memguard.LockedBuffer,
|
fs afero.Fs, stateDir string, mnemonic, passphrase *memguard.LockedBuffer,
|
||||||
) (*KeychainUnlocker, error) {
|
) (*KeychainUnlocker, error) {
|
||||||
// Check if we're on macOS
|
|
||||||
err := checkMacOSAvailable()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current vault using the GetCurrentVault function from the same package
|
// Get current vault using the GetCurrentVault function from the same package
|
||||||
vault, err := GetCurrentVault(fs, stateDir)
|
vault, err := GetCurrentVault(fs, stateDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -555,15 +546,6 @@ func writeKeychainUnlocker(
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkMacOSAvailable verifies that we're running on macOS
|
|
||||||
func checkMacOSAvailable() error {
|
|
||||||
if runtime.GOOS != "darwin" {
|
|
||||||
return fmt.Errorf("%w, current OS: %s", errNotMacOS, runtime.GOOS)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateKeychainItemName validates that a keychain item name is safe for
|
// validateKeychainItemName validates that a keychain item name is safe for
|
||||||
// command execution
|
// command execution
|
||||||
func validateKeychainItemName(itemName string) error {
|
func validateKeychainItemName(itemName string) error {
|
||||||
|
|||||||
@@ -216,11 +216,6 @@ func CreateSecureEnclaveUnlocker(
|
|||||||
stateDir string,
|
stateDir string,
|
||||||
mnemonic, passphrase *memguard.LockedBuffer,
|
mnemonic, passphrase *memguard.LockedBuffer,
|
||||||
) (*SecureEnclaveUnlocker, error) {
|
) (*SecureEnclaveUnlocker, error) {
|
||||||
err := checkMacOSAvailable()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
vault, err := GetCurrentVault(fs, stateDir)
|
vault, err := GetCurrentVault(fs, stateDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get current vault: %w", err)
|
return nil, fmt.Errorf("failed to get current vault: %w", err)
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ const (
|
|||||||
maxVersionsPerDay = 999
|
maxVersionsPerDay = 999
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var errMaxVersionsPerDay = errors.New("exceeded maximum versions per day (999)")
|
||||||
errMaxVersionsPerDay = errors.New("exceeded maximum versions per day (999)")
|
|
||||||
errNilValueBuffer = errors.New("value buffer is nil")
|
// ErrNilValueBuffer is returned when a secret's value is given as nil.
|
||||||
)
|
var ErrNilValueBuffer = errors.New("value buffer is nil")
|
||||||
|
|
||||||
// VersionMetadata contains information about a secret version
|
// VersionMetadata contains information about a secret version
|
||||||
type VersionMetadata struct {
|
type VersionMetadata struct {
|
||||||
@@ -138,7 +138,7 @@ func GenerateVersionName(fs afero.Fs, secretDir string) (string, error) {
|
|||||||
// process dies part-way.
|
// process dies part-way.
|
||||||
func (sv *Version) Save(value *memguard.LockedBuffer) error {
|
func (sv *Version) Save(value *memguard.LockedBuffer) error {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return errNilValueBuffer
|
return ErrNilValueBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugWith("Saving secret version",
|
DebugWith("Saving secret version",
|
||||||
|
|||||||
@@ -36,9 +36,6 @@ var (
|
|||||||
// it unlocks. Composed as "vault <name> needs a mnemonic for an unlocker".
|
// it unlocks. Composed as "vault <name> needs a mnemonic for an unlocker".
|
||||||
ErrUnlockerWithoutMnemonic = errors.New("needs a mnemonic for an unlocker")
|
ErrUnlockerWithoutMnemonic = errors.New("needs a mnemonic for an unlocker")
|
||||||
|
|
||||||
// ErrNilValueBuffer indicates a nil value buffer was supplied.
|
|
||||||
ErrNilValueBuffer = errors.New("value buffer is nil")
|
|
||||||
|
|
||||||
// ErrInvalidSecretName indicates a secret name that breaks the naming
|
// ErrInvalidSecretName indicates a secret name that breaks the naming
|
||||||
// rule: only ASCII letters, digits, '.', '-', '_' and '/'; not empty;
|
// rule: only ASCII letters, digits, '.', '-', '_' and '/'; not empty;
|
||||||
// no leading '.' or '/', no trailing '/', no '//', no '..' path segment.
|
// no leading '.' or '/', no trailing '/', no '//', no '..' path segment.
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func TestVaultErrors(t *testing.T) {
|
|||||||
}, vault.ErrVaultNotFound},
|
}, vault.ErrVaultNotFound},
|
||||||
{"add a nil value", func(vlt *vault.Vault) error {
|
{"add a nil value", func(vlt *vault.Vault) error {
|
||||||
return vlt.AddSecret(missingName, nil, false)
|
return vlt.AddSecret(missingName, nil, false)
|
||||||
}, vault.ErrNilValueBuffer},
|
}, secret.ErrNilValueBuffer},
|
||||||
{"get a missing secret", func(vlt *vault.Vault) error {
|
{"get a missing secret", func(vlt *vault.Vault) error {
|
||||||
_, err := vlt.GetSecret(missingName)
|
_, err := vlt.GetSecret(missingName)
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ func ValidateSecretName(name string) error {
|
|||||||
// AddSecret adds a secret to this vault
|
// AddSecret adds a secret to this vault
|
||||||
func (v *Vault) AddSecret(name string, value *memguard.LockedBuffer, force bool) error {
|
func (v *Vault) AddSecret(name string, value *memguard.LockedBuffer, force bool) error {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return ErrNilValueBuffer
|
return secret.ErrNilValueBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
secret.DebugWith("Adding secret to vault",
|
secret.DebugWith("Adding secret to vault",
|
||||||
|
|||||||
Reference in New Issue
Block a user