Commands fail when currentvault names no vault (closes #156)
check / check (push) Waiting to run

An empty currentvault, or one naming a vault that does not exist, made
`secret list` report an empty vault with exit 0 and `secret add` fail on a
missing directory. ResolveVaultSymlink now refuses an empty or invalid
name, or one with no directory under vaults.d, with an error that wraps
ErrVaultNotFound, names the file and says to run
`secret vault select <name>`. Every command that uses the current vault
gets it; `secret vault list` still lists the vaults.

newSizeTestVault wrote a full path into currentvault, which resolved only
because the last path element was taken as the name; it now relies on
CreateVault selecting the vault.

Model: opus-5-5
This commit is contained in:
2026-10-15 01:16:29 +00:00
parent 220213abfe
commit 8c1040b6cd
4 changed files with 83 additions and 10 deletions
+59
View File
@@ -0,0 +1,59 @@
package cli_test
import (
"bytes"
"path/filepath"
"strconv"
"testing"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sneak.berlin/go/secret/internal/cli"
"sneak.berlin/go/secret/internal/secret"
"sneak.berlin/go/secret/internal/vault"
)
// TestListFailsWhenCurrentVaultDoesNotExist is a regression test for
// https://git.eeqj.de/sneak/secret/issues/156, where a currentvault file
// that was empty, or named a vault that does not exist, made `secret list`
// report an empty vault. Listing must fail with an error that names the
// file and says to run `secret vault select`, `secret vault list` must
// still list the vaults, and selecting a vault must make listing work
// again.
func TestListFailsWhenCurrentVaultDoesNotExist(t *testing.T) {
t.Parallel()
for _, name := range []string{"", "gone"} {
t.Run(strconv.Quote(name), func(t *testing.T) {
t.Parallel()
fs := newTwoVaultFs(t)
currentVaultPath := filepath.Join(testStateDir, "currentvault")
require.NoError(t, afero.WriteFile(fs, currentVaultPath,
[]byte(name), secret.FilePerms))
c := cli.NewCLIInstanceWithStateDir(fs, testStateDir)
var out bytes.Buffer
cmd := &cobra.Command{}
cmd.SetOut(&out)
err := c.ListSecrets(cmd, false, true, "")
require.ErrorIs(t, err, vault.ErrVaultNotFound)
require.ErrorContains(t, err, currentVaultPath)
require.ErrorContains(t, err, "secret vault select")
assert.Empty(t, out.String())
require.NoError(t, c.ListVaults(cmd, false))
assert.Equal(t, "Available vaults:\n default\n work\n", out.String())
require.NoError(t, c.SelectVault(cmd, "default"))
out.Reset()
require.NoError(t, c.ListSecrets(cmd, false, true, ""))
assert.Equal(t, "x\n", out.String())
})
}
}
+1 -8
View File
@@ -6,7 +6,6 @@ import (
"crypto/rand"
"fmt"
"io"
"path/filepath"
"strings"
"testing"
@@ -30,17 +29,11 @@ func newSizeTestVault(t *testing.T) (afero.Fs, *vault.Vault) {
fs := afero.NewMemMapFs()
// Create vault
// Create vault, which selects it as the current vault
_, err := vault.CreateVault(fs, testStateDir, testVaultName,
testMnemonicBuffer(t), nil)
require.NoError(t, err)
// Set current vault
currentVaultPath := filepath.Join(testStateDir, "currentvault")
vaultPath := filepath.Join(testStateDir, "vaults.d", testVaultName)
err = afero.WriteFile(fs, currentVaultPath, []byte(vaultPath), 0o600)
require.NoError(t, err)
// Get vault and set up long-term key
vlt, err := vault.GetCurrentVault(fs, testStateDir)
require.NoError(t, err)