Skip to content

Implement spike secret purge #257

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions