Fix --keyid flag scope and implement secret move command
- Restrict --keyid flag to PGP unlocker type only - Add validation to prevent --keyid usage with non-PGP unlockers - Implement 'secret move' command with 'mv' and 'rename' aliases - Add comprehensive tests for move functionality - Update documentation to reflect optional nature of --keyid for PGP The move command allows renaming or moving secrets within a vault while preserving all versions and metadata. It fails if the destination already exists to prevent accidental overwrites.
This commit is contained in:
@@ -189,6 +189,12 @@ func TestSecretManagerIntegration(t *testing.T) {
|
||||
// Expected: Proper filesystem encoding (/ -> %)
|
||||
test12SecretNameFormats(t, tempDir, testMnemonic, runSecretWithEnv, runSecretWithStdin)
|
||||
|
||||
// Test 12b: Move/rename secrets
|
||||
// Commands: secret move, secret mv, secret rename
|
||||
// Purpose: Test moving and renaming secrets
|
||||
// Expected: Secret moved to new location, old location removed
|
||||
test12bMoveSecret(t, testMnemonic, runSecret, runSecretWithStdin)
|
||||
|
||||
// Test 13: Unlocker management
|
||||
// Commands: secret unlocker list, secret unlocker add pgp
|
||||
// Purpose: Test multiple unlocker types
|
||||
@@ -1091,6 +1097,80 @@ func test12SecretNameFormats(t *testing.T, tempDir, testMnemonic string, runSecr
|
||||
}
|
||||
}
|
||||
|
||||
func test12bMoveSecret(t *testing.T, testMnemonic string, runSecret func(...string) (string, error), runSecretWithStdin func(string, map[string]string, ...string) (string, error)) {
|
||||
// First, create a secret to move
|
||||
_, err := runSecretWithStdin("original-value", map[string]string{
|
||||
"SB_SECRET_MNEMONIC": testMnemonic,
|
||||
}, "add", "test/original")
|
||||
require.NoError(t, err, "add test/original should succeed")
|
||||
|
||||
// Test move command
|
||||
output, err := runSecret("move", "test/original", "test/renamed")
|
||||
require.NoError(t, err, "move should succeed")
|
||||
assert.Contains(t, output, "Moved secret 'test/original' to 'test/renamed'", "should show move confirmation")
|
||||
|
||||
// Need to create a runSecretWithEnv for get operations
|
||||
runSecretWithEnv := func(env map[string]string, args ...string) (string, error) {
|
||||
return cli.ExecuteCommandInProcess(args, "", env)
|
||||
}
|
||||
|
||||
// Verify original doesn't exist
|
||||
_, err = runSecretWithEnv(map[string]string{
|
||||
"SB_SECRET_MNEMONIC": testMnemonic,
|
||||
}, "get", "test/original")
|
||||
assert.Error(t, err, "get original should fail after move")
|
||||
|
||||
// Verify new location exists and has correct value
|
||||
getOutput, err := runSecretWithEnv(map[string]string{
|
||||
"SB_SECRET_MNEMONIC": testMnemonic,
|
||||
}, "get", "test/renamed")
|
||||
require.NoError(t, err, "get renamed should succeed")
|
||||
assert.Equal(t, "original-value", getOutput, "renamed secret should have original value")
|
||||
|
||||
// Test mv alias
|
||||
_, err = runSecretWithStdin("another-value", map[string]string{
|
||||
"SB_SECRET_MNEMONIC": testMnemonic,
|
||||
}, "add", "test/another")
|
||||
require.NoError(t, err, "add test/another should succeed")
|
||||
|
||||
output, err = runSecret("mv", "test/another", "test/moved-with-mv")
|
||||
require.NoError(t, err, "mv alias should work")
|
||||
assert.Contains(t, output, "Moved secret", "should show move confirmation")
|
||||
|
||||
// Test rename alias
|
||||
_, err = runSecretWithStdin("rename-test-value", map[string]string{
|
||||
"SB_SECRET_MNEMONIC": testMnemonic,
|
||||
}, "add", "test/rename-me")
|
||||
require.NoError(t, err, "add test/rename-me should succeed")
|
||||
|
||||
output, err = runSecret("rename", "test/rename-me", "test/renamed-with-alias")
|
||||
require.NoError(t, err, "rename alias should work")
|
||||
assert.Contains(t, output, "Moved secret", "should show move confirmation")
|
||||
|
||||
// Test error cases
|
||||
// Try to move non-existent secret
|
||||
output, err = runSecret("move", "test/nonexistent", "test/destination")
|
||||
assert.Error(t, err, "move non-existent should fail")
|
||||
assert.Contains(t, output, "not found", "should indicate source not found")
|
||||
|
||||
// Try to move to existing destination
|
||||
_, err = runSecretWithStdin("dest-value", map[string]string{
|
||||
"SB_SECRET_MNEMONIC": testMnemonic,
|
||||
}, "add", "test/existing-dest")
|
||||
require.NoError(t, err, "add test/existing-dest should succeed")
|
||||
|
||||
output, err = runSecret("move", "test/renamed", "test/existing-dest")
|
||||
assert.Error(t, err, "move to existing destination should fail")
|
||||
assert.Contains(t, output, "already exists", "should indicate destination exists")
|
||||
|
||||
// Verify the source wasn't removed since move failed
|
||||
getOutput, err = runSecretWithEnv(map[string]string{
|
||||
"SB_SECRET_MNEMONIC": testMnemonic,
|
||||
}, "get", "test/renamed")
|
||||
require.NoError(t, err, "get source should still work after failed move")
|
||||
assert.Equal(t, "original-value", getOutput, "source should still have original value")
|
||||
}
|
||||
|
||||
func test13UnlockerManagement(t *testing.T, tempDir, testMnemonic string, runSecret func(...string) (string, error), runSecretWithEnv func(map[string]string, ...string) (string, error)) {
|
||||
// Make sure we're in default vault
|
||||
_, err := runSecret("vault", "select", "default")
|
||||
|
||||
Reference in New Issue
Block a user