ryu-webhook-ingress 0.1.3

Webhook ingress: the swappable public-reachability seam that lets a loopback-bound Ryu Core receive third-party webhooks (Composio triggers, per-workflow webhooks). Owns the four ingress backends (managed RyuRelay outbound SSE push, Tailscale Funnel, cloudflared quick tunnel, BYO own-relay), the path-routed inbound dispatcher with fail-closed HMAC re-verification, replay-window + delivery dedup, and the ingress-URL registry. An extracted Core capability crate — in-process default (no IPC on any hot path); the kernel couplings (composio verify/run, workflow-secret lookup, mesh funnel, auth token, data dir) are inverted through the WebhookIngressHost trait so this crate has ZERO dependency on apps/core. Public webhook ROUTES stay kernel-ingress in Core and forward into this engine (program §5).
Documentation
# ryu-webhook-ingress

The swappable **public-reachability seam** (unified-tool-gateway epic #479, P6a) that
lets a loopback-bound Ryu Core receive third-party webhooks — Composio triggers (which
are webhook-delivered, with no event-pull API) and per-workflow webhooks — by giving
Core a publicly-reachable URL pointed at its existing handler.

## Role in the decomposition

An extracted **Core capability crate**, compiled into `apps/core` as the in-process
default (no IPC on any hot path). Exposing a tunnel + deciding which backend runs is
*what runs* → **Core**; there is no policy here. Public webhook **routes** stay
kernel-ingress in Core and forward inbound deliveries into this engine.

Zero dependency on `apps/core`. The kernel couplings (Composio verify/run,
workflow-secret lookup, mesh funnel, auth token, data dir) invert through the
**`WebhookIngressHost`** trait, installed by Core at boot via `set_global_host`.

## Nothing hardcoded — the backend swap seam

The backend is a swappable `Ingress` enum selected by the `webhook.ingress.backend`
pref (`IngressKind`, kebab-case wire form), default `RyuRelay`:

- **RyuRelay** — the managed default: outbound SSE push (no inbound port).
- **TailscaleFunnel** — via `ryu-mesh`'s `ensure_funnel`.
- **Cloudflared** — a quick tunnel subprocess.
- **OwnRelay** — BYO public base URL (`RYU_WEBHOOK_INGRESS_URL` env override, else the
  `webhook.ingress.url` pref).

Backend dispatch uses native `async fn` trait methods + a closed enum match — no
`async-trait`/`dyn` (the host seam is the one `dyn` boundary).

## Key surface

- `Ingress` / `IngressKind` + backend sources (`RyuRelaySource`,
  `TailscaleFunnelSource`, `CloudflaredSource`, `OwnRelaySource`).
- `deliver_inbound` / `deliver_workflow_webhook` — the path-routed inbound dispatcher
  with fail-closed HMAC re-verification, a replay window, and delivery dedup.
- `record_delivery` / `last_delivery` / `timestamp_fresh` / `workflow_webhook_path`.

## Consumed as

Compiled-into-Core crate; Core's public webhook routes forward into it.

Deps: tokio, reqwest, futures-util, serde/serde_json, anyhow, async-trait.