feat!: key rename cli command (#9601)

<!--
The default pull request template is for types feat, fix, or refactor.
For other templates, add one of the following parameters to the url:
- template=docs.md
- template=other.md
-->

## Description
this PR adds a new function to the keyring interface, as well as a CLI command to rename a key in the keyring

ref: #9407

<!-- Add a description of the changes that this PR introduces and the files that
are the most critical to review. -->

---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [x] added `!` to the type prefix if API or client breaking change
- [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [x] provided a link to the relevant issue or specification
- [x] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [x] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [x] added a changelog entry to `CHANGELOG.md`
- [x] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [x] updated the relevant documentation or specification
- [x] reviewed "Files changed" and left comments if necessary
- [x] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [x] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [x] confirmed `!` in the type prefix if API or client breaking change
- [x] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [x] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [x] reviewed tests and test coverage
- [x] manually tested (if applicable)
This commit is contained in:
Tyler
2021-07-19 15:20:27 +00:00
committed by GitHub
parent 48cb9eab8c
commit 57d21fa8e0
7 changed files with 298 additions and 8 deletions
+67
View File
@@ -0,0 +1,67 @@
package keys
import (
"bufio"
"fmt"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/input"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/spf13/cobra"
)
// RenameKeyCommand renames a key from the key store.
func RenameKeyCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "rename <old_name> <new_name>",
Short: "Rename an existing key",
Long: `Rename a key from the Keybase backend.
Note that renaming offline or ledger keys will rename
only the public key references stored locally, i.e.
private keys stored in a ledger device cannot be renamed with the CLI.
`,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
buf := bufio.NewReader(cmd.InOrStdin())
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
oldName, newName := args[0], args[1]
info, err := clientCtx.Keyring.Key(oldName)
if err != nil {
return err
}
// confirm rename, unless -y is passed
if skip, _ := cmd.Flags().GetBool(flagYes); !skip {
prompt := fmt.Sprintf("Key reference will be renamed from %s to %s. Continue?", args[0], args[1])
if yes, err := input.GetConfirmation(prompt, buf, cmd.ErrOrStderr()); err != nil {
return err
} else if !yes {
return nil
}
}
if err := clientCtx.Keyring.Rename(oldName, newName); err != nil {
return err
}
if info.GetType() == keyring.TypeLedger || info.GetType() == keyring.TypeOffline {
cmd.PrintErrln("Public key reference renamed")
return nil
}
cmd.PrintErrln(fmt.Sprintf("Key was successfully renamed from %s to %s", oldName, newName))
return nil
},
}
cmd.Flags().BoolP(flagYes, "y", false, "Skip confirmation prompt when renaming offline or ledger key references")
return cmd
}
+98
View File
@@ -0,0 +1,98 @@
package keys
import (
"context"
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func Test_runRenameCmd(t *testing.T) {
// temp keybase
kbHome := t.TempDir()
cmd := RenameKeyCommand()
cmd.Flags().AddFlagSet(Commands(kbHome).PersistentFlags())
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
yesF, _ := cmd.Flags().GetBool(flagYes)
require.False(t, yesF)
fakeKeyName1 := "runRenameCmd_Key1"
fakeKeyName2 := "runRenameCmd_Key2"
path := sdk.GetConfig().GetFullBIP44Path()
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn)
require.NoError(t, err)
// put fakeKeyName1 in keyring
_, err = kb.NewAccount(fakeKeyName1, testutil.TestMnemonic, "", path, hd.Secp256k1)
require.NoError(t, err)
clientCtx := client.Context{}.
WithKeyringDir(kbHome).
WithKeyring(kb)
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
// rename a key 'blah' which doesnt exist
cmd.SetArgs([]string{"blah", "blaah", fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome)})
err = cmd.ExecuteContext(ctx)
require.Error(t, err)
require.EqualError(t, err, "blah.info: key not found")
// User confirmation missing
cmd.SetArgs([]string{
fakeKeyName1,
"nokey",
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
})
err = cmd.Execute()
require.Error(t, err)
require.Equal(t, "EOF", err.Error())
oldKey, err := kb.Key(fakeKeyName1)
require.NoError(t, err)
// add a confirmation
cmd.SetArgs([]string{
fakeKeyName1,
fakeKeyName2,
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
fmt.Sprintf("--%s=true", flagYes),
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
})
require.NoError(t, cmd.Execute())
// key1 is gone
_, err = kb.Key(fakeKeyName1)
require.Error(t, err)
// key2 exists now
renamedKey, err := kb.Key(fakeKeyName2)
require.NoError(t, err)
require.Equal(t, oldKey.GetPubKey(), renamedKey.GetPubKey())
require.Equal(t, oldKey.GetType(), renamedKey.GetType())
require.Equal(t, oldKey.GetAddress(), renamedKey.GetAddress())
require.Equal(t, oldKey.GetAlgo(), renamedKey.GetAlgo())
// try to rename key1 but it doesnt exist anymore so error
cmd.SetArgs([]string{
fakeKeyName1,
fakeKeyName2,
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
fmt.Sprintf("--%s=true", flagYes),
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
})
require.Error(t, cmd.Execute())
}
+1
View File
@@ -45,6 +45,7 @@ The pass backend requires GnuPG: https://gnupg.org/
ListKeysCmd(),
ShowKeysCmd(),
DeleteKeyCommand(),
RenameKeyCommand(),
ParseKeyStringCommand(),
MigrateCommand(),
)
+1 -1
View File
@@ -11,5 +11,5 @@ func TestCommands(t *testing.T) {
assert.NotNil(t, rootCommands)
// Commands are registered
assert.Equal(t, 9, len(rootCommands.Commands()))
assert.Equal(t, 10, len(rootCommands.Commands()))
}