70 lines
4.2 KiB
Markdown
70 lines
4.2 KiB
Markdown
# `@suaveplan/api-secrets` — abstract Secrets contract
|
|
|
|
**Package**: `@suaveplan/api-secrets`
|
|
**Status**: PROPOSED
|
|
**Type**: new-package
|
|
**Stage**: 1 (Contracts) — see umbrella `openspec/changes/api-plugin-foundation/`
|
|
|
|
## Why
|
|
|
|
Every plugin needs to read secrets — Stripe keys, JWT signing keys, OAuth client secrets, database passwords. Different deployments want different sources: `process.env` / `Bun.env` (dev + simple prod), `Bun.secrets` (OS keystore), `@suaveplan/vault` (the genesis vault), HashiCorp Vault, AWS Secrets Manager. This package owns the abstract contract: `SecretsLike` (read-only, typed against the manifest's `secrets[]` declarations) plus `SecretDescriptor` (the manifest-side declaration). Concrete sources plug behind it (`api-secrets-env`, `api-secrets-bun`, `api-secrets-vault`).
|
|
|
|
Per design §5.2: "every adapter exports `defineCapability({ id, version, scope, provider, disposer })`." Per §5.1: `ctx.secrets: SecretsLike; // typed against manifest.secrets[]`.
|
|
|
|
## What changes
|
|
|
|
Net-new package. Contract + Zod schema for `SecretDescriptor` + conformance harness.
|
|
|
|
- ADDED: `./secrets-like` — abstract `SecretsLike`: `get(name: string): Promise<string>` (returns the secret value); `has(name: string): Promise<boolean>`; `dispose(): Promise<void>`. The type MUST be generic over a `Names extends string` so `ctx.secrets.get(name)` autocompletes against the manifest's declared secret names.
|
|
- ADDED: `./descriptor` — `SecretDescriptor` shape: `{ name: string, required: boolean, description?: string, format?: "string" | "base64" | "json" }`. Zod schema for parsing manifest entries.
|
|
- ADDED: `./redaction` — `redactSecret(value: string): string` returning `"<redacted>"` for log/audit use. Helper, not enforced — adapters / loggers may use it.
|
|
- ADDED: `./capability-id` — adds `"secrets"` (and ensures `"secrets.bun"` is reserved for the Stage-8 adapter) to `CapabilityId`.
|
|
- ADDED: `./error-codes` — frozen `SECRETS_CODES`: `SECRET_NOT_FOUND`, `SECRET_REQUIRED_MISSING_AT_START`, `SECRET_INVALID_FORMAT`, `SOURCE_UNAVAILABLE`.
|
|
- ADDED: `./testing` — `runSecretsConformance(factory)` reusable harness.
|
|
|
|
## CapabilityId additions
|
|
|
|
This package contributes `"secrets"` to the `CapabilityId` union. The Bun-specific `"secrets.bun"` capability id is reserved here (declared in the union) for the Stage-8 `api-secrets-bun` adapter, so plugins can declare `requiredCapabilities: ["secrets.bun"]` at type-check time before the adapter ships.
|
|
|
|
## Out of scope
|
|
|
|
- Concrete sources (`api-secrets-env`, `api-secrets-bun`, `api-secrets-vault`) — Stages 4 and 8.
|
|
- Secret rotation — out of scope for v1 (separate change).
|
|
- Encryption-at-rest — source-specific.
|
|
|
|
## Source mapping
|
|
|
|
Genesis-original. Source of design intent: `docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md`.
|
|
|
|
| Requirement | Design doc section |
|
|
|---|---|
|
|
| `ctx.secrets: SecretsLike` typed against manifest | §5.1, §5.2 |
|
|
| Required-secret enforcement at start | §3 manifest example (`"required": true`) + §4 install hook order |
|
|
| Per-secret format declaration | §3 manifest example |
|
|
| `"secrets.bun"` capability | §3 manifest example (`"optionalCapabilities": ["events.bounded-queue", "secrets.bun"]`) |
|
|
|
|
### Requirements with no source line
|
|
|
|
| Requirement | Justification |
|
|
|---|---|
|
|
| `redactSecret` helper | Logging plugins / OTel exporters need a canonical redaction marker; pinning the string `"<redacted>"` here means every downstream tool agrees. |
|
|
| `runSecretsConformance` harness | Stage-5 deliverable (§13.4). |
|
|
|
|
## Verification approach
|
|
|
|
- `src/secrets-like/secrets-like.spec-conformance.test.ts` — `get`/`has`/`dispose` shape; `Names extends string` generic narrows return type.
|
|
- `src/descriptor/descriptor.test.ts` — Zod accept/reject suite over `SecretDescriptor`.
|
|
- `src/redaction/redaction.test.ts` — input → `"<redacted>"`; empty string handled.
|
|
- `src/capability-id/capability-id.spec-conformance.test.ts` — `"secrets"` AND `"secrets.bun"` in `CapabilityId`.
|
|
- `tests/dep-graph.test.ts` — deps: `@suaveplan/api-types`, `@suaveplan/error`, `@suaveplan/types`, `zod`.
|
|
|
|
## Migration impact
|
|
|
|
None — additive only.
|
|
|
|
## Impact
|
|
|
|
### Affected dependents
|
|
|
|
- (none) — [x] no action needed (reason: net-new; concrete sources land Stage 4/8)
|