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:
@@ -125,6 +125,24 @@ func newRemoveCmd() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newMoveCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "move <source> <destination>",
|
||||
Aliases: []string{"mv", "rename"},
|
||||
Short: "Move or rename a secret",
|
||||
Long: `Move or rename a secret within the current vault. ` +
|
||||
`If the destination already exists, the operation will fail.`,
|
||||
Args: cobra.ExactArgs(2), //nolint:mnd // Command requires exactly 2 arguments: source and destination
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cli := NewCLIInstance()
|
||||
|
||||
return cli.MoveSecret(cmd, args[0], args[1])
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// updateBufferSize updates the buffer size based on usage pattern
|
||||
func updateBufferSize(currentSize int, sameSize *int) int {
|
||||
*sameSize++
|
||||
@@ -517,3 +535,51 @@ func (cli *Instance) RemoveSecret(cmd *cobra.Command, secretName string, _ bool)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MoveSecret moves or renames a secret
|
||||
func (cli *Instance) MoveSecret(cmd *cobra.Command, sourceName, destName string) error {
|
||||
// Get current vault
|
||||
currentVlt, err := vault.GetCurrentVault(cli.fs, cli.stateDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get vault directory
|
||||
vaultDir, err := currentVlt.GetDirectory()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if source exists
|
||||
sourceEncoded := strings.ReplaceAll(sourceName, "/", "%")
|
||||
sourceDir := filepath.Join(vaultDir, "secrets.d", sourceEncoded)
|
||||
|
||||
exists, err := afero.DirExists(cli.fs, sourceDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check if source secret exists: %w", err)
|
||||
}
|
||||
if !exists {
|
||||
return fmt.Errorf("secret '%s' not found", sourceName)
|
||||
}
|
||||
|
||||
// Check if destination already exists
|
||||
destEncoded := strings.ReplaceAll(destName, "/", "%")
|
||||
destDir := filepath.Join(vaultDir, "secrets.d", destEncoded)
|
||||
|
||||
exists, err = afero.DirExists(cli.fs, destDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check if destination secret exists: %w", err)
|
||||
}
|
||||
if exists {
|
||||
return fmt.Errorf("secret '%s' already exists", destName)
|
||||
}
|
||||
|
||||
// Perform the move
|
||||
if err := cli.fs.Rename(sourceDir, destDir); err != nil {
|
||||
return fmt.Errorf("failed to move secret: %w", err)
|
||||
}
|
||||
|
||||
cmd.Printf("Moved secret '%s' to '%s'\n", sourceName, destName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user