zeph_gateway/lib.rs
1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! HTTP gateway for webhook ingestion with bearer-token auth and health endpoint.
5//!
6//! `zeph-gateway` exposes two HTTP endpoints over a single TCP listener:
7//!
8//! | Endpoint | Method | Auth required | Purpose |
9//! |---|---|---|---|
10//! | `/health` | GET | No | Liveness check; returns uptime in seconds |
11//! | `/webhook` | POST | Yes (if token set) | Ingest external events into the agent |
12//!
13//! # Security model
14//!
15//! - Bearer token comparison is performed in constant time via BLAKE3 + `subtle::ConstantTimeEq`
16//! to prevent timing-oracle attacks (see [`GatewayServer::with_auth`]).
17//! - When no token is configured the server logs a warning. Callers are expected to enforce
18//! access control at the network layer (firewall, upstream reverse proxy) in that case.
19//! - Payload fields are sanitised with [`zeph_common::sanitize`] before forwarding.
20//!
21//! # Rate limiting
22//!
23//! Requests to `/webhook` are rate-limited per remote IP using a fixed-window counter with a
24//! 60-second window. The default ceiling is 120 requests per window and is configurable via
25//! [`GatewayServer::with_rate_limit`]. Setting the limit to `0` disables rate limiting.
26//!
27//! # Quick start
28//!
29//! ```no_run
30//! use tokio::sync::{mpsc, watch};
31//! use zeph_gateway::GatewayServer;
32//!
33//! #[tokio::main]
34//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
35//! let (webhook_tx, mut webhook_rx) = mpsc::channel::<String>(64);
36//! let (_shutdown_tx, shutdown_rx) = watch::channel(false);
37//!
38//! // Spawn a consumer that processes incoming webhook messages.
39//! tokio::spawn(async move {
40//! while let Some(msg) = webhook_rx.recv().await {
41//! println!("received: {msg}");
42//! }
43//! });
44//!
45//! GatewayServer::new("127.0.0.1", 8080, webhook_tx, shutdown_rx)
46//! .with_auth(Some("my-secret-token".into()))
47//! .with_rate_limit(60)
48//! .serve()
49//! .await?;
50//!
51//! Ok(())
52//! }
53//! ```
54
55mod error;
56mod handlers;
57mod router;
58mod server;
59
60pub use error::GatewayError;
61pub use server::GatewayServer;