88 lines
6.8 KiB
Markdown
88 lines
6.8 KiB
Markdown
# 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.
|