diff options
Diffstat (limited to 'internal/store/store_shred.go')
| -rw-r--r-- | internal/store/store_shred.go | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/internal/store/store_shred.go b/internal/store/store_shred.go new file mode 100644 index 0000000..7d28f70 --- /dev/null +++ b/internal/store/store_shred.go @@ -0,0 +1,54 @@ +// store_shred.go provides secure file deletion for the secret store. +// ShredFile uses GNU shred(1) when available and falls back to "rm -Pfv". +// ShredAllExported iterates cfg.ExportDir and shreds every regular file, +// mirroring Ruby's Geheim#shred_all_exported best-effort deletion strategy. +package store + +import ( + "context" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" +) + +// ShredAllExported removes (shreds) every regular file in cfg.ExportDir. +// Uses GNU shred when available; falls back to "rm -Pfv" otherwise. +// Mirrors Ruby's shred_all_exported: iterates all files and returns the last +// non-nil error so that as many files as possible are shredded even on failure. +func (s *Store) ShredAllExported(ctx context.Context) error { + entries, err := filepath.Glob(filepath.Join(s.cfg.ExportDir, "*")) + if err != nil { + return fmt.Errorf("listing export dir: %w", err) + } + + var lastErr error + for _, entry := range entries { + info, err := os.Stat(entry) + if err != nil || !info.Mode().IsRegular() { + continue + } + if err := ShredFile(ctx, entry); err != nil { + // Record the error but keep shredding — security demands best-effort + // destruction of all exported secrets even if one fails. + lastErr = err + } + } + return lastErr +} + +// ShredFile destroys a single file using shred(1) if available, or rm -Pfv. +// This mirrors Ruby's Geheim#shred_file method. +func ShredFile(ctx context.Context, filePath string) error { + if _, err := exec.LookPath("shred"); err == nil { + cmd := exec.CommandContext(ctx, "shred", "-vu", filePath) + cmd.Stdout = io.Discard + cmd.Stderr = io.Discard + return cmd.Run() + } + cmd := exec.CommandContext(ctx, "rm", "-Pfv", filePath) + cmd.Stdout = io.Discard + cmd.Stderr = io.Discard + return cmd.Run() +} |
