Skip to content

feat: implement Secret Rotation Service (Issue #119)#136

Open
KarenZita01 wants to merge 1 commit into
VeriNode-Labs:mainfrom
KarenZita01:fix/soroban-balance-scaling
Open

feat: implement Secret Rotation Service (Issue #119)#136
KarenZita01 wants to merge 1 commit into
VeriNode-Labs:mainfrom
KarenZita01:fix/soroban-balance-scaling

Conversation

@KarenZita01

@KarenZita01 KarenZita01 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Closes #119

Overview

This PR implements a Secret Rotation Service for Database Credentials and API Keys as a first-class module in the VeriNode frontend. The service provides a secure, auditable, and observable foundation for rotating sensitive credentials at the client layer, with zero-downtime guarantees and comprehensive monitoring hooks.

The implementation is framework-agnostic (pure TypeScript) so it can be consumed by Next.js routes, API handlers, and client-side state managers without coupling to React or Next.js internals.


Problem Statement

VeriNode interacts with database-backed credentials and external API keys. Without rotation:

  • Long-lived credentials increase blast radius if leaked.
  • Operational overhead grows when secrets must be rotated manually.
  • There is no structured visibility into rotation health, latency, or failures.

This service addresses those gaps by introducing a policy-driven rotation engine with dual-version overlap, expiry monitoring, and event-driven observability.


Architecture

Core Abstractions

Abstraction Responsibility
SecretRotationService Orchestrates registration, rotation, expiry evaluation, revocation, and metric aggregation.
SecretStoreBackend Pluggable persistence layer. Defaults to an in-memory store; can be swapped for IndexedDB, server-side storage, etc.
SecretGenerator Pluggable credential generator. Defaults to UUID-based values.
RotationPolicy Declarative rotation cadence (rotationIntervalMs), maximum retained versions (maxVersions), and dual-write overlap (overlapMs).
RotationEvent Typed lifecycle events emitted on rotation start/complete/fail, expiry warning/expiry, and revocation.

Rotation Lifecycle

  1. Registration — A secret is registered with a kind (database-credential, api-key, token, encryption-key), an optional initial value, and a policy. The service creates the first version and schedules the next rotation.
  2. Rotation — On demand or on schedule, a new version is generated and appended. Old versions are retained for the configured overlap window (overlapMs) to allow zero-downtime cutover. Versions older than the overlap are pruned, respecting the maxVersions cap.
  3. Expiry Evaluation — A periodic evaluateExpiry() pass emits secret:expiring when the active version enters the overlap window, and secret:expired when no valid version remains.
  4. Revocation — Immediately invalidates all versions and blocks future validation.

Zero-Downtime Overlap

During rotation, both the previous and next credential are considered valid for overlapMs. Consumers can validate against either version, enabling live cutover without downtime.

T0: v0 expiresAt = T0 + interval
T1 (rotation): v1 expiresAt = T1 + interval
      v0 and v1 are both valid until max(v0.expiresAt, T1 - overlapMs)

Observability

  • Events — rotation:started, rotation:completed, rotation:failed, secret:expiring, secret:expired, secret:revoked are emitted to registered listeners.
  • Metrics — RotationMetrics exposes totalRotations, failedRotations, activeSecrets, expiredSecrets, and lastRotationLatencyMs.

Files Changed

File Description
src/types/secrets.ts Type definitions: SecretKind, SecretRecord, SecretVersion, RotationPolicy, RotationEvent, RotationMetrics.
src/services/secretRotation.ts Core service implementation with pluggable backend/generator interfaces, rotation scheduling, overlap pruning, expiry evaluation, revocation, metrics, and event emission.
tests/secretRotation.test.ts 13 Node-based unit tests covering registration, idempotency, zero-downtime overlap, pruning, max-versions cap, event emission, expiry/expired states, revocation, unregistered-key errors, metrics, custom backends, and default policy.
src/__tests__/secretRotation.benchmark.ts Browser/Node benchmark matching the repository's existing benchmark pattern. Validates P99 latency < 100ms.
e2e/wallet-tests/secretRotation.spec.ts Playwright E2E spec executing in the wallet-ci project, exercising the service in a real browser context.

Performance

Benchmark results on Node 24:

Rounds: 2000
P50: 0.0236ms
P95: 0.0835ms
P99: 0.4480ms
Max: 2.5018ms
P99 < 100ms target: PASS (0.4480ms)
Throughput: ~24,137 ops/sec

The service is synchronous for in-memory operations, making it suitable for hot paths.


Testing Strategy

Unit Tests (tests/secretRotation.test.ts)

  • Registration & Idempotency — Duplicate registration returns the existing record without creating a new version.
  • Zero-Downtime Rotation — After rotation, both old and new versions validate during the overlap window.
  • Overlap Expiry — After the overlap window passes, only the newest version validates.
  • Max Versions Cap — maxVersions is strictly enforced after pruning.
  • Event Emission — Lifecycle and monitoring events are emitted to listeners.
  • Expiry Monitoring — secret:expiring and secret:expired events are emitted at the correct thresholds.
  • Revocation — Revoked secrets return null and fail validation.
  • Error Handling — Rotating an unregistered secret throws a descriptive error.
  • Metrics — Rotation counts, active/expired counts, and latency are tracked correctly.
  • Custom Backend — The service persists correctly through a user-supplied SecretStoreBackend.
  • Default Policy — Sensible defaults are defined and exported.

Benchmark (src/__tests__/secretRotation.benchmark.ts)

  • 2,000 rotate + get cycles across 50 secrets.
  • Validates P99 < 100ms target.
  • Reports throughput.

Playwright E2E (e2e/wallet-tests/secretRotation.spec.ts)

  • Runs in the existing wallet-ci project alongside wallet tests.
  • Validates the same core behaviors in a browser context to catch bundling/runtime issues.

Security Considerations

  • No hardcoded secrets — All values are generated or supplied by the caller.
  • Minimal trust surface — The service does not transmit secrets; it manages versioning and validation. Actual storage/retrieval is delegated to the SecretStoreBackend.
  • Revocation is immediate — Revoked secrets have their versions cleared and cannot be validated.
  • Overlap controls exposure window — The overlapMs policy limits the time both old and new credentials are valid.

Backward Compatibility

This is a purely additive change. No existing modules, components, or tests are modified.


Checklist

  • npm run lint passes (0 errors, 1 ignored-file warning)
  • npm run build passes
  • Unit tests pass (13/13)
  • Benchmark passes (P99 0.45ms < 100ms)
  • Playwright E2E spec added for CI validation
  • Types exported for downstream consumption

- Add SecretRotationService with rotation scheduling, zero-downtime overlap, expiry monitoring, and revocation
- Add types for SecretRecord, RotationPolicy, RotationEvent, etc.
- Add Node unit tests (13 tests) and browser benchmark (P99 0.45ms < 100ms)
- Add Playwright E2E spec for CI validation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Secret Rotation Service for Database Credentials and API Keys

1 participant