11 KiB
11 KiB
Tasks — @suaveplan/tpm-struct (TPM 2.0 attestation-structure parser)
Every checkbox below MUST reflect work actually done in this change. Do not retroactively tick boxes. Do not tick a box for a test that doesn't exist or doesn't pin the requirement it claims to verify.
1. Spec authoring
- 1.1 Read TCG TPM 2.0 Library Part 2 — Structures r1.59 end-to-end (focus §10.1, §10.5, §10.10, §10.11, §10.12, §11.1, §11.2.5, §8.3, §12.2)
- 1.2 Read TCG TPM 2.0 Library Part 1 — Architecture §16 (Names)
- 1.3 Read W3C WebAuthn Level 3 §8.3 TPM Attestation Statement Format end-to-end
- 1.4 Read TCG Credential Profile EK 2.0 v2.3 (informational — AIK / EK context)
- 1.5 Read
openspec/AGENTS.md§0, §0a, §0b, §2b, §6a, §7, §13, §14, §14a - 1.6 Confirm
proposal.mdcovers every public-surface item, every subpath, and every dependency - 1.7 Confirm
specs/tpm-struct/spec.mdcarries one requirement per logical capability with ≥2 scenarios each - 1.8 Confirm every requirement has a
**Verified by:**line naming concreteit(...)titles in concrete test file paths - 1.9 Source-mapping table cites every TCG / W3C section consumed
2. Package scaffold
- 2.1 Create
packages/security/tpm-struct/withsrc/{buffer,alg,public,attest,name,extra-data,schemas,errors,observability,diagnostic,__fixtures__,__integration__,__benchmarks__}/ - 2.2
package.json—@suaveplan/tpm-struct@0.0.0,type: module,sideEffects: false, deps@suaveplan/error workspace:^,@suaveplan/types workspace:^,@opentelemetry/api catalog:observability,tslib catalog:build,zod catalog:forms(no bare versions) - 2.3
package.jsonexportsmap declares.,./buffer,./alg,./public,./attest,./name,./extra-data,./schemas,./errors,./diagnostic(10 subpaths) — each mapped todist/<feature>/<feature>.js+.d.ts - 2.4
tsconfig.lib.jsonextends@suaveplan/typescript-config/library.json - 2.5
vite.config.tsmulti-entry build (one entry per subpath) +vitest.config.tscallingcreateTestConfig()from@suaveplan/testing/config - 2.6
README.mdwith package name, description,bun addinstall, quick-start example,## Modulestable linking every co-located.md
3. Implementation — buffer primitives
- 3.1
src/buffer/buffer.ts—TpmBufferReader(readUint8,readUint16Be,readUint32Be,readUint64Be: bigint,readBytes(n),readTpm2b(): Uint8Array,peek(n),remaining(),assertEnd()) - 3.2
src/buffer/buffer.ts—TpmBufferWriter(mirror writes +writeTpm2b(bytes)+toUint8Array()) - 3.3 Out-of-bounds read raises
TPM_STRUCT.TRUNCATEDwith cursor + requested-length incause - 3.4
src/buffer/buffer.types.ts—TpmReaderOptions,TpmWriterOptions,Tpm2bReadResult - 3.5 Sibling
src/buffer/buffer.md≥200 words with basic + advanced examples
4. Implementation — algorithm registry
- 4.1
src/alg/alg.ts—TPM_ALGfrozen 31-entry registry per TCG Part 2 §11.1 - 4.2
src/alg/alg.ts—TPM_ECC_CURVEfrozen 6-entry registry per TCG Part 2 §11.2.5 - 4.3
algIdToName(id)returns symbolic name; unknown raisesALG_UNSUPPORTED - 4.4
eccCurveToName(id)returns symbolic name; unknown raisesCURVE_UNSUPPORTED - 4.5
src/alg/alg.types.ts—TpmAlgId,TpmEccCurveliteral unions - 4.6 Sibling
src/alg/alg.md≥200 words
5. Implementation — TPMT_PUBLIC parser + serialiser
- 5.1
src/public/public.ts—parseTpmtPublic(bytes): TpmtPublicper TCG Part 2 §12.2 header (type, nameAlg, objectAttributes, authPolicy) - 5.2 RSA branch:
TPMS_RSA_PARMSper §12.2.3.5 +TPM2B_PUBLIC_KEY_RSAunique - 5.3 ECC branch:
TPMS_ECC_PARMSper §12.2.3.6 +TPMS_ECC_POINTunique with curveID lookup - 5.4 KEYEDHASH branch:
TPMS_KEYEDHASH_PARMSper §12.2.3.3 +TPM2B_DIGESTunique - 5.5 SYMCIPHER branch:
TPMS_SYMCIPHER_PARMSper §12.2.3.4 +TPM2B_DIGESTunique - 5.6
objectAttributesreserved bits non-zero raisesOBJECT_ATTRIBUTES_RESERVED_NONZERO - 5.7
src/public/serialize.ts—serializeTpmtPublic(pub): Uint8Arraybyte-identical round-trip - 5.8
src/public/public.types.ts—TpmtPublicdiscriminator + parameter / point / attribute types - 5.9 Sibling
.mdforpublic.tsandserialize.ts(≥200 words each)
6. Implementation — TPMS_ATTEST parser + serialiser
- 6.1
src/attest/attest.ts— magic validation:0xff544347mismatch raisesMAGIC_INVALID - 6.2
parseTpmsAttestreads type, qualifiedSigner (TPM2B_NAME), extraData (TPM2B_DATA), clockInfo (17 bytes), firmwareVersion (uint64 BE) - 6.3 Eight
TPMU_ATTESTbranches:TPM_ST_ATTEST_CERTIFY⇒TPMS_CERTIFY_INFO; the other seven per TCG Part 2 §10.11 - 6.4 Unknown
typeraisesATTEST_TYPE_UNSUPPORTED - 6.5
src/attest/serialize.ts—serializeTpmsAttest(att): Uint8Arraybyte-identical round-trip - 6.6
src/attest/attest.types.ts—TpmsAttestdiscriminator + everyTPMU_ATTESTmember type +ClockInfo - 6.7 Sibling
.mdforattest.tsandserialize.ts(≥200 words each)
7. Implementation — name digest
- 7.1
src/name/name.ts—computeTpmtPublicName(pub, hash): Uint8Arrayper TCG Part 1 §16 - 7.2 Output =
nameAlg (2 BE) || hash.digest(serializeTpmtPublic(pub)) - 7.3
nameAlg === TPM_ALG_NULLraisesNAME_ALG_NULL - 7.4
src/name/name.types.ts—HashLikeinterface - 7.5 Sibling
src/name/name.md≥200 words
8. Implementation — extra-data helper
- 8.1
src/extra-data/extra-data.ts—extraDataMatches(actual, expected, equal): boolean - 8.2 Length mismatch returns false without calling
equal - 8.3
src/extra-data/extra-data.types.ts—ConstantTimeEqualsignature - 8.4 Sibling
.md≥200 words
9. Implementation — Zod schemas
- 9.1
src/schemas/schemas.ts— every public type has a matching schema (TpmsAttestSchema,TpmtPublicSchema,TpmsRsaParmsSchema,TpmsEccParmsSchema,TpmsKeyedHashParmsSchema,TpmsSymCipherParmsSchema,TpmsCertifyInfoSchema,ClockInfoSchema,Tpm2bSchema,TpmAlgIdSchema,TpmEccCurveSchema,ObjectAttributesSchema) - 9.2 Every public parser validates its output through the matching schema before returning
- 9.3 Schema failure raises
MALFORMEDwith Zod issues oncause.issues - 9.4 Sibling
.md≥200 words
10. Implementation — error registry
- 10.1
src/errors/error-codes.ts—defineCodes("TPM_STRUCT", [...])10 codes:MAGIC_INVALID,TRUNCATED,ALG_UNSUPPORTED,CURVE_UNSUPPORTED,TYPE_MISMATCH,MALFORMED,NAME_ALG_NULL,ATTEST_TYPE_UNSUPPORTED,PARAMETERS_INVALID,OBJECT_ATTRIBUTES_RESERVED_NONZERO - 10.2
TpmStructError extends SuaveplanError<TpmStructErrorCode> - 10.3 Every code thrown by ≥1 production path (registry-coverage test pins this)
- 10.4 Sibling
.md≥200 words
11. Implementation — OTel surface
- 11.1
src/observability/metrics.ts— histogramstpm_struct.parse_tpms_attest_duration_ms{outcome},tpm_struct.parse_tpmt_public_duration_ms{type,outcome},tpm_struct.compute_name_duration_ms{name_alg} - 11.2 Counters
tpm_struct.parse_total{kind,outcome},tpm_struct.parse_errors_total{code},tpm_struct.alg_total{alg} - 11.3 Every attribute is a bounded enum from the registries (no free-form strings)
- 11.4 Hot paths emit under a real in-memory
MeterProvider(no mocks) - 11.5 Sibling
.md≥200 words
12. Implementation — diagnostic emitter
- 12.1
src/diagnostic/diagnostic.ts—toDiagnostic(value: TpmsAttest | TpmtPublic): string - 12.2 Symbolic
TPM_ALGandTPM_ECC_CURVEnames inlined - 12.3 Never invokes parser hot paths; never emits telemetry
- 12.4 Sibling
.md≥200 words
13. Fixtures + integration test
- 13.1
src/__fixtures__/webauthn-tpm-vector.ts— real-world WebAuthntpmattestation byte strings + expected parsed structures + expected name digest - 13.2
src/__integration__/webauthn-vector.test.ts—parseTpmsAttest(attestationData)+parseTpmtPublic(pubArea)+computeTpmtPublicNameround-trip matches expected digest - 13.3 Test uses a real SHA-256 implementation injected via
HashLike(no mocks)
14. Tests
- 14.1 Unit tests at each
src/<feature>/<feature>.test.tscovering every scenario in the spec delta - 14.2 Property tests at
src/public/property.test.tsandsrc/attest/property.test.ts(fast-check round-trip + single-bit-flip) - 14.3 Spec-conformance test at
src/index.test.tsresolves every subpath export - 14.4 Every
it(...)carries{ timeout: 5000 }(or 30000 for genuinely async) - 14.5 Every test imports runner primitives from
@suaveplan/testing/runner— zero directfrom "vitest"/from "bun:test"(peropenspec/AGENTS.md§7)
15. Documentation
- 15.1 Sibling
.mdfor every implementation.ts(≥200 words, basic + advanced examples, full API reference, Implementation Notes) - 15.2 README links every co-located
.mdunder## Modules - 15.3 Update
CLAUDE.mdpackage listing under §Security / supply chain to addtpm-struct
16. Benchmarks
- 16.1
src/__benchmarks__/parse-tpms-attest.bench.ts— ~1 KiB attest buffer - 16.2
src/__benchmarks__/parse-tpmt-public-rsa2048.bench.ts— RSA-2048 public area - 16.3
src/__benchmarks__/parse-tpmt-public-ecc-p256.bench.ts— ECC P-256 public area - 16.4
src/__benchmarks__/compute-name.bench.ts— name digest with injected SHA-256 - 16.5 Baseline numbers published in README
17. Pre-archive verification (the 5-gate triple)
- 17.1
bun run check— Biome 0 errors / 0 warnings / 0 info across the whole monorepo - 17.2
bunx turbo lint typecheck test --filter=@suaveplan/tpm-struct— green - 17.3
bunx turbo test:coverage --filter=@suaveplan/tpm-struct— 100/100/100/100 - 17.4
bun scripts/openspec-conformance.ts @suaveplan/tpm-struct— exit 0, noerrorfindings - 17.5
bunx turbo build --filter=@suaveplan/tpm-struct— green
18. Pre-archive 7-row checklist (AGENTS.md §13)
- 18.1 Generics threaded;
expectTypeOfassertions on the literal unions (TpmAlgId,TpmEccCurve,TpmStructErrorCode, every discriminator) - 18.2 Zod schemas wired at every declared boundary
- 18.3 Every error code in
error-codes.tsthrown by at least one production path - 18.4
objectAttributesreserved-bits-strict mode tested both on (raise) and off (default raise; documented invariant — no off-mode) - 18.5 OTel instruments emitted from production paths and asserted with a real in-memory
MeterProvider - 18.6 No I/O imports —
grep -rnE "from ['\"](node:|tpm-js|node-tss|tss.js)" packages/security/tpm-struct/src/returns zero - 18.7 No retroactive tick — every box above reflects work done in this change
19. Archive
- 19.1 Fold spec delta into
openspec/specs/tpm-struct/spec.md - 19.2 Move
openspec/changes/enterprise-tpm-struct/→openspec/archive/2026-MM-DD-enterprise-tpm-struct/ - 19.3 Refresh
MANIFEST.mdviabun scripts/folder-reorg/generate-manifest.ts - 19.4 Refresh
MISSING.ymlviabun scripts/generate-missing.ts - 19.5 Update
STATUS.mdto move@suaveplan/tpm-structto Completed - 19.6 Update
SUMMARY.mdwith the per-package paragraph - 19.7
bunx markdownlint-cli2 --fixon touched files; re-stage; verify clean