Refactor unlockers command structure and add quiet flag to list command
- Rename 'unlockers' command to 'unlocker' for consistency - Move all unlocker subcommands (list, add, remove) under single 'unlocker' command - Add --quiet/-q flag to 'secret list' for scripting support - Update documentation and tests to reflect command changes The quiet flag outputs only secret names without headers or formatting, making it ideal for shell script usage like: secret get $(secret list -q | head -1)
This commit is contained in:
parent
70d19d09d0
commit
a73a409fe4
@ -26,3 +26,5 @@ Read the rules in AGENTS.md and follow them.
|
|||||||
* Do not stop working on a task until you have reached the definition of
|
* Do not stop working on a task until you have reached the definition of
|
||||||
done provided to you in the initial instruction. Don't do part or most of
|
done provided to you in the initial instruction. Don't do part or most of
|
||||||
the work, do all of the work until the criteria for done are met.
|
the work, do all of the work until the criteria for done are met.
|
||||||
|
|
||||||
|
* When you complete each task, if the tests are passing and the code is formatted and there are no linter errors, always commit and push your work. Use a good commit message and don't mention any author or co-author attribution.
|
3
Makefile
3
Makefile
@ -11,8 +11,7 @@ default: check
|
|||||||
|
|
||||||
build: ./secret
|
build: ./secret
|
||||||
|
|
||||||
# Simple build (no code signing needed)
|
./secret: ./internal/*/*.go ./pkg/*/*.go ./cmd/*/*.go ./go.*
|
||||||
./secret:
|
|
||||||
go build -v -ldflags "$(LDFLAGS)" -o $@ cmd/secret/main.go
|
go build -v -ldflags "$(LDFLAGS)" -o $@ cmd/secret/main.go
|
||||||
|
|
||||||
vet:
|
vet:
|
||||||
|
18
README.md
18
README.md
@ -132,10 +132,10 @@ Generates and stores a random secret.
|
|||||||
|
|
||||||
### Unlocker Management
|
### Unlocker Management
|
||||||
|
|
||||||
#### `secret unlockers list [--json]` / `secret unlockers ls`
|
#### `secret unlocker list [--json]` / `secret unlocker ls`
|
||||||
Lists all unlockers in the current vault with their metadata.
|
Lists all unlockers in the current vault with their metadata.
|
||||||
|
|
||||||
#### `secret unlockers add <type> [options]`
|
#### `secret unlocker add <type> [options]`
|
||||||
Creates a new unlocker of the specified type:
|
Creates a new unlocker of the specified type:
|
||||||
|
|
||||||
**Types:**
|
**Types:**
|
||||||
@ -146,7 +146,7 @@ Creates a new unlocker of the specified type:
|
|||||||
**Options:**
|
**Options:**
|
||||||
- `--keyid <id>`: GPG key ID (required for PGP type)
|
- `--keyid <id>`: GPG key ID (required for PGP type)
|
||||||
|
|
||||||
#### `secret unlockers remove <unlocker-id> [--force]` / `secret unlockers rm` ⚠️ 🛑
|
#### `secret unlocker remove <unlocker-id> [--force]` / `secret unlocker rm` ⚠️ 🛑
|
||||||
**DANGER**: Permanently removes an unlocker. Like Unix `rm`, this command does not ask for confirmation.
|
**DANGER**: Permanently removes an unlocker. Like Unix `rm`, this command does not ask for confirmation.
|
||||||
Cannot remove the last unlocker if the vault has secrets unless --force is used.
|
Cannot remove the last unlocker if the vault has secrets unless --force is used.
|
||||||
- `--force, -f`: Force removal of last unlocker even if vault has secrets
|
- `--force, -f`: Force removal of last unlocker even if vault has secrets
|
||||||
@ -308,7 +308,7 @@ secret vault create personal
|
|||||||
# Work with work vault
|
# Work with work vault
|
||||||
secret vault select work
|
secret vault select work
|
||||||
echo "work-db-pass" | secret add database/password
|
echo "work-db-pass" | secret add database/password
|
||||||
secret unlockers add passphrase # Add passphrase authentication
|
secret unlocker add passphrase # Add passphrase authentication
|
||||||
|
|
||||||
# Switch to personal vault
|
# Switch to personal vault
|
||||||
secret vault select personal
|
secret vault select personal
|
||||||
@ -324,18 +324,18 @@ secret vault remove personal --force
|
|||||||
### Advanced Authentication
|
### Advanced Authentication
|
||||||
```bash
|
```bash
|
||||||
# Add multiple unlock methods
|
# Add multiple unlock methods
|
||||||
secret unlockers add passphrase # Password-based
|
secret unlocker add passphrase # Password-based
|
||||||
secret unlockers add pgp --keyid ABCD1234 # GPG key
|
secret unlocker add pgp --keyid ABCD1234 # GPG key
|
||||||
secret unlockers add keychain # macOS Keychain (macOS only)
|
secret unlocker add keychain # macOS Keychain (macOS only)
|
||||||
|
|
||||||
# List unlockers
|
# List unlockers
|
||||||
secret unlockers list
|
secret unlocker list
|
||||||
|
|
||||||
# Select a specific unlocker
|
# Select a specific unlocker
|
||||||
secret unlocker select <unlocker-id>
|
secret unlocker select <unlocker-id>
|
||||||
|
|
||||||
# Remove an unlocker ⚠️ 🛑 (NO CONFIRMATION!)
|
# Remove an unlocker ⚠️ 🛑 (NO CONFIRMATION!)
|
||||||
secret unlockers remove <unlocker-id>
|
secret unlocker remove <unlocker-id>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Version Management
|
### Version Management
|
||||||
|
@ -177,6 +177,12 @@ func TestSecretManagerIntegration(t *testing.T) {
|
|||||||
// Expected: Shows database/password with metadata
|
// Expected: Shows database/password with metadata
|
||||||
test11ListSecrets(t, testMnemonic, runSecret, runSecretWithStdin)
|
test11ListSecrets(t, testMnemonic, runSecret, runSecretWithStdin)
|
||||||
|
|
||||||
|
// Test 11b: List secrets with quiet flag
|
||||||
|
// Command: secret list -q
|
||||||
|
// Purpose: Test quiet output for scripting
|
||||||
|
// Expected: Only secret names, no headers or formatting
|
||||||
|
test11bListSecretsQuiet(t, testMnemonic, runSecret)
|
||||||
|
|
||||||
// Test 12: Add secrets with different name formats
|
// Test 12: Add secrets with different name formats
|
||||||
// Commands: Various secret names (paths, dots, underscores)
|
// Commands: Various secret names (paths, dots, underscores)
|
||||||
// Purpose: Test secret name validation and storage encoding
|
// Purpose: Test secret name validation and storage encoding
|
||||||
@ -184,7 +190,7 @@ func TestSecretManagerIntegration(t *testing.T) {
|
|||||||
test12SecretNameFormats(t, tempDir, testMnemonic, runSecretWithEnv, runSecretWithStdin)
|
test12SecretNameFormats(t, tempDir, testMnemonic, runSecretWithEnv, runSecretWithStdin)
|
||||||
|
|
||||||
// Test 13: Unlocker management
|
// Test 13: Unlocker management
|
||||||
// Commands: secret unlockers list, secret unlockers add pgp
|
// Commands: secret unlocker list, secret unlocker add pgp
|
||||||
// Purpose: Test multiple unlocker types
|
// Purpose: Test multiple unlocker types
|
||||||
// Expected filesystem:
|
// Expected filesystem:
|
||||||
// - Multiple directories under unlockers.d/
|
// - Multiple directories under unlockers.d/
|
||||||
@ -901,6 +907,81 @@ func test11ListSecrets(t *testing.T, testMnemonic string, runSecret func(...stri
|
|||||||
assert.True(t, secretNames["database/password"], "should have database/password")
|
assert.True(t, secretNames["database/password"], "should have database/password")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func test11bListSecretsQuiet(t *testing.T, testMnemonic string, runSecret func(...string) (string, error)) {
|
||||||
|
// Test quiet output
|
||||||
|
quietOutput, err := runSecret("list", "-q")
|
||||||
|
require.NoError(t, err, "secret list -q should succeed")
|
||||||
|
|
||||||
|
// Split output into lines
|
||||||
|
lines := strings.Split(strings.TrimSpace(quietOutput), "\n")
|
||||||
|
|
||||||
|
// Should have exactly 3 lines (3 secrets)
|
||||||
|
assert.Len(t, lines, 3, "quiet output should have exactly 3 lines")
|
||||||
|
|
||||||
|
// Should not contain any headers or formatting
|
||||||
|
assert.NotContains(t, quietOutput, "Secrets in vault", "should not have vault header")
|
||||||
|
assert.NotContains(t, quietOutput, "NAME", "should not have NAME header")
|
||||||
|
assert.NotContains(t, quietOutput, "LAST UPDATED", "should not have LAST UPDATED header")
|
||||||
|
assert.NotContains(t, quietOutput, "Total:", "should not have total count")
|
||||||
|
assert.NotContains(t, quietOutput, "----", "should not have separator lines")
|
||||||
|
|
||||||
|
// Should contain exactly the secret names
|
||||||
|
secretNames := make(map[string]bool)
|
||||||
|
for _, line := range lines {
|
||||||
|
secretNames[line] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.True(t, secretNames["api/key"], "should have api/key")
|
||||||
|
assert.True(t, secretNames["config/database.yaml"], "should have config/database.yaml")
|
||||||
|
assert.True(t, secretNames["database/password"], "should have database/password")
|
||||||
|
|
||||||
|
// Test quiet output with filter
|
||||||
|
quietFilterOutput, err := runSecret("list", "database", "-q")
|
||||||
|
require.NoError(t, err, "secret list with filter and -q should succeed")
|
||||||
|
|
||||||
|
// Should only show secrets matching filter
|
||||||
|
filteredLines := strings.Split(strings.TrimSpace(quietFilterOutput), "\n")
|
||||||
|
assert.Len(t, filteredLines, 2, "quiet filtered output should have exactly 2 lines")
|
||||||
|
|
||||||
|
// Verify filtered results
|
||||||
|
filteredSecrets := make(map[string]bool)
|
||||||
|
for _, line := range filteredLines {
|
||||||
|
filteredSecrets[line] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.True(t, filteredSecrets["config/database.yaml"], "should have config/database.yaml")
|
||||||
|
assert.True(t, filteredSecrets["database/password"], "should have database/password")
|
||||||
|
assert.False(t, filteredSecrets["api/key"], "should not have api/key")
|
||||||
|
|
||||||
|
// Test that quiet and JSON flags are mutually exclusive behavior
|
||||||
|
// (JSON should take precedence if both are specified)
|
||||||
|
jsonQuietOutput, err := runSecret("list", "--json", "-q")
|
||||||
|
require.NoError(t, err, "secret list --json -q should succeed")
|
||||||
|
|
||||||
|
// Should be valid JSON, not quiet output
|
||||||
|
var jsonResponse map[string]interface{}
|
||||||
|
err = json.Unmarshal([]byte(jsonQuietOutput), &jsonResponse)
|
||||||
|
assert.NoError(t, err, "output should be valid JSON when both flags are used")
|
||||||
|
|
||||||
|
// Test using quiet output in command substitution would work like:
|
||||||
|
// secret get $(secret list -q | head -1)
|
||||||
|
// We'll simulate this by getting the first secret name
|
||||||
|
firstSecret := lines[0]
|
||||||
|
|
||||||
|
// Need to create a runSecretWithEnv to provide mnemonic for get operation
|
||||||
|
runSecretWithEnv := func(env map[string]string, args ...string) (string, error) {
|
||||||
|
return cli.ExecuteCommandInProcess(args, "", env)
|
||||||
|
}
|
||||||
|
|
||||||
|
getOutput, err := runSecretWithEnv(map[string]string{
|
||||||
|
"SB_SECRET_MNEMONIC": testMnemonic,
|
||||||
|
}, "get", firstSecret)
|
||||||
|
require.NoError(t, err, "get with secret name from quiet output should succeed")
|
||||||
|
|
||||||
|
// Verify we got a value (not empty)
|
||||||
|
assert.NotEmpty(t, getOutput, "should retrieve a non-empty secret value")
|
||||||
|
}
|
||||||
|
|
||||||
func test12SecretNameFormats(t *testing.T, tempDir, testMnemonic string, runSecretWithEnv func(map[string]string, ...string) (string, error), runSecretWithStdin func(string, map[string]string, ...string) (string, error)) {
|
func test12SecretNameFormats(t *testing.T, tempDir, testMnemonic string, runSecretWithEnv func(map[string]string, ...string) (string, error), runSecretWithStdin func(string, map[string]string, ...string) (string, error)) {
|
||||||
// Make sure we're in default vault
|
// Make sure we're in default vault
|
||||||
runSecret := func(args ...string) (string, error) {
|
runSecret := func(args ...string) (string, error) {
|
||||||
@ -1016,9 +1097,9 @@ func test13UnlockerManagement(t *testing.T, tempDir, testMnemonic string, runSec
|
|||||||
require.NoError(t, err, "vault select should succeed")
|
require.NoError(t, err, "vault select should succeed")
|
||||||
|
|
||||||
// List unlockers
|
// List unlockers
|
||||||
output, err := runSecret("unlockers", "list")
|
output, err := runSecret("unlocker", "list")
|
||||||
require.NoError(t, err, "unlockers list should succeed")
|
require.NoError(t, err, "unlocker list should succeed")
|
||||||
t.Logf("DEBUG: unlockers list output: %q", output)
|
t.Logf("DEBUG: unlocker list output: %q", output)
|
||||||
|
|
||||||
// Should have the passphrase unlocker created during init
|
// Should have the passphrase unlocker created during init
|
||||||
assert.Contains(t, output, "passphrase", "should have passphrase unlocker")
|
assert.Contains(t, output, "passphrase", "should have passphrase unlocker")
|
||||||
@ -1027,15 +1108,15 @@ func test13UnlockerManagement(t *testing.T, tempDir, testMnemonic string, runSec
|
|||||||
output, err = runSecretWithEnv(map[string]string{
|
output, err = runSecretWithEnv(map[string]string{
|
||||||
"SB_UNLOCK_PASSPHRASE": "another-passphrase",
|
"SB_UNLOCK_PASSPHRASE": "another-passphrase",
|
||||||
"SB_SECRET_MNEMONIC": testMnemonic, // Need mnemonic to get long-term key
|
"SB_SECRET_MNEMONIC": testMnemonic, // Need mnemonic to get long-term key
|
||||||
}, "unlockers", "add", "passphrase")
|
}, "unlocker", "add", "passphrase")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("Error adding passphrase unlocker: %v, output: %s", err, output)
|
t.Logf("Error adding passphrase unlocker: %v, output: %s", err, output)
|
||||||
}
|
}
|
||||||
require.NoError(t, err, "add passphrase unlocker should succeed")
|
require.NoError(t, err, "add passphrase unlocker should succeed")
|
||||||
|
|
||||||
// List unlockers again - should have 2 now
|
// List unlockers again - should have 2 now
|
||||||
output, err = runSecret("unlockers", "list")
|
output, err = runSecret("unlocker", "list")
|
||||||
require.NoError(t, err, "unlockers list should succeed")
|
require.NoError(t, err, "unlocker list should succeed")
|
||||||
|
|
||||||
// Count passphrase unlockers
|
// Count passphrase unlockers
|
||||||
lines := strings.Split(output, "\n")
|
lines := strings.Split(output, "\n")
|
||||||
@ -1051,8 +1132,8 @@ func test13UnlockerManagement(t *testing.T, tempDir, testMnemonic string, runSec
|
|||||||
assert.GreaterOrEqual(t, passphraseCount, 1, "should have at least 1 passphrase unlocker")
|
assert.GreaterOrEqual(t, passphraseCount, 1, "should have at least 1 passphrase unlocker")
|
||||||
|
|
||||||
// Test JSON output
|
// Test JSON output
|
||||||
jsonOutput, err := runSecret("unlockers", "list", "--json")
|
jsonOutput, err := runSecret("unlocker", "list", "--json")
|
||||||
require.NoError(t, err, "unlockers list --json should succeed")
|
require.NoError(t, err, "unlocker list --json should succeed")
|
||||||
|
|
||||||
var response map[string]interface{}
|
var response map[string]interface{}
|
||||||
err = json.Unmarshal([]byte(jsonOutput), &response)
|
err = json.Unmarshal([]byte(jsonOutput), &response)
|
||||||
@ -1536,10 +1617,10 @@ func test22JSONOutput(t *testing.T, runSecret func(...string) (string, error)) {
|
|||||||
|
|
||||||
// Test secret list --json (already tested in test 11)
|
// Test secret list --json (already tested in test 11)
|
||||||
|
|
||||||
// Test unlockers list --json (already tested in test 13)
|
// Test unlocker list --json (already tested in test 13)
|
||||||
|
|
||||||
// All JSON outputs verified to be valid and contain expected fields
|
// All JSON outputs verified to be valid and contain expected fields
|
||||||
t.Log("JSON output formats verified for vault list, secret list, and unlockers list")
|
t.Log("JSON output formats verified for vault list, secret list, and unlocker list")
|
||||||
}
|
}
|
||||||
|
|
||||||
func test23ErrorHandling(t *testing.T, tempDir, secretPath, testMnemonic string, runSecret func(...string) (string, error), runSecretWithEnv func(map[string]string, ...string) (string, error)) {
|
func test23ErrorHandling(t *testing.T, tempDir, secretPath, testMnemonic string, runSecret func(...string) (string, error), runSecretWithEnv func(map[string]string, ...string) (string, error)) {
|
||||||
|
@ -35,7 +35,6 @@ func newRootCmd() *cobra.Command {
|
|||||||
cmd.AddCommand(newGetCmd())
|
cmd.AddCommand(newGetCmd())
|
||||||
cmd.AddCommand(newListCmd())
|
cmd.AddCommand(newListCmd())
|
||||||
cmd.AddCommand(newRemoveCmd())
|
cmd.AddCommand(newRemoveCmd())
|
||||||
cmd.AddCommand(newUnlockersCmd())
|
|
||||||
cmd.AddCommand(newUnlockerCmd())
|
cmd.AddCommand(newUnlockerCmd())
|
||||||
cmd.AddCommand(newImportCmd())
|
cmd.AddCommand(newImportCmd())
|
||||||
cmd.AddCommand(newEncryptCmd())
|
cmd.AddCommand(newEncryptCmd())
|
||||||
|
@ -65,6 +65,7 @@ func newListCmd() *cobra.Command {
|
|||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
jsonOutput, _ := cmd.Flags().GetBool("json")
|
jsonOutput, _ := cmd.Flags().GetBool("json")
|
||||||
|
quietOutput, _ := cmd.Flags().GetBool("quiet")
|
||||||
|
|
||||||
var filter string
|
var filter string
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
@ -73,11 +74,12 @@ func newListCmd() *cobra.Command {
|
|||||||
|
|
||||||
cli := NewCLIInstance()
|
cli := NewCLIInstance()
|
||||||
|
|
||||||
return cli.ListSecrets(cmd, jsonOutput, filter)
|
return cli.ListSecrets(cmd, jsonOutput, quietOutput, filter)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().Bool("json", false, "Output in JSON format")
|
cmd.Flags().Bool("json", false, "Output in JSON format")
|
||||||
|
cmd.Flags().BoolP("quiet", "q", false, "Output only secret names (for scripting)")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@ -284,7 +286,7 @@ func (cli *Instance) GetSecretWithVersion(cmd *cobra.Command, secretName string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListSecrets lists all secrets in the current vault
|
// ListSecrets lists all secrets in the current vault
|
||||||
func (cli *Instance) ListSecrets(cmd *cobra.Command, jsonOutput bool, filter string) error {
|
func (cli *Instance) ListSecrets(cmd *cobra.Command, jsonOutput bool, quietOutput bool, filter string) error {
|
||||||
// Get current vault
|
// Get current vault
|
||||||
vlt, err := vault.GetCurrentVault(cli.fs, cli.stateDir)
|
vlt, err := vault.GetCurrentVault(cli.fs, cli.stateDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -341,6 +343,11 @@ func (cli *Instance) ListSecrets(cmd *cobra.Command, jsonOutput bool, filter str
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd.Println(string(jsonBytes))
|
cmd.Println(string(jsonBytes))
|
||||||
|
} else if quietOutput {
|
||||||
|
// Quiet output - just secret names
|
||||||
|
for _, secretName := range filteredSecrets {
|
||||||
|
cmd.Println(secretName)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Pretty table output
|
// Pretty table output
|
||||||
if len(filteredSecrets) == 0 {
|
if len(filteredSecrets) == 0 {
|
||||||
|
@ -56,21 +56,22 @@ func getDefaultGPGKey() (string, error) {
|
|||||||
return "", fmt.Errorf("no GPG secret keys found")
|
return "", fmt.Errorf("no GPG secret keys found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUnlockersCmd() *cobra.Command {
|
func newUnlockerCmd() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "unlockers",
|
Use: "unlocker",
|
||||||
Short: "Manage unlockers",
|
Short: "Manage unlockers",
|
||||||
Long: `Create, list, and remove unlockers for the current vault.`,
|
Long: `Create, list, and remove unlockers for the current vault.`,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(newUnlockersListCmd())
|
cmd.AddCommand(newUnlockerListCmd())
|
||||||
cmd.AddCommand(newUnlockersAddCmd())
|
cmd.AddCommand(newUnlockerAddCmd())
|
||||||
cmd.AddCommand(newUnlockersRemoveCmd())
|
cmd.AddCommand(newUnlockerRemoveCmd())
|
||||||
|
cmd.AddCommand(newUnlockerSelectCmd())
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUnlockersListCmd() *cobra.Command {
|
func newUnlockerListCmd() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "list",
|
Use: "list",
|
||||||
Aliases: []string{"ls"},
|
Aliases: []string{"ls"},
|
||||||
@ -90,7 +91,7 @@ func newUnlockersListCmd() *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUnlockersAddCmd() *cobra.Command {
|
func newUnlockerAddCmd() *cobra.Command {
|
||||||
// Build the supported types list based on platform
|
// Build the supported types list based on platform
|
||||||
supportedTypes := "passphrase, pgp"
|
supportedTypes := "passphrase, pgp"
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
@ -120,7 +121,7 @@ func newUnlockersAddCmd() *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUnlockersRemoveCmd() *cobra.Command {
|
func newUnlockerRemoveCmd() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "remove <unlocker-id>",
|
Use: "remove <unlocker-id>",
|
||||||
Aliases: []string{"rm"},
|
Aliases: []string{"rm"},
|
||||||
@ -142,19 +143,7 @@ func newUnlockersRemoveCmd() *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUnlockerCmd() *cobra.Command {
|
func newUnlockerSelectCmd() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "unlocker",
|
|
||||||
Short: "Manage current unlocker",
|
|
||||||
Long: `Select the current unlocker for operations.`,
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.AddCommand(newUnlockerSelectSubCmd())
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func newUnlockerSelectSubCmd() *cobra.Command {
|
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "select <unlocker-id>",
|
Use: "select <unlocker-id>",
|
||||||
Short: "Select an unlocker as current",
|
Short: "Select an unlocker as current",
|
||||||
@ -274,7 +263,7 @@ func (cli *Instance) UnlockersList(jsonOutput bool) error {
|
|||||||
// Pretty table output
|
// Pretty table output
|
||||||
if len(unlockers) == 0 {
|
if len(unlockers) == 0 {
|
||||||
cli.cmd.Println("No unlockers found in current vault.")
|
cli.cmd.Println("No unlockers found in current vault.")
|
||||||
cli.cmd.Println("Run 'secret unlockers add passphrase' to create one.")
|
cli.cmd.Println("Run 'secret unlocker add passphrase' to create one.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user