Proof #3 now supports the production asymmetric path, not just the dev shared secret.
- context-attestation.ts: PublicKeyResolverPort seam; verify() picks ES256 (JWKS by
kid) when the client has a jwksUri, else HS256 (dev). signDevAttestationES256 helper.
- attestation-stores.ts: JwksPublicKeyResolver (jwks-rsa, one cached client per URI,
refetch on rotation, fail-closed to NO_KEY).
- attestation.module.ts: inject the resolver into the verifier; dev-seed the client as
clientType APPSHELL (it is the CRM browser-flow parent per the July-12 notes).
- rename the registered client crm-support-widget -> appshell-crm (the name reflects the
attesting parent, not a widget).
- specs: ES256 (valid via JWKS, wrong key -> BAD_SIGNATURE, unknown kid -> NO_KEY, no
resolver -> NO_KEY) + two stolen-token gate cases (wrong app binding -> APP_MISMATCH,
wrong audience -> WRONG_AUDIENCE).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Applies the context-attestation verifier at the request boundary via a guard, so a
stolen/forged/replayed attestation is rejected before IIOS acts — while staying safe
to roll out.
- ContextAttestationGuard: if an X-Context-Attestation header is present, verify it
(its app_id must match the actor token's app_id) → 403 on any failure; if absent,
allow only when IIOS_REQUIRE_ATTESTATION != 1 (dev/zero-trust), else 403. The flag is
read per-request and defaults OFF, so existing callers keep working until AppShell/
be-crm start forwarding attestations.
- AttestationModule (@Global): provides the verifier + Prisma stores + guard, and
dev-seeds the crm-support-widget client so locally minted attestations verify.
- Guard applied to ThreadsController + SupportController.
- Tests (5 pass, no DB): not-required-allows, required-rejects, valid, forged, replayed.
Workload/mTLS (proof #2) stays a mesh concern. Next: SDK header passthrough + demote
be-crm IiosClient to forward an attestation, then flip the flag to prove end-to-end.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>