5.1 KiB
Capability Spec Delta: crypto (crypto-trust-anchor-bootstrap)
Package: @suaveplan/crypto
Status: PROPOSED
Every requirement below carries a
**Verified by:**line at authoring time, pointing to a real test inpackages/crypto/crypto/src/trust-anchors/.
ADDED Requirements
Requirement: Trust-anchor bootstrap
@suaveplan/crypto SHALL ship a trust-anchor loader at src/trust-anchors/ that reads a self-verifying root public bundle from a caller-supplied filesystem reader and returns both the raw bytes (for direct use with verifyChain) and the parsed PublicBundle (for diagnostics). The loader SHALL self-verify the bundle in root-mode (verifyPublicBundle(bytes, null)) on every load — bytes that do not self-verify SHALL be rejected with CRYPTO.TRUST_ANCHOR.SELF_VERIFY_FAILED.
The package SHALL expose:
loadTrustAnchor(reader, path): Promise<TrustAnchor>— explicit-path entry.loadTrustAnchorFromEnv(reader, options): Promise<TrustAnchor>— env-driven entry.options.getenvis required (the universal package never readsprocess.envdirectly); production wires(name) => process.env[name], tests inject deterministic stubs.options.envVardefaults toSUAVEPLAN_TRUST_ANCHOR_PATH.DEFAULT_TRUST_ANCHOR_ENV_VAR— the canonical env-var name as aconst.- Types
TrustAnchor,TrustAnchorReader,TrustAnchorEnvGetter,LoadTrustAnchorFromEnvOptions.
The universal-tier package MUST NOT import node:fs or read process.env at the module-import level; all platform access is caller-injected via the TrustAnchorReader interface and the optional getenv callback. Production wires (path) => fs.readFile(path); tests inject deterministic stubs.
Scenario: round-trip self-verify
- WHEN a self-signed root public bundle is supplied via the reader and
loadTrustAnchor(reader, path)is called - THEN the call returns
{ bytes, bundle }wherebytesis byte-identical to the input andbundlehas a 32-bytesignslot public key
Scenario: env-var default name
- WHEN
loadTrustAnchorFromEnv(reader, { getenv })is called withoutoptions.envVar - THEN
getenvis invoked with"SUAVEPLAN_TRUST_ANCHOR_PATH"and the returned path is read
Scenario: env-var name override
- WHEN
loadTrustAnchorFromEnv(reader, { envVar: "VAULT_ANCHOR", getenv })is called - THEN
getenvis invoked with"VAULT_ANCHOR"and the returned path is read
Scenario: missing env-var rejected
- WHEN
loadTrustAnchorFromEnv(reader, { envVar, getenv: () => undefined })is called - THEN the call throws
CryptoErrorwith codeCRYPTO.TRUST_ANCHOR.PATH_MISSINGandcontext.envVarreflects the requested name
Scenario: empty env-var string rejected
- WHEN
loadTrustAnchorFromEnv(reader, { envVar, getenv: () => "" })is called - THEN the call throws
CryptoErrorwith codeCRYPTO.TRUST_ANCHOR.PATH_MISSING
Scenario: reader failure surfaces structured error
- WHEN the reader's
read(path)rejects (e.g. ENOENT) - THEN the call throws
CryptoErrorwith codeCRYPTO.TRUST_ANCHOR.READ_FAILED, with the reader's error attached viacauseandcontext.pathequal to the requested path
Scenario: tampered bytes rejected
- WHEN the loader receives bytes that parse but fail
verifyPublicBundle(bytes, null) - THEN the call throws
CryptoErrorwith codeCRYPTO.TRUST_ANCHOR.SELF_VERIFY_FAILEDandcontext.byteLengthreflects the actual length
Scenario: garbage bytes rejected
- WHEN the loader receives bytes that fail to parse as a public bundle
- THEN the call throws
CryptoErrorwith codeCRYPTO.TRUST_ANCHOR.SELF_VERIFY_FAILED
Verified by: packages/crypto/crypto/src/trust-anchors/trust-anchor.test.ts::"loads, self-verifies, and returns byte-identical bytes" AND packages/crypto/crypto/src/trust-anchors/trust-anchor.test.ts::"the returned bundle parses identically to a fresh verify on the bytes" AND packages/crypto/crypto/src/trust-anchors/trust-anchor.test.ts::"uses the default env var name SUAVEPLAN_TRUST_ANCHOR_PATH" AND packages/crypto/crypto/src/trust-anchors/trust-anchor.test.ts::"honors a caller-supplied envVar override" AND packages/crypto/crypto/src/trust-anchors/trust-anchor.test.ts::"getenv is invoked exactly once with the resolved env-var name" AND packages/crypto/crypto/src/trust-anchors/trust-anchor.spec-conformance.test.ts::"throws TRUST_ANCHOR.PATH_MISSING when env var is unset" AND packages/crypto/crypto/src/trust-anchors/trust-anchor.spec-conformance.test.ts::"throws TRUST_ANCHOR.PATH_MISSING when env var is empty string" AND packages/crypto/crypto/src/trust-anchors/trust-anchor.spec-conformance.test.ts::"throws TRUST_ANCHOR.READ_FAILED when reader rejects" AND packages/crypto/crypto/src/trust-anchors/trust-anchor.spec-conformance.test.ts::"throws TRUST_ANCHOR.SELF_VERIFY_FAILED on tampered bundle bytes" AND packages/crypto/crypto/src/trust-anchors/trust-anchor.spec-conformance.test.ts::"throws TRUST_ANCHOR.SELF_VERIFY_FAILED on garbage bytes"