//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/secret" "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 removes // current-unlocker. // // The second case also gives the vault the unlocker directory "odd", whose // metadata names a type that `secret unlocker select` refuses, and which // sorts before the passphrase unlocker: neither removal makes it current. // //nolint:paralleltest // t.Setenv (GNUPGHOME) forbids parallel tests func TestUnlockerRemoveCurrent(t *testing.T) { tests := []struct { name string withOdd bool }{ {name: "two unlockers", withOdd: false}, {name: "and the directory odd", withOdd: true}, } for _, tt := range tests { t.Run(tt.name, func(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) if tt.withOdd { require.NoError(t, afero.WriteFile(fs, filepath.Join(testVaultDir(listTestVaultName), "unlockers.d", "odd", "unlocker-metadata.json"), []byte(`{"type": "odd"}`), secret.FilePerms)) } 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 passphrase unlocker") }) } }