6.8 KiB
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":
@suaveplan/crypto-cli— akeychainbinary 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".@suaveplan/slsamigration —slsaalready callscrypto.ed25519.sign(secretKey, …)directly with raw bytes today. This slice migrates it toAuthority.sign(DOMAIN_SLSA_BUILDER_V1, …), with the builder identity issued as aServerIdentityunder a SLSA-builder root. The DSSE envelope wire format is unchanged — the proof is a round-trip equality test against pre-change fixtures.- Import-allowlist conformance gate — the most important piece.
scripts/openspec-conformance.tsis extended to fail witherrorseverity when any package outside the allowlist (@suaveplan/crypto,@suaveplan/crypto-cli) imports the cryptographic primitives fromcrypto-core,crypto-cipher,crypto-curve, orcrypto-hash-as-MAC. Encoding helpers fromcrypto-utilsand pure-hash uses fromcrypto-hashremain open. The allowlist is committed asscripts/conformance/crypto-core-allowlist.ymlso 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):
keychain root init— generate root identity, write encrypted vault, emit public bundlekeychain server init— generate server identity under a root, emit signed public bundle, append audit logkeychain server roll— version-bump rotation;--idempotency-keydeduped via local file ledger; appends CRL + auditkeychain server revoke—--idempotency-keydeduped; appends CRL + audit; no re-issuekeychain inspect— view a packed public keychain (verifies self-signature)keychain verify— verify any signed envelope against a trust anchor + CRLkeychain export-public— strip secrets, output portable public bundlekeychain restore— re-derive a vault from BIP39 mnemonic + version
Cross-cutting:
- TTY-only password input via
cli'spasswordprompt;--passwordflag rejected with a security pointer - Stdin/stdout streamable;
--output json|binary|text - Distinct exit codes:
0success,2usage error,10bad password,11tampered vault,12expired key,13revoked key,14missing trust anchor,15audit-log mismatch - OTel spans + structured logger output for every command
- Co-located
.mdper command file (≥ 200 words, basic + advanced examples)
Modified: @suaveplan/slsa
- Replace direct
crypto.ed25519.sign(secretKey, …)calls withAuthority.sign(DOMAIN_SLSA_BUILDER_V1, …) - Builder identity constructed from a
ServerIdentityissued 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/cryptoworkspace dep; remove direct@suaveplan/crypto-coresigning import (retain@suaveplan/crypto-hashand@suaveplan/crypto-utilsfor hashing + encoding)- New test
tests/no-direct-crypto-core.test.tspins 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'ssrc/for imports of@suaveplan/crypto-core,@suaveplan/crypto-cipher,@suaveplan/crypto-curve, or@suaveplan/crypto-hashMAC subpaths; fails witherrorseverity for any non-allowlisted packagescripts/conformance/crypto-core-allowlist.test.ts— exercises positive (allowed) and negative (forbidden) cases against fixture packages
Out of scope
- HSM / threshold backends for
Authority— separatecrypto-authority-yubikey,crypto-authority-tpmchanges - Network-fetched CRL distribution (
--fetch-crlover 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
slsaround-trip equals byte-for-byte - Allowlist gate: positive fixtures (
crypto,crypto-cliimport primitives → green) and negative fixtures (test fixture package importing primitives → red) exercised intests/ - TTY mock harness driven via
@suaveplan/cli'sInputReaderinterface (no real TTY needed)
Migration impact
- Every package in genesis whose
src/reaches intocrypto-core,crypto-cipher,crypto-curve, orcrypto-hash-as-MAC for cryptographic operations MUST migrate to@suaveplan/crypto'sAuthority/Packer/VaultAPI or be added to the allowlist (with reviewer approval). - After this slice, the gate enforces the discipline mechanically. The 5 packages currently importing
@suaveplan/cryptofor primitives (crypto-sodium,crypto-browser,slsa,bitpacker-crypto,drive-plugin-chunks,packer) are reviewed in this slice and either migrated or allowlisted with rationale.