Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add 'keyring list' command to CLI #3331

Merged
merged 30 commits into from
Jan 1, 2025
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
227365a
Issue 3153 first commit
ChrisBQu Dec 4, 2024
80f0661
Fixed one unit test
ChrisBQu Dec 4, 2024
76273ae
Feedback changes
ChrisBQu Dec 5, 2024
c8f70a1
Feedback changes
ChrisBQu Dec 5, 2024
462ee5f
Roll back package-lock.json in playground
ChrisBQu Dec 5, 2024
942ae7f
Adjust white space
ChrisBQu Dec 5, 2024
169fbd1
Removed extraneous line of code
ChrisBQu Dec 5, 2024
f6a0eb8
Major fixes; Changed tests
ChrisBQu Dec 5, 2024
5afefe6
Improve comments, remove error checks
ChrisBQu Dec 5, 2024
5a6078b
Delint
ChrisBQu Dec 5, 2024
563abbb
Merge branch 'sourcenetwork:develop' into issue-3140
ChrisBQu Dec 6, 2024
0872e94
First commit
ChrisBQu Dec 6, 2024
f9c395f
New approach: checking IsDevMode flag in handler_extras.go/Purge func…
ChrisBQu Dec 6, 2024
96dd91f
helpful comment
ChrisBQu Dec 6, 2024
94ca9d1
Delint
ChrisBQu Dec 6, 2024
50c9fa9
Clean up white space and comments
ChrisBQu Dec 6, 2024
12aee96
Changed comment
ChrisBQu Dec 6, 2024
4d8fea4
Adjusted tests
ChrisBQu Dec 6, 2024
5a48789
Merge branch 'issue-2756' of github.com:ChrisBQu/defradb into issue-3140
ChrisBQu Dec 16, 2024
6d103ce
First commit
ChrisBQu Dec 16, 2024
662db5a
Removed changes to unrelated file
ChrisBQu Dec 16, 2024
0b3a9b5
Refactored List() function, updated comments
ChrisBQu Dec 16, 2024
64a999c
Unit test and delint/gofmt
ChrisBQu Dec 16, 2024
1313d54
Updated comments, print statements
ChrisBQu Dec 17, 2024
9371602
Make docs
ChrisBQu Dec 17, 2024
4131a0a
Typo fix
ChrisBQu Dec 18, 2024
c16d843
Error output to systemKeyring.List and unit test
ChrisBQu Dec 18, 2024
bcb5df8
Comment formatting// assert -> require
ChrisBQu Dec 20, 2024
d7e407f
Merge branch 'develop' into issue-2756
ChrisBQu Dec 20, 2024
b78eacf
Merge branch 'develop' into issue-2756
ChrisBQu Jan 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ func NewDefraCommand() *cobra.Command {
MakeKeyringGenerateCommand(),
MakeKeyringImportCommand(),
MakeKeyringExportCommand(),
MakeKeyringListCommand(),
)

identity := MakeIdentityCommand()
Expand Down
54 changes: 54 additions & 0 deletions cli/keyring_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2024 Democratized Data Foundation
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package cli
ChrisBQu marked this conversation as resolved.
Show resolved Hide resolved

import (
"github.com/spf13/cobra"
)

// MakeKeyringListCommand creates a new command to list all keys in the keyring.
func MakeKeyringListCommand() *cobra.Command {
var cmd = &cobra.Command{
Use: "list",
Short: "List all keys in the keyring",
Long: `List all keys in the keyring.
The DEFRA_KEYRING_SECRET environment variable must be set to unlock the keyring.
This can also be done with a .env file in the working directory or at a path
defined with the --secret-file flag.

Example:
defradb keyring list`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
keyring, err := openKeyring(cmd)
if err != nil {
return err
}

Check warning on line 34 in cli/keyring_list.go

View check run for this annotation

Codecov / codecov/patch

cli/keyring_list.go#L33-L34

Added lines #L33 - L34 were not covered by tests

keyNames, err := keyring.List()
if err != nil {
return err
}

Check warning on line 39 in cli/keyring_list.go

View check run for this annotation

Codecov / codecov/patch

cli/keyring_list.go#L38-L39

Added lines #L38 - L39 were not covered by tests

if len(keyNames) == 0 {
cmd.Println("No keys found in the keyring.")
return nil
}

Check warning on line 44 in cli/keyring_list.go

View check run for this annotation

Codecov / codecov/patch

cli/keyring_list.go#L42-L44

Added lines #L42 - L44 were not covered by tests

cmd.Println("Keys in the keyring:")
for _, keyName := range keyNames {
cmd.Println("- " + keyName)
}
return nil
},
}
return cmd
}
66 changes: 66 additions & 0 deletions cli/keyring_list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2024 Democratized Data Foundation
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package cli

import (
"bytes"
"encoding/hex"
"os"
"regexp"
"testing"

"github.com/sourcenetwork/defradb/crypto"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestKeyringList(t *testing.T) {
rootdir := t.TempDir()

err := os.Setenv("DEFRA_KEYRING_SECRET", "password")
require.NoError(t, err)

keyNames := []string{"keyname1", "keyname2", "keyname3"}

// Insert the keys into the keyring
for _, keyName := range keyNames {
keyBytes, err := crypto.GenerateAES256()
require.NoError(t, err)
keyHex := hex.EncodeToString(keyBytes)
cmd := NewDefraCommand()
cmd.SetArgs([]string{"keyring", "import", "--rootdir", rootdir, keyName, keyHex})
err = cmd.Execute()
require.NoError(t, err)
}

// Run the 'keyring list' command, and require no error on the output
var output bytes.Buffer
cmd := NewDefraCommand()
cmd.SetOut(&output)
cmd.SetArgs([]string{"keyring", "list", "--rootdir", rootdir})
err = cmd.Execute()
require.NoError(t, err)

outputString := output.String()

// Use regex to extract the keys, and compare with the expected values
// We know what the format the output should be, which is:
// "Keys in the keyring:\n- keyname1\n- keyname2\n- keyname3\n"
re := regexp.MustCompile(`-\s([^\n]+)`)
matches := re.FindAllStringSubmatch(outputString, -1)
var extractedKeys []string
for _, match := range matches {
extractedKeys = append(extractedKeys, match[1])
}

assert.ElementsMatch(t, keyNames, extractedKeys, "The listed keys do not match the expected keys.")
}
1 change: 1 addition & 0 deletions docs/website/references/cli/defradb_keyring.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ To learn more about the available options:
* [defradb keyring export](defradb_keyring_export.md) - Export a private key
* [defradb keyring generate](defradb_keyring_generate.md) - Generate private keys
* [defradb keyring import](defradb_keyring_import.md) - Import a private key
* [defradb keyring list](defradb_keyring_list.md) - List all keys in the keyring

48 changes: 48 additions & 0 deletions docs/website/references/cli/defradb_keyring_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## defradb keyring list

List all keys in the keyring

### Synopsis

List all keys in the keyring.
The DEFRA_KEYRING_SECRET environment variable must be set to unlock the keyring.
This can also be done with a .env file in the working directory or at a path
defined with the --secret-file flag.

Example:
defradb keyring list

```
defradb keyring list [flags]
```

### Options

```
-h, --help help for list
```

### Options inherited from parent commands

```
--keyring-backend string Keyring backend to use. Options are file or system (default "file")
--keyring-namespace string Service name to use when using the system backend (default "defradb")
--keyring-path string Path to store encrypted keys when using the file backend (default "keys")
--log-format string Log format to use. Options are text or json (default "text")
--log-level string Log level to use. Options are debug, info, error, fatal (default "info")
--log-output string Log output path. Options are stderr or stdout. (default "stderr")
--log-overrides string Logger config overrides. Format <name>,<key>=<val>,...;<name>,...
--log-source Include source location in logs
--log-stacktrace Include stacktrace in error and fatal logs
--no-keyring Disable the keyring and generate ephemeral keys
--no-log-color Disable colored log output
--rootdir string Directory for persistent data (default: $HOME/.defradb)
--secret-file string Path to the file containing secrets (default ".env")
--source-hub-address string The SourceHub address authorized by the client to make SourceHub transactions on behalf of the actor
--url string URL of HTTP endpoint to listen on or connect to (default "127.0.0.1:9181")
```

### SEE ALSO

* [defradb keyring](defradb_keyring.md) - Manage DefraDB private keys

17 changes: 17 additions & 0 deletions keyring/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,20 @@
}
return err
}

func (f *fileKeyring) List() ([]string, error) {
files, err := os.ReadDir(f.dir)
if err != nil {
return nil, err
}

Check warning on line 72 in keyring/file.go

View check run for this annotation

Codecov / codecov/patch

keyring/file.go#L71-L72

Added lines #L71 - L72 were not covered by tests

// File names are key names
var keyNames []string
for _, file := range files {
if !file.IsDir() {
keyNames = append(keyNames, file.Name())
}
}

return keyNames, nil
}
2 changes: 2 additions & 0 deletions keyring/keyring.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ type Keyring interface {
//
// If a key with that name does not exist `ErrNotFound` is returned.
Delete(name string) error
// List returns a list of all keys in the keyring, used by the CLI 'keyring list' command
List() ([]string, error)
}
7 changes: 7 additions & 0 deletions keyring/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,10 @@
func (s *systemKeyring) Delete(user string) error {
return keyring.Delete(s.service, user)
}

func (s *systemKeyring) List() ([]string, error) {
// The OS keyring does not support listing keys
// This function is a stub for now because the Keyring interface requires it
// Currently, the 'defradb keyring list' command uses only fileKeyring
return nil, nil

Check warning on line 61 in keyring/system.go

View check run for this annotation

Codecov / codecov/patch

keyring/system.go#L57-L61

Added lines #L57 - L61 were not covered by tests
Copy link
Contributor

@AndrewSisley AndrewSisley Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: I was worried you would leave this func like this :) Sorry I should have clarified on discord.

I agree that this is the best choice for now, however I think it should error, not silently return - otherwise the users will go bald from the large amount of head scratching that they'll do when trying to figure out why their added keys never appear in the keyring! (it looks like it is empty when they call list on an os-keyring no?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the logic behind it throwing an error. My original thoughts were that this function should never actually get called so there was no need to have it do anything. But as I think over it some more, that's all the more reason to make it throw an error. I think you are right.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made the changes. I'm going to tag you for re-review, so let me know what you think!

}
Loading