check / check (push) Canceled after 0s
Removing the vault's current unlocker left current-unlocker naming it, so every command that opened the vault failed although another unlocker remained, and the error pointed at the mnemonic. RemoveUnlocker now makes the first other unlocker, in the order `secret unlocker list` shows, current before the removal and returns its ID, which `secret unlocker remove` prints; removing the last unlocker also removes current-unlocker. When current-unlocker names an unlocker that does not exist and the vault has others, the error wraps ErrUnlockerNotFound and says to run `secret unlocker select`, without the mnemonic advice. Unverified: no test covers that advice for a vault other than the current one, which gets `secret vault select` first. Model: opus-5-5
69 lines
2.2 KiB
Go
69 lines
2.2 KiB
Go
//nolint:testpackage // white-box test of unexported internals
|
|
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/awnumar/memguard"
|
|
"github.com/spf13/afero"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/secret/internal/vault"
|
|
)
|
|
|
|
// TestUnlockerRemoveCurrent is a regression test for
|
|
// https://git.eeqj.de/sneak/secret/issues/137. A vault has a passphrase
|
|
// unlocker and a PGP unlocker, the current one. Removing the PGP unlocker
|
|
// makes the passphrase unlocker current and says so, and the vault then
|
|
// opens through it. Removing the passphrase unlocker too, the vault's last,
|
|
// removes current-unlocker.
|
|
//
|
|
//nolint:paralleltest // t.Setenv (GNUPGHOME) forbids parallel tests
|
|
func TestUnlockerRemoveCurrent(t *testing.T) {
|
|
newTestGPGKey(t)
|
|
|
|
passphrase := memguard.NewBufferFromBytes([]byte(testPassphrase))
|
|
t.Cleanup(passphrase.Destroy)
|
|
|
|
fs := afero.NewMemMapFs()
|
|
vlt, err := vault.CreateVault(fs, listTestStateDir, listTestVaultName,
|
|
testMnemonicBuffer(t), nil)
|
|
require.NoError(t, err)
|
|
|
|
passphraseUnlocker, err := vlt.CreatePassphraseUnlocker(passphrase)
|
|
require.NoError(t, err)
|
|
|
|
instance, cmd := newTestInstance(fs)
|
|
instance.UnlockPassphrase = passphrase
|
|
|
|
cmd.Flags().String("keyid", unreadableTestGPGUserID, "")
|
|
require.NoError(t, instance.UnlockersAdd(unlockerTypePGP, cmd))
|
|
|
|
pgpUnlocker, err := vlt.GetCurrentUnlocker()
|
|
require.NoError(t, err)
|
|
require.Equal(t, unlockerTypePGP, pgpUnlocker.GetType())
|
|
|
|
var output bytes.Buffer
|
|
|
|
cmd.SetOut(&output)
|
|
require.NoError(t, instance.UnlockersRemove(pgpUnlocker.GetID(), true, cmd))
|
|
assert.Contains(t, output.String(),
|
|
"Switched current unlocker to '"+passphraseUnlocker.GetID()+"'")
|
|
|
|
reopened := vault.NewVault(fs, listTestStateDir, listTestVaultName)
|
|
reopened.UnlockPassphrase = passphrase
|
|
|
|
_, err = reopened.GetOrDeriveLongTermKey()
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t,
|
|
instance.UnlockersRemove(passphraseUnlocker.GetID(), true, cmd))
|
|
|
|
exists, err := afero.Exists(fs,
|
|
filepath.Join(testVaultDir(listTestVaultName), "current-unlocker"))
|
|
require.NoError(t, err)
|
|
assert.False(t, exists, "current-unlocker is left after the last unlocker")
|
|
}
|