166 lines
11 KiB
Markdown
166 lines
11 KiB
Markdown
# Tasks — `@suaveplan/webauthn` (WebAuthn Level 3 client + parser + verifier)
|
|
|
|
> Every checkbox MUST reflect work actually done in this change. Do not retroactively tick boxes for work that was already in main when this change opened. Do not tick a box for a test that doesn't exist or doesn't pin the requirement it claims to verify.
|
|
|
|
## 0. Blocking prerequisite
|
|
|
|
- [ ] 0.1 `enterprise-cbor` change archived and `@suaveplan/cbor` published from genesis (COSE / CTAP CBOR profile available). **No implementation task in §2 may start until this lands.** Spec / proposal / fixture-prep tasks (§1, §3) are unblocked.
|
|
|
|
## 1. Spec authoring
|
|
|
|
- [x] 1.1 Read `../suaveplan/enterprise/webauthn.md` end-to-end
|
|
- [x] 1.2 Read W3C WebAuthn L3 §5, §6, §7, §8, §9, §10
|
|
- [x] 1.3 Read CTAP 2.1 §6.5, RFC 9052 §7, IANA WebAuthn registries
|
|
- [x] 1.4 Read `openspec/AGENTS.md` §13 and §14
|
|
- [x] 1.5 Draft `proposal.md` from `openspec/templates/proposal.md`
|
|
- [x] 1.6 Fill in `## Source mapping` table — every requirement cites enterprise-doc lines + a W3C / CTAP / RFC anchor
|
|
- [x] 1.7 Draft `specs/webauthn/spec.md` from `openspec/templates/spec-delta.md`
|
|
- [x] 1.8 Every requirement in the spec delta carries a `**Verified by:**` line naming concrete `it(...)` titles
|
|
|
|
## 2. Implementation
|
|
|
|
### 2.1 Adapter abstraction
|
|
|
|
- [x] 2.1.1 `src/adapter/adapter.ts` — `WebAuthnAdapter` interface (`create`, `get`, `isSupported`, `isConditionalMediationAvailable`)
|
|
- [x] 2.1.2 `src/adapter/default-adapter.ts` — `defaultWebAuthnAdapter()` binding `globalThis.navigator.credentials`; throws `WEBAUTHN.NOT_SUPPORTED` when missing
|
|
- [x] 2.1.3 `src/adapter/dom-exception-mapper.ts` — `NotAllowedError` → `WEBAUTHN.USER_CANCELLED`, `InvalidStateError` → `WEBAUTHN.INVALID_STATE`, `SecurityError` → `WEBAUTHN.SECURITY_ERROR`, `AbortError` → `WEBAUTHN.ABORTED`, `NotSupportedError` → `WEBAUTHN.NOT_SUPPORTED`
|
|
|
|
### 2.2 Errors + observability
|
|
|
|
- [x] 2.2.1 `src/errors/errors.ts` — `WebAuthnError` registry via `defineCodes("WEBAUTHN", [...])` covering every code in the spec delta
|
|
- [x] 2.2.2 `src/observability/metrics.ts` — `webauthn.register_duration_ms`, `webauthn.authenticate_duration_ms`, `webauthn.outcome_total`, `webauthn.attestation_format_total`, `webauthn.errors_total`
|
|
|
|
### 2.3 Parser (universal-tier `./parser` subpath)
|
|
|
|
- [x] 2.3.1 `src/parser/client-data.ts` — `parseClientDataJSON`; type pinning + origin + base64url challenge decode + Zod `ClientDataJSONSchema`
|
|
- [x] 2.3.2 `src/parser/authenticator-data.ts` — `parseAuthenticatorData`; 37-byte fixed-prefix split + flag-byte decoder + attested-credential-data + extensions block
|
|
- [x] 2.3.3 `src/parser/cose-key.ts` — RFC 9052 §7 COSE_Key decoder consuming `@suaveplan/cbor`; supports ES256 / ES384 / ES512 / EdDSA / RS256 alg labels
|
|
- [x] 2.3.4 `src/parser/attestation-object.ts` — `parseAttestationObject` per CTAP 2.1 §6.5; extracts `fmt` / `authData` / `attStmt`
|
|
- [x] 2.3.5 Zod boundary schemas at every export — `MALFORMED_RESPONSE` on mismatch
|
|
|
|
### 2.4 Verifier (universal-tier `./verifier` subpath)
|
|
|
|
- [x] 2.4.1 `src/verifier/verify-assertion.ts` — signature verify over `authData || sha256(clientDataJSON)` via `@suaveplan/crypto-curve`, dispatched on COSE alg
|
|
- [x] 2.4.2 `src/verifier/sign-counter.ts` — sign-counter regression detection per W3C L3 §6.1.1
|
|
- [x] 2.4.3 `src/verifier/verify-attestation.ts` — `verifyAttestation` dispatcher
|
|
- [x] 2.4.4 `src/verifier/registry.ts` — `defaultAttestationRegistry()` + `registerAttestationFormat(name, verifier)`
|
|
|
|
### 2.5 Per-format attestation verifiers
|
|
|
|
- [x] 2.5.1 `src/attestation/packed/packed.ts` — W3C L3 §8.2
|
|
- [x] 2.5.2 `src/attestation/fido-u2f/fido-u2f.ts` — W3C L3 §8.6
|
|
- [x] 2.5.3 `src/attestation/tpm/tpm.ts` — W3C L3 §8.3
|
|
- [x] 2.5.4 `src/attestation/android-key/android-key.ts` — W3C L3 §8.4
|
|
- [x] 2.5.5 `src/attestation/android-safetynet/android-safetynet.ts` — W3C L3 §8.5
|
|
- [x] 2.5.6 `src/attestation/apple/apple.ts` — W3C L3 §8.8
|
|
- [x] 2.5.7 `src/attestation/none/none.ts` — W3C L3 §8.7
|
|
|
|
### 2.6 Registration (browser-tier root)
|
|
|
|
- [x] 2.6.1 `src/register/register.ts` — `register(opts)` building `PublicKeyCredentialCreationOptions`, calling adapter, parsing `AuthenticatorAttestationResponse`
|
|
- [x] 2.6.2 Client-data validator wired (type / origin / challenge constant-time-equals)
|
|
- [x] 2.6.3 `expectedRpIdHash` constant-time compare
|
|
- [x] 2.6.4 AbortSignal forwarded to `navigator.credentials.create`
|
|
- [x] 2.6.5 OTel `webauthn.register_duration_ms` recorded with `outcome` label
|
|
|
|
### 2.7 Authentication (browser-tier root)
|
|
|
|
- [x] 2.7.1 `src/authenticate/authenticate.ts` — `authenticate(opts)` building `PublicKeyCredentialRequestOptions`, calling adapter, parsing `AuthenticatorAssertionResponse`
|
|
- [x] 2.7.2 Client-data validator pinned to `webauthn.get`
|
|
- [x] 2.7.3 Conditional mediation passthrough; `isConditionalMediationAvailable()` helper
|
|
- [x] 2.7.4 AbortSignal forwarded to `navigator.credentials.get`
|
|
- [x] 2.7.5 OTel `webauthn.authenticate_duration_ms` recorded with `outcome` label
|
|
|
|
### 2.8 Extensions
|
|
|
|
- [x] 2.8.1 `src/extensions/prf/prf.ts` — PRF eval input on register + authenticate; result parsing; `enabled === false` fallback
|
|
- [x] 2.8.2 `src/extensions/large-blob/large-blob.ts` — `support` on register; `read` / `write` on authenticate; result shape
|
|
|
|
### 2.9 Root barrel + subpath exports
|
|
|
|
- [x] 2.9.1 `src/index.ts` — explicit named re-exports (no `export *`)
|
|
- [x] 2.9.2 `package.json` `exports` map covers every subpath listed in the proposal
|
|
- [x] 2.9.3 `package.json` `browser` field set; `engines` does not pin Node-only
|
|
|
|
## 3. Test-vector bundle
|
|
|
|
- [ ] 3.1 `src/__fixtures__/yubikey-packed/` — Yubikey 5 packed attestation good vector + corrupted variants
|
|
- [ ] 3.2 `src/__fixtures__/yubikey-fido-u2f/` — Yubikey 5 fido-u2f good vector
|
|
- [ ] 3.3 `src/__fixtures__/windows-hello-tpm/` — Windows Hello TPM attestation good vector
|
|
- [ ] 3.4 `src/__fixtures__/macos-touch-id-apple/` — Apple anonymous attestation good vector
|
|
- [ ] 3.5 `src/__fixtures__/chrome-software-none/` — Chrome software authenticator `none` format
|
|
- [ ] 3.6 `src/__fixtures__/android-key/` and `android-safetynet/` — Pixel platform-authenticator vectors
|
|
- [ ] 3.7 Each fixture set has at least one corrupted variant (signature flipped, rpIdHash zeroed, signCount frozen)
|
|
- [ ] 3.8 Fixtures generated offline; CI does not depend on a real authenticator
|
|
|
|
## 4. Tests (runner-neutral imports per CLAUDE.md §11 — `@suaveplan/testing/runner`)
|
|
|
|
- [ ] 4.1 `src/register/register.test.ts` — happy path, client-data mismatches, AbortSignal, DOMException mapping
|
|
- [ ] 4.2 `src/authenticate/authenticate.test.ts` — happy path, conditional mediation, AbortSignal
|
|
- [ ] 4.3 `src/parser/authenticator-data.test.ts` — every flag combination, attested-credential-data, extensions block
|
|
- [ ] 4.4 `src/parser/attestation-object.test.ts` — `fmt` / `authData` / `attStmt` extraction
|
|
- [ ] 4.5 `src/parser/client-data.test.ts` — type pinning, base64url decode
|
|
- [ ] 4.6 `src/parser/cose-key.test.ts` — RFC 9052 §7 round-trip per alg
|
|
- [ ] 4.7 `src/verifier/verify-assertion.test.ts` — every alg, signature-flip negative, sign-counter regression boundaries
|
|
- [ ] 4.8 `src/verifier/verify-attestation.test.ts` — registry dispatch, unknown-format error
|
|
- [ ] 4.9 Per-format `src/attestation/<fmt>/<fmt>.test.ts` — good + corrupted vectors for `packed`, `fido-u2f`, `tpm`, `android-key`, `android-safetynet`, `apple`, `none`
|
|
- [ ] 4.10 `src/extensions/prf/prf.test.ts` — register + authenticate eval round-trip + length assertion + missing-PRF fallback
|
|
- [ ] 4.11 `src/extensions/large-blob/large-blob.test.ts` — support flag, read, write
|
|
- [ ] 4.12 `src/adapter/adapter.test.ts` — `NOT_SUPPORTED` when missing, conditional-mediation check
|
|
- [ ] 4.13 `src/errors/errors.test.ts` — every code thrown by ≥1 production path; DOMException mapping
|
|
- [ ] 4.14 `src/observability/metrics.test.ts` — every histogram + counter recorded against in-memory `MeterProvider`
|
|
- [ ] 4.15 `src/parser/authenticator-data.property.test.ts` — fast-check fuzz, parser never panics
|
|
- [ ] 4.16 `src/parser/attestation-object.property.test.ts` — fast-check fuzz of envelope decoder
|
|
- [ ] 4.17 `src/index.test.ts` — every documented subpath resolves
|
|
- [ ] 4.18 `tests/dep-graph.test.ts` — `./parser` and `./verifier` import zero DOM types
|
|
- [ ] 4.19 Every `it(...)` carries `{ timeout: 5000 }` (or 30000 for genuinely async)
|
|
|
|
## 5. Documentation
|
|
|
|
- [x] 5.1 Sibling `.md` for every implementation `.ts` (≥200 words, basic + advanced examples, full API reference)
|
|
- [x] 5.2 README.md with Modules table linking every co-located `.md`
|
|
- [x] 5.3 Update `CLAUDE.md` package listing under the Vault section
|
|
- [x] 5.4 README cites W3C WebAuthn L3 / CTAP 2.1 / RFC 9052 anchors
|
|
|
|
## 6. Benchmarks (mitata)
|
|
|
|
- [ ] 6.1 `src/__benchmarks__/parse_authdata.bench.ts`
|
|
- [ ] 6.2 `src/__benchmarks__/verify_assertion_es256.bench.ts`
|
|
- [ ] 6.3 `src/__benchmarks__/verify_attestation_packed.bench.ts`
|
|
- [ ] 6.4 `src/__benchmarks__/verify_attestation_tpm.bench.ts`
|
|
- [ ] 6.5 Baseline numbers committed in README
|
|
|
|
## 7. Pre-archive verification (the 5-gate triple)
|
|
|
|
- [ ] 7.1 `bun run check` — Biome 0 errors / 0 warnings / 0 info across the whole monorepo
|
|
- [ ] 7.2 `bunx turbo lint typecheck test --filter=@suaveplan/webauthn` — green
|
|
- [ ] 7.3 `bunx turbo test:coverage --filter=@suaveplan/webauthn` — 100/100/100/100
|
|
- [ ] 7.4 `bun scripts/openspec-conformance.ts @suaveplan/webauthn` — exit 0, no `error` findings
|
|
- [ ] 7.5 `bunx turbo build --filter=@suaveplan/webauthn` — green
|
|
|
|
## 8. Pre-archive 7-row checklist (AGENTS.md §13)
|
|
|
|
- [ ] 8.1 Generics threaded; `expectTypeOf` assertions on every literal-type claim (`AttestationType`, `WebAuthnErrorCode`, `CoseAlg`)
|
|
- [ ] 8.2 Zod schemas wired at every declared boundary (register / authenticate options, parsed structures, COSE_Key)
|
|
- [ ] 8.3 Every error code in `errors.ts` thrown by at least one production path
|
|
- [ ] 8.4 Strict-mode behaviors tested both on and off (UV required vs preferred; attestation `direct` vs `none`)
|
|
- [ ] 8.5 OTel instruments emitted from production paths and asserted with a real in-memory `MeterProvider`
|
|
- [ ] 8.6 Lifecycle dedup tested where claimed (AbortSignal mid-flight, conditional-mediation availability cache)
|
|
- [ ] 8.7 No retroactive tick — every box above reflects work done in this change
|
|
|
|
## 9. Banned-pattern + barrel + runner-import scans
|
|
|
|
- [ ] 9.1 `grep -rn "@deprecated\|TODO\|FIXME\|ts-ignore\|ts-expect-error\|\.skip\|\.only" packages/vault/webauthn/src/ --include="*.ts"` — zero output
|
|
- [ ] 9.2 `grep -rn "^\s*export\s\+\(type\s\+\)\?\*\s\+from" packages/vault/webauthn/src/ --include="index.ts"` — zero output (root `src/index.ts` permitted; feature barrels must use named exports)
|
|
- [ ] 9.3 `grep -rnE "from ['\"](vitest|bun:test)['\"]" packages/vault/webauthn/src/ --include="*.ts" --include="*.tsx"` — zero output (package is not on the testing-infra exempt allowlist)
|
|
|
|
## 10. Archive
|
|
|
|
- [ ] 10.1 Fold spec delta into `openspec/specs/webauthn/spec.md`
|
|
- [ ] 10.2 Move `openspec/changes/enterprise-webauthn/` → `openspec/archive/<yyyy-mm-dd>-enterprise-webauthn/`
|
|
- [ ] 10.3 Refresh `MANIFEST.md` via `bun scripts/folder-reorg/generate-manifest.ts`
|
|
- [ ] 10.4 Refresh `MISSING.yml` via `bun scripts/generate-missing.ts`
|
|
- [ ] 10.5 Move `@suaveplan/webauthn` row in `STATUS.md` from `Pending` → `Completed`
|
|
- [ ] 10.6 Update `SUMMARY.md` with per-package paragraph
|
|
- [ ] 10.7 `bunx markdownlint-cli2 --fix` and stage results
|