Skip to content

POST / should route to a CESR-typed dispatcher (standard keripy wallets post to URL root, not /process) #2

Description

@seriouscoderone

Summary

Standard keripy clients (keri.app.agenting.WitnessReceiptor → HTTPMessenger → streamCESRRequests) POST inbound CESR events to the root path (/) of the URL declared in the witness's /loc/scheme reply. keripy's LocationRecord.url is parsed for scheme + host + port only — any path component is ignored when building the HTTP client.

keri.host's API Gateway today routes only:

Path Methods
/ OPTIONS only
/witness GET — status
/witness/oobi/{id} GET — OOBI bundle (controller role)
/witness/oobi/{id}/witness/{witness} GET — witness-role OOBI bundle (from issue #1)
/witness/introduce GET
/witness/process POST — inbound events
/witness/query POST — queries

So a wallet's POST to the URL declared by the OOBI (https://witness.keri.host/) has no matching route — the request hangs at the API Gateway until timeout. CloudWatch confirms zero invocations of KerihostWitnessStack-{process,query,oobi} for our test traffic.

Repro

After issue #1 fixed (witness-role OOBI now serves correct endpoint declarations), Locksmith successfully:

  1. Resolved /oobi/BNbRf.../witness — ends table now has (BNbRf..., 'witness', BNbRf...) and locs has (BNbRf..., 'https') → https://witness.keri.host.

  2. Created an inception event EAat5ezAlaTezaWi1Njx866poW-6_l5xXIUO5DTqvuG4 with wits=[BNbRf...], toad=1.

  3. keri.app.agenting.WitnessReceiptor picked up the event, constructed an HTTPMessenger with url=https://witness.keri.host, and submitted the CESR bytes to streamCESRRequests(client, ims=..., dest=BNbRf...).

  4. streamCESRRequests posted to / (the default path when path=None).

  5. API Gateway found no POST / route and the request hung. AWS confirms zero Lambda invocations during the test window:

    $ aws logs tail /aws/lambda/KerihostWitnessStack-process --since 5m
    (empty)
    $ aws logs tail /aws/lambda/KerihostWitnessStack-query --since 5m
    (empty)
    

Direct repro at the HTTP layer:

$ curl -sS -w "HTTP %{http_code}\n" --max-time 5 -X POST "https://witness.keri.host/" \
       -H "Content-Type: application/cesr" --data-binary "test"
HTTP 000   # (timeout — no response at all)

$ curl -sS -w "HTTP %{http_code}\n" --max-time 5 -X POST "https://witness.keri.host/process" \
       -H "Content-Type: application/cesr" --data-binary "test"
HTTP 403   # (API Gateway "no route" — confirms /process is not a top-level route either)

Why this matters

Standard keripy wallets cannot publish events to keri.host today. The wallet's WitnessReceiptor will sit indefinitely in "Waiting for witness receipts for ..." with no error surfaced — because the HTTP layer just times out, and keripy's outer wait-loop doesn't have a meaningful timeout that propagates back up.

Three approaches considered

A. Add POST / that routes to KerihostWitnessStack-process

One API Gateway route change. Standard keripy wallets work immediately. Right answer for an unblocking patch.

Downside: process Lambda is now the catch-all for any POST. If a wallet sends a qry (query) message — also a valid CESR payload that some flows produce — it lands at process rather than query. Either process handles it (duplicate logic) or proxies to query (added latency + indirection inside the Lambda).

B. Declare URL with path in /loc/scheme

E.g., return "url":"https://witness.keri.host/process" from the OOBI. Doesn't work. keripy's LocationRecord.url is parsed by urllib.parse.urlparse and only the scheme/hostname/port are passed to hio.http.clienting.Client. The path component is dropped. Confirmed by reading keri.app.agenting.HTTPMessenger.__init__ and keri.app.agenting.streamCESRRequests.

C. CESR-typed dispatch at the root — recommended

Add POST / mapped to a small router Lambda (or routing logic in the existing process Lambda) that:

  1. Reads enough of the incoming CESR stream to identify the message type (t field on the first Serder).
  2. Dispatches to the appropriate downstream:
    • icp, rot, ixn, dip, drt (establishment + interaction events) → process Lambda
    • qry (query messages) → query Lambda
    • rct (receipts) → process Lambda
    • exn (peer-to-peer exchange) → depending on route, an exchange handler or process
  3. Returns the downstream's response (or a CESR-encoded receipt stream when applicable).

This is the same pattern keria-aws uses (/agent/{proxy+} with internal dispatch). Production-grade benefits:

  • Single entry surface — one place for auth, rate limiting, request size limits, DLQ semantics, structured logging.
  • Observability — log message type before dispatch; CloudWatch metrics per message type.
  • Evolvability — adding a new message type is a router-Lambda change, not an API Gateway change.
  • Standard keripy compatibility — no client-side changes needed.
  • The existing /witness/process and /witness/query routes can remain for direct-dispatch testing/diagnostics.

Recommendation

Ship C. A is acceptable as a stopgap if C is more than ~a day of work, but the architecture should converge on C because that's what production-grade KERI-on-AWS deployments look like (keria-aws being the reference).

If implementing C in the existing KerihostWitnessStack-process Lambda (vs adding a dedicated router Lambda), the existing process handler can be the dispatcher itself — it already runs provided.al2023 (Rust/native), which makes parsing the CESR header for message-type-based dispatch cheap.

Environment

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions