check / check (push) Failing after 2s
REPO_POLICIES.md requires the module root sneak.berlin/go/<name>. go.mod, every import (rewritten with gofmt -r), the -X flags in script/build and the examples in the pkg READMEs now use the new path. go mod tidy lists go-humanize and fatih/color as direct requirements, since internal/cli imports them. This breaks anyone who fetched or imported git.eeqj.de/sneak/secret: they must switch to sneak.berlin/go/secret, which resolves to this repository. Model: opus-5-5
139 lines
4.1 KiB
Go
139 lines
4.1 KiB
Go
package vault_test
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/awnumar/memguard"
|
|
"github.com/spf13/afero"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/secret/internal/secret"
|
|
"sneak.berlin/go/secret/internal/vault"
|
|
)
|
|
|
|
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)
|
|
}, secret.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 {
|
|
const versionless = "versionless"
|
|
|
|
err := vlt.GetFilesystem().MkdirAll(
|
|
filepath.Join(vaultDir, "secrets.d", versionless), secret.DirPerms)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return vlt.CopySecretAllVersions(vlt, versionless, "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)
|
|
}
|