check / check (push) Failing after 3s
Tests that asserted a failure by a fragment of its message now use errors.Is: a refactor returning the wrong error, or wrapping with %v instead of %w, now fails them. New tests return each exported error of internal/vault and pkg/bip85 that no test returned, and check wrapped causes (os.ErrNotExist, ErrMnemonicMismatch through GetSecret, ErrInvalidPathComponent through DeriveBIP85Entropy). The 999-versions test moves into package secret to name its unexported error. Checks of errors no test can name keep their text; they are listed on the issue. Model: opus-5-5
137 lines
4.0 KiB
Go
137 lines
4.0 KiB
Go
package vault_test
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"git.eeqj.de/sneak/secret/internal/secret"
|
|
"git.eeqj.de/sneak/secret/internal/vault"
|
|
"github.com/awnumar/memguard"
|
|
"github.com/spf13/afero"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
const (
|
|
// otherMnemonic is a valid BIP39 mnemonic other than testMnemonic.
|
|
otherMnemonic = "legal winner thank year wave sausage worth useful " +
|
|
"legal winner thank yellow"
|
|
|
|
// missingName names no vault, secret or unlocker.
|
|
missingName = "missing"
|
|
)
|
|
|
|
// newErrorTestVault creates the vault testVaultName, with the secret
|
|
// testSecretName in it, on a new in-memory filesystem.
|
|
func newErrorTestVault(t *testing.T) *vault.Vault {
|
|
t.Helper()
|
|
|
|
vlt, err := vault.CreateVault(afero.NewMemMapFs(), testStateDir,
|
|
testVaultName, testMnemonicBuffer(t), nil)
|
|
require.NoError(t, err)
|
|
|
|
value := memguard.NewBufferFromBytes([]byte("value"))
|
|
t.Cleanup(value.Destroy)
|
|
|
|
require.NoError(t, vlt.AddSecret(testSecretName, value, false))
|
|
|
|
return vlt
|
|
}
|
|
|
|
// TestVaultErrors checks that each failure returns its exported error,
|
|
// wrapped or not, so that errors.Is tells it apart from the others.
|
|
func TestVaultErrors(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
vaultDir := filepath.Join(testStateDir, "vaults.d", testVaultName)
|
|
|
|
tests := []struct {
|
|
name string
|
|
run func(vlt *vault.Vault) error
|
|
want error
|
|
}{
|
|
{"create an existing vault", func(vlt *vault.Vault) error {
|
|
_, err := vault.CreateVault(vlt.GetFilesystem(), testStateDir,
|
|
testVaultName, nil, nil)
|
|
|
|
return err
|
|
}, vault.ErrVaultExists},
|
|
{"select a missing vault", func(vlt *vault.Vault) error {
|
|
return vault.SelectVault(vlt.GetFilesystem(), testStateDir, missingName)
|
|
}, vault.ErrVaultNotFound},
|
|
{"add a nil value", func(vlt *vault.Vault) error {
|
|
return vlt.AddSecret(missingName, nil, false)
|
|
}, vault.ErrNilValueBuffer},
|
|
{"get a missing secret", func(vlt *vault.Vault) error {
|
|
_, err := vlt.GetSecret(missingName)
|
|
|
|
return err
|
|
}, vault.ErrSecretNotFound},
|
|
{"copy onto an existing secret", func(vlt *vault.Vault) error {
|
|
return vlt.CopySecretAllVersions(vlt, testSecretName, testSecretName, false)
|
|
}, vault.ErrSecretExists},
|
|
{"copy a secret without versions", func(vlt *vault.Vault) error {
|
|
err := vlt.GetFilesystem().MkdirAll(
|
|
filepath.Join(vaultDir, "secrets.d", missingName), secret.DirPerms)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return vlt.CopySecretAllVersions(vlt, missingName, "copy", false)
|
|
}, vault.ErrNoVersions},
|
|
{"remove a missing unlocker", func(vlt *vault.Vault) error {
|
|
return vlt.RemoveUnlocker(missingName)
|
|
}, vault.ErrUnlockerNotFound},
|
|
{"select a missing unlocker", func(vlt *vault.Vault) error {
|
|
return vlt.SelectUnlocker(missingName)
|
|
}, vault.ErrUnlockerNotFound},
|
|
{"unlocker of an unknown type", func(vlt *vault.Vault) error {
|
|
fs := vlt.GetFilesystem()
|
|
|
|
err := afero.WriteFile(fs,
|
|
filepath.Join(vaultDir, "unlockers.d", "odd", "unlocker-metadata.json"),
|
|
[]byte(`{"type":"odd"}`), secret.FilePerms)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = afero.WriteFile(fs, filepath.Join(vaultDir, "current-unlocker"),
|
|
[]byte("odd"), secret.FilePerms)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = vlt.GetCurrentUnlocker()
|
|
|
|
return err
|
|
}, vault.ErrUnsupportedUnlockerType},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
require.ErrorIs(t, tt.run(newErrorTestVault(t)), tt.want)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestGetSecretWithWrongMnemonic checks that getting a secret that exists,
|
|
// from a vault the given mnemonic does not open, fails with
|
|
// ErrMnemonicMismatch through GetSecret's wrapping, and not with
|
|
// ErrSecretNotFound.
|
|
func TestGetSecretWithWrongMnemonic(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
created := newErrorTestVault(t)
|
|
|
|
mnemonic := memguard.NewBufferFromBytes([]byte(otherMnemonic))
|
|
t.Cleanup(mnemonic.Destroy)
|
|
|
|
vlt := vault.NewVault(created.GetFilesystem(), testStateDir, testVaultName)
|
|
vlt.SetMnemonic(mnemonic)
|
|
|
|
_, err := vlt.GetSecret(testSecretName)
|
|
require.ErrorIs(t, err, vault.ErrMnemonicMismatch)
|
|
require.NotErrorIs(t, err, vault.ErrSecretNotFound)
|
|
}
|