# restore-crypto-cli-and-allowlist — `keychain` CLI, `slsa` migration, import-allowlist gate **Packages:** `@suaveplan/crypto-cli` (new), `@suaveplan/slsa` (modified), `@suaveplan/crypto-core` (allowlist gate) **Status:** PROPOSED **Type:** new-package + refactor + conformance gate **Carved from:** `restore-crypto-keychain-packer` umbrella (2026-05-03) **Depends on:** slices 1, 2, and 3 must land first ## Why This terminal slice ships the three pieces that turn the crypto stack from "library that exists" into "library that consumers must use correctly": 1. **`@suaveplan/crypto-cli`** — a `keychain` binary with eight subcommands. Operators (and CI) drive root + server identity lifecycle through a stable command surface rather than ad-hoc scripts. Distinct exit codes per failure class let operators distinguish "wrong password" from "tampered vault" from "expired key" from "revoked key". 2. **`@suaveplan/slsa` migration** — `slsa` already calls `crypto.ed25519.sign(secretKey, …)` directly with raw bytes today. This slice migrates it to `Authority.sign(DOMAIN_SLSA_BUILDER_V1, …)`, with the builder identity issued as a `ServerIdentity` under a SLSA-builder root. The DSSE envelope wire format is unchanged — the proof is a round-trip equality test against pre-change fixtures. 3. **Import-allowlist conformance gate** — the most important piece. `scripts/openspec-conformance.ts` is extended to fail with `error` severity when any package outside the allowlist (`@suaveplan/crypto`, `@suaveplan/crypto-cli`) imports the cryptographic primitives from `crypto-core`, `crypto-cipher`, `crypto-curve`, or `crypto-hash`-as-MAC. Encoding helpers from `crypto-utils` and pure-hash uses from `crypto-hash` remain open. The allowlist is committed as `scripts/conformance/crypto-core-allowlist.yml` so additions are reviewable. Without the gate, future packages will drift back into direct primitive use exactly as `slsa` did. The gate is the single most important guarantee in the umbrella proposal. ## What changes ### New: `@suaveplan/crypto-cli` Located at `packages/crypto/crypto-cli/`. Built on `@suaveplan/cli` + `@suaveplan/readline` + `@suaveplan/crypto`. Bin entry: `keychain` → `dist/keychain.js`. Subcommands (eight): 1. `keychain root init` — generate root identity, write encrypted vault, emit public bundle 2. `keychain server init` — generate server identity under a root, emit signed public bundle, append audit log 3. `keychain server roll` — version-bump rotation; `--idempotency-key` deduped via local file ledger; appends CRL + audit 4. `keychain server revoke` — `--idempotency-key` deduped; appends CRL + audit; no re-issue 5. `keychain inspect` — view a packed public keychain (verifies self-signature) 6. `keychain verify` — verify any signed envelope against a trust anchor + CRL 7. `keychain export-public` — strip secrets, output portable public bundle 8. `keychain restore` — re-derive a vault from BIP39 mnemonic + version Cross-cutting: - TTY-only password input via `cli`'s `password` prompt; `--password` flag rejected with a security pointer - Stdin/stdout streamable; `--output json|binary|text` - Distinct exit codes: `0` success, `2` usage error, `10` bad password, `11` tampered vault, `12` expired key, `13` revoked key, `14` missing trust anchor, `15` audit-log mismatch - OTel spans + structured logger output for every command - Co-located `.md` per command file (≥ 200 words, basic + advanced examples) ### Modified: `@suaveplan/slsa` - Replace direct `crypto.ed25519.sign(secretKey, …)` calls with `Authority.sign(DOMAIN_SLSA_BUILDER_V1, …)` - Builder identity constructed from a `ServerIdentity` issued under a SLSA-builder root - Provenance test fixtures regenerated with new construction path; DSSE envelope output unchanged (asserted by round-trip equality test) - `package.json`: add `@suaveplan/crypto` workspace dep; remove direct `@suaveplan/crypto-core` signing import (retain `@suaveplan/crypto-hash` and `@suaveplan/crypto-utils` for hashing + encoding) - New test `tests/no-direct-crypto-core.test.ts` pins import discipline ### New: import-allowlist conformance gate - `scripts/conformance/crypto-core-allowlist.yml` — committed allowlist (`@suaveplan/crypto`, `@suaveplan/crypto-cli`) - `scripts/openspec-conformance.ts` — extended to scan every workspace package's `src/` for imports of `@suaveplan/crypto-core`, `@suaveplan/crypto-cipher`, `@suaveplan/crypto-curve`, or `@suaveplan/crypto-hash` MAC subpaths; fails with `error` severity for any non-allowlisted package - `scripts/conformance/crypto-core-allowlist.test.ts` — exercises positive (allowed) and negative (forbidden) cases against fixture packages ## Out of scope - HSM / threshold backends for `Authority` — separate `crypto-authority-yubikey`, `crypto-authority-tpm` changes - Network-fetched CRL distribution (`--fetch-crl` over HTTP/OCSP) - Trust-anchor distribution mechanism beyond two documented patterns (compiled-in pinned constant; env-var path to a trusted public bundle) - SLSA Sigstore Rekor integration migration to share the `AuditLog` (flagged in umbrella as a follow-up) ## Source mapping | Requirement | Source | Notes | |---|---|---| | `keychain` binary surface (8 commands) | umbrella `### Requirement: \`keychain\` binary surface` (crypto-cli/spec.md) | Verbatim | | TTY-only password input | umbrella crypto-cli/spec.md | Verbatim | | Distinct exit codes per failure class | umbrella crypto-cli/spec.md | Verbatim | | `--idempotency-key` on state-changing commands | umbrella crypto-cli/spec.md | Verbatim | | Per-command behaviour table | umbrella crypto-cli/spec.md | Verbatim | | `slsa` builder identity via `Authority` | umbrella slsa/spec.md | Verbatim | | Import-allowlist gate | umbrella crypto-core/spec.md | Verbatim | ## Verification approach - 100/100/100/100 coverage on every new command file in `crypto-cli` - Pre-change DSSE envelope fixtures committed; post-migration `slsa` round-trip equals byte-for-byte - Allowlist gate: positive fixtures (`crypto`, `crypto-cli` import primitives → green) and negative fixtures (test fixture package importing primitives → red) exercised in `tests/` - TTY mock harness driven via `@suaveplan/cli`'s `InputReader` interface (no real TTY needed) ## Migration impact - Every package in genesis whose `src/` reaches into `crypto-core`, `crypto-cipher`, `crypto-curve`, or `crypto-hash`-as-MAC for cryptographic operations MUST migrate to `@suaveplan/crypto`'s `Authority`/`Packer`/`Vault` API or be added to the allowlist (with reviewer approval). - After this slice, the gate enforces the discipline mechanically. The 5 packages currently importing `@suaveplan/crypto` for primitives (`crypto-sodium`, `crypto-browser`, `slsa`, `bitpacker-crypto`, `drive-plugin-chunks`, `packer`) are reviewed in this slice and either migrated or allowlisted with rationale.