Initial Commit
This commit is contained in:
55
openspec/archive/2026-05-26-api-secrets-env/proposal.md
Normal file
55
openspec/archive/2026-05-26-api-secrets-env/proposal.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# `@suaveplan/api-secrets-env` — Environment-variable secrets adapter
|
||||
|
||||
**Package**: `@suaveplan/api-secrets-env`
|
||||
**Status**: PROPOSED
|
||||
**Type**: new-package
|
||||
**Stage**: 4 (Base adapters) — see umbrella `openspec/changes/api-plugin-foundation/`
|
||||
|
||||
## Why
|
||||
|
||||
The simplest secrets source: `process.env` (or `Bun.env`). Suitable for local development, single-host deployments, container orchestrators that inject secrets as env vars, and anywhere the operator already has tooling around env-var injection.
|
||||
|
||||
Per design doc, plugins declare their secrets in `plugin.json` under `manifest.secrets[]` (each entry has `name`, `required: boolean`, `description`). The installer's fail-fast contract (§4) is: any required secret missing at install or start time → refuse to install / refuse to start. `api-secrets-env` implements that contract by reading from env at construction and at `validateAgainstManifest(manifest)` time.
|
||||
|
||||
Stage 4 invariant: ships direct AND worker-proxy surfaces; both pass `runSecretsConformance` (§5.2a, §13.4).
|
||||
|
||||
## What changes
|
||||
|
||||
Net-new package depending on `@suaveplan/api-secrets` (contract), `@suaveplan/api-types`, `@suaveplan/api-worker-rpc`, `@suaveplan/error`, `@suaveplan/data-masking` (for redaction in logs), `zod`.
|
||||
|
||||
- ADDED: `createEnvSecrets(opts)` — direct-surface factory returning a `SecretsLike`. Reads via `Bun.env` first then falls back to `process.env`.
|
||||
- ADDED: `createEnvSecretsWorkerProxy(port, opts)` — proxy-surface factory; the worker NEVER touches host env directly — every `get()` round-trips through the proxy so secret materialisation stays in the main process.
|
||||
- ADDED: `EnvSecretsOptions` — Zod schema (`prefix?: string` (default ""), `caseSensitive?: boolean` (default true), `fallbackSource?: "process" | "bun" | "both"` (default `"both"`)).
|
||||
- ADDED: `validateAgainstManifest(manifest)` — given a plugin manifest's `secrets[]`, checks every `required: true` entry is present; missing → throws `SECRETS_ENV_REQUIRED_MISSING` listing every missing name.
|
||||
- ADDED: `SECRETS_ENV_*` error codes (`SECRETS_ENV_REQUIRED_MISSING`, `SECRETS_ENV_INVALID_OPTIONS`).
|
||||
- ADDED: Log redaction integration — secret VALUES never appear in error messages or telemetry; only NAMES.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Watched/reactive secrets — env vars are read once at construction; rotation requires plugin reload (delegated to host hot reload §8).
|
||||
- Encrypted secrets at rest — `api-secrets-vault` Stage 8.
|
||||
- Per-tenant secrets — env-based source is host-global by definition.
|
||||
|
||||
## Source mapping
|
||||
|
||||
Genesis-original. Source of design intent: `docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md`.
|
||||
|
||||
| Requirement | Design doc section |
|
||||
|---|---|
|
||||
| Manifest secrets installer fail-fast | §3 (manifest schema), §4 (lifecycle FSM) |
|
||||
| Worker-proxy variant required | §5.2a |
|
||||
| Conformance both surfaces | §13.4 |
|
||||
| Value redaction | §12.2 |
|
||||
|
||||
## Verification approach
|
||||
|
||||
- `src/factory/create-env-secrets.test.ts` — `get(name)` returns env value; missing → undefined; redaction never leaks values.
|
||||
- `src/factory/create-env-secrets.spec-conformance.test.ts` — `runSecretsConformance("env-direct", ...)`.
|
||||
- `src/proxy/create-env-secrets-worker-proxy.test.ts` — proxy unit tests; worker side has no env access.
|
||||
- `src/proxy/create-env-secrets-worker-proxy.spec-conformance.test.ts` — `runSecretsConformance("env-worker-proxy", ...)`.
|
||||
- `src/manifest-validation/validate-against-manifest.test.ts` — required missing → throw with named list; optional missing → silent.
|
||||
- `src/redaction/redaction.test.ts` — error messages and metrics never contain raw secret values.
|
||||
|
||||
## Migration impact
|
||||
|
||||
None — additive only.
|
||||
Reference in New Issue
Block a user