Skip to content

Implement spike secret purge #257

@v0lkan

Description

@v0lkan

After all versions of a secret are deleted, the secret metadata remains in the backend storage indefinitely. This causes unbounded storage growth over time. A spike secret purge command is needed to permanently remove these empty secret entries.

Problem

When a user deletes all versions of a secret:

spike secret delete secrets/db/creds --all-versions

The secret's metadata (path, timestamps, etc.) remains in the backend with CurrentVersion == 0. Over time, this accumulates and wastes storage space.

Proposed Solution

Implement a spike secret purge command that:

  1. Scans all secrets in the backend
  2. Identifies secrets where CurrentVersion == 0 (all versions deleted)
  3. Uses the backend's Destroy() method to permanently remove them
  4. Reports how many secrets were purged

Usage

Interactive confirmation (default)

spike secret purge

Output: Found 42 empty secrets. Purge them? [y/N]

Skip confirmation

spike secret purge --force

Show what would be purged without actually purging

spike secret purge --dry-run

Output:

Would purge: secrets/old/api-key

Would purge: secrets/deprecated/token

Would purge: secrets/test/temp

Dry run: 3 secrets would be purged

Combined: preview then purge

spike secret purge --dry-run
spike secret purge --force

Future Enhancement

Consider adding time-based filtering:

Only purge secrets emptied more than 30 days ago

spike secret purge --older-than 30d

This allows operators to keep recently-deleted secrets recoverable for a grace period.

Implementation Notes

SDK Support

The spike-sdk-go already has the necessary building blocks:

  • Value.IsEmpty() - Check if a secret has no versions
  • KV.Destroy() - Permanently remove a secret entry

Backend Changes

SPIKE Nexus backend needs a corresponding Destroy() implementation:

  • SQLite: DELETE FROM secrets WHERE path = ?
  • Memory: delete(store, path)
  • Lite: Similar to SQLite

API Endpoint

New endpoint needed:

  • POST /v1/secrets/purge - Purge empty secrets
  • Request body: { "force": bool, "dryRun": bool, "olderThan": duration }
  • Response: { "purged": int, "paths": []string }

Alternatively, could be implemented as:

  • DELETE /v1/secrets/{path}?destroy=true - For single secret destruction
  • POST /v1/secrets/purge - For bulk purge operation

Authorization

Purge should require super permission or a new purge permission on the system path.

Files to Create/Modify

  • app/pilot/internal/cmd/secret/purge.go - New CLI command
  • app/nexus/internal/route/secret/purge.go - New API endpoint
  • app/nexus/internal/state/backend/sqlite/persist/secret.go - Add Destroy() method
  • app/nexus/internal/state/backend/memory/secret.go - Add Destroy() method
  • app/nexus/internal/state/backend/lite/secret.go - Add Destroy() method
  • spike-sdk-go/api/secret.go - Add Purge() method
  • docs-src/content/usage/commands/secret.md - Document new command

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions