3 Commits

Author SHA1 Message Date
Grant Whitmer
a094960da3 G3.5: accept platform.test_ping unverified — unverifiable by construction
All checks were successful
check / gate (push) Successful in 19s
canary / probe (push) Successful in 26s
Read the sender rather than guessing: Eternitas generates the webhook secret at
registration time and pings the URL to prove reachability BEFORE returning that
secret. The ping IS signed — with a secret the receiver cannot possibly hold
yet. Unverifiable by construction, not by oversight.

Accepting it is safe because the event is definitionally a no-op: nothing read,
nothing written, acted:false. Every event that changes anything still requires a
valid HMAC. The alternative, skip_validation:true, would permanently disable
reachability checking for this platform to solve a one-time ordering problem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 15:36:03 -04:00
Grant Whitmer
5dd914b8a6 G3.5: answer the reachability probe honestly instead of skipping validation
All checks were successful
check / gate (push) Successful in 18s
Eternitas verifies a webhook URL answers BEFORE issuing the secret that signs
deliveries, so the very first request can never carry a signature — refusing it
makes registration impossible. Real chicken-and-egg, not a reason to disable
validation.

A probe is a request claiming no event and carrying no signature. Answering it
200 is honest: the endpoint exists and is ready. It changes nothing (acted:
false), and anything claiming to BE an event still goes through full HMAC
verification. Registering with skip_validation:true would have permanently
disabled a safety check to solve a one-time ordering problem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 15:33:56 -04:00
Grant Whitmer
339ec70853 G3.5: Eternitas revocation receiver — fail-closed, both signature traps avoided
All checks were successful
check / gate (push) Successful in 18s
When a passport is revoked, every credential it holds here dies in one
transaction: tokens revoked, grants revoked. A revocation that takes effect
'eventually' is not a revocation.

Avoids two traps that each cost a sibling service a subscription that looked
wired and never once delivered:
  1. strip the 'sha256=' prefix before comparing — comparing the decorated
     header against a bare digest returns 401 forever
  2. HMAC the RAW REQUEST BYTES, never a re-serialised body — JSON.stringify of
     a parsed body reorders keys and changes whitespace, so the digest never
     matches what the sender signed

Both fail silently from the sender's side: Eternitas records a delivery, the
receiver records a rejection, nobody notices for weeks.

Unset secret REFUSES rather than accepts — accepting unverified instructions
about identity is worse than missing them. And it never acknowledges a
revocation it could not apply; a 200 there is a security hole reporting success.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 15:32:27 -04:00