# Add @suaveplan/server-keys — full-parity port of the 18-bin CLI **Package**: `@suaveplan/server-keys` **Status**: PROPOSED **Type**: migration (full parity with main) + enterprise stack additions - **Spec delta**: ./specs/server-keys/spec.md - **Target path**: `packages/security/server-keys/` ## Why Operator-facing CLI bundle for the Suaveplan server-key lifecycle: root + server keychain generation (with hierarchical `ChainedKeySigner` chains via `@suaveplan/crypto-keys`), encrypted vault persistence, key rotation, vault/key viewing, signed file packet preparation/serving/validation, and a license-key issuance bin (uses the just-shipped `@suaveplan/license`). Upstream at `../suaveplan/packages/server/server-keys/` ships 18 bin entry points + 3 command modules + a shared prompt utility (3,122 LOC total). This migration ports all 18 bins verbatim at the CLI-surface level so operator scripts that invoke `create-root-keys`, `roll-server-keys-chain`, `prepare-file`, etc. continue to work byte-compatibly. Genesis enterprise stack layered on top: `SuaveplanError`-typed errors with a `SERVER_KEYS.*` code registry, Zod boundary validation for CLI options, OpenTelemetry spans on the long-running operations (file prep/serve/validate, keychain ops), sibling `.md` docs ≥200 words per implementation file, fast-check property tests where pure-data functions exist (packet manifests, key-chain encode/decode), and 100/100/100/100 coverage. Upstream uses `@suaveplan/keys` (the old umbrella package); genesis-side calls are re-pointed to `@suaveplan/crypto` + `@suaveplan/crypto-keys` (the post-split surface) without changing the wire formats. ## What changes Net-new package at `0.1.0`, ships under `packages/security/server-keys/`. ADDED: ### 18 bin entry points (verbatim CLI surface) - **Key + chain bins** (`@suaveplan/crypto-keys` chain signer): `create-root-keys`, `create-root-keys-chain`, `create-server-keys`, `create-server-keys-chain`, `roll-server-keys`, `roll-server-keys-chain`, `verify-key-chain` - **Viewer bins**: `view-keys`, `view-vault`, `view-public-key-file`, `view-chain-public` - **File transport bins** (`@suaveplan/packer` + `@suaveplan/storage`): `prepare-file`, `serve-file`, `validate-file`, `get-file-stats`, `validate-packet` - **License bin** (`@suaveplan/license`): `license` — issues / validates / inspects software-license keys - **Top-level dispatcher**: `suaveplan` (single `commander` entry routing to all 17 sub-commands) ### Internal command modules (the library surface the bins call into) - `commands/keys/keys.ts` — `createRootKeysCommand`, `createServerKeysCommand`, `rollServerKeysCommand`, `createRootKeysChainCommand`, `createServerKeysChainCommand`, `rollServerKeysChainCommand`, `verifyKeyChainCommand`, viewers - `commands/files/files.ts` — `prepareFileCommand`, `validateFileCommand`, `getFileStatsCommand`, `validatePacketCommand` - `commands/files/serve-file.ts` — `serveFileCommand` - `commands/license/license.ts` — `licenseCommand` (wraps `@suaveplan/license` `LicenseManager`) - `prompt/prompt.ts` — `promptForPassword`, `promptForNewPassword` (`@inquirer/prompts`) - `run-function.ts` — top-level error-handling wrapper for `.action(...)` callbacks ### Enterprise stack (additive over upstream) - `error-codes.ts` — `SERVER_KEYS_*` code registry via `defineCodes("SERVER_KEYS", [...])`, `ServerKeysError extends SuaveplanError`. Codes cover vault decrypt failures, password mismatch, missing root vault, chain verification failure, packet integrity failure, file IO failures, unknown command, plus license-bin pass-throughs. - Zod boundary schemas for every CLI option bag. - OpenTelemetry: counter `server_keys.command_total{command}`, histogram `server_keys.command_duration_ms{command}`, span per command. - `LoggerLike` from `@suaveplan/types` injectable through every command (defaults to console). - `AbortSignal` plumbing for long-running file ops. ### Bin registration in `package.json` The full 18-bin `bin` map matches upstream verbatim so `bun link` / `npm install -g` exposes every operator command. Names: ```text suaveplan, license, create-root-keys, create-server-keys, roll-server-keys, create-root-keys-chain, create-server-keys-chain, roll-server-keys-chain, verify-key-chain, view-keys, view-vault, view-public-key-file, view-chain-public, prepare-file, serve-file, validate-file, get-file-stats, validate-packet ``` ### Subpath exports Library subpaths so downstream packages can call the command functions directly (e.g. test harnesses, integration tests): `./commands/keys/keys`, `./commands/files/files`, `./commands/files/serve-file`, `./commands/license/license`, `./prompt/prompt`, `./error-codes`, `./run-function`. ## Out of scope - **Daemon / always-on serve-file mode.** Upstream's `serve-file` is one-shot reconstruction; genesis preserves that. A long-running HTTP serve mode belongs in a separate `@suaveplan/server-keys-http` follow-up. - **Re-implementing the upstream wire formats.** The keychain encoding, packet header, and license payload formats all come from their respective packages (`@suaveplan/crypto-keys`, `@suaveplan/packer`, `@suaveplan/license`). server-keys is the CLI wrapper, not the format owner. - **Cross-platform binary distribution.** Bins run under Bun/Node; we do not ship pkg/nexe-style standalone binaries. - **Telemetry exporter wiring.** OTel instruments are registered against `@opentelemetry/api`; concrete exporter (OTLP/Prometheus/Jaeger) is the operator's choice. ## Source mapping | Capability | Upstream source | Notes | |---|---|---| | 18 bin entry points + commander routing | `../suaveplan/packages/server/server-keys/src/bin/*.ts` + `bin/index.ts` | verbatim CLI surface | | Key + chain commands (628 LOC) | `src/commands/keys/keys.ts` | re-pointed from `@suaveplan/keys` → `@suaveplan/crypto-keys` `ChainedKeySigner` | | File transport commands (311 LOC) | `src/commands/files/files.ts` + `serve-file.ts` | uses `@suaveplan/packer` + `@suaveplan/storage`/`storage-file` | | Password prompts | `src/prompt/prompt.ts` | `@inquirer/prompts` | | License bin | `src/bin/license.ts` + `src/commands/license/license.types.ts` | wraps `@suaveplan/license` `LicenseManager` | | `runFunction` error wrapper | `src/runFunction.ts` | verbatim | | Enterprise audit (Zod, OTel, structured errors, 100% coverage, sibling .md) | `../suaveplan/enterprise/server-keys.md` | all addressed | | `ServerKeysError` + `SERVER_KEYS_*` code registry | genesis-original | genesis policy — upstream throws plain `Error` | ## Impact ### Affected dependents None today — net-new on genesis. First downstream will be operator scripts (out-of-repo) and CI workflows that issue/rotate server keys. The `license` bin transitively pulls in `@suaveplan/license` (shipped today).