SIGN IN SIGN UP

Restore inbound webhooks; wrap webhook wakes in the structured wake envelope (#570)

* Restore inbound webhooks; wrap webhook wakes in the structured wake envelope

Reinstates the inbound-webhook subsystem that was removed alongside Gmail
Pub/Sub: the receiver, store, and verifiers (hmac-sha256/github/slack/stripe),
the /v1/webhooks routes with public ingress, control-service resolution, the
typed `webhook` tool, the portal ingress passthrough, and the web-ui Webhooks
view. Gmail Pub/Sub stays removed.

The wake a delivery fires is new: instead of the old bare
"<action>\n\n<event>…</event>" prompt, the receiver renders a structured
<wake reason="webhook"> envelope (buildWebhookWakeEnvelope, sharing the
ambient wake's grammar) — the owner's stored action attributed in
<standing-orders>, the payload XML-escaped inside a trust-annotated <event>
block so a hostile body cannot forge envelope structure or instructions,
and host guidance in <instructions>. The raw capped payload still goes to
the security screener via securityScreenData, and "webhook" is back in
DATA_BEARING_SURFACES and POLL_SURFACES.

* Address review: legacy-row sweep, fire-time consent, URL single-source, BFF fixes

- One-time migration disables webhook rows orphaned by the removal, so
  redeploying cannot silently re-arm months-old registrations against
  stale secrets and standing orders.
- Webhook fires now pass recipientConsentRequired, closing the gap where
  a raw source-auth create with a third-party principal destination
  would DM that person forever with no consent record; owner gets the
  same skip notice crons produce. Covered by two new receiver tests.
- Re-creating a byte-identical disabled webhook re-enables it instead of
  silently returning a dead registration that 404s every delivery.
- Core is the single source of inbound URLs: the list route now returns
  each webhook's url from the core public base, and the web-ui BFF's
  WEBHOOK_PUBLIC_BASE env (which fell back to the internal core address)
  is gone along with its cli/stack/fly plumbing.
- BFF: non-string verification.scheme is a 400 instead of silently
  minting a different secret; the enable/disable ownership pre-check
  relays core errors instead of converting them to 404.
- The standing-obligations overflow footer names `webhook` action=list
  when the truncated items include webhooks.
- Enable/disable paths use app.getWebhook instead of scanning the full
  list; the supported-scheme list is exported from the verifier registry
  instead of hand-copied into the route validator.
- Repair a bad CSS insert that had widened .card .actions to .actions.

---------

Co-authored-by: Regan Bell <reganbell@gmail.com>
J
Joshua France committed
f0480629c608c62a2573a486028248dc622c5b73
Parent: 3b6674b
Committed by GitHub <noreply@github.com> on 8/18/2026, 1:08:44 AM