Expand description
GitHub webhook processing and validation.
This module provides comprehensive webhook handling for GitHub Apps, including signature validation, event processing, and async handler execution using a fire-and-forget pattern to ensure fast HTTP responses.
§Core Components
WebhookHandler- Trait for application-provided event processing logicWebhookReceiver- HTTP webhook intake with validation and async dispatchSignatureValidator- HMAC-SHA256 signature validationWebhookRequest/WebhookResponse- HTTP request/response types
§Fire-and-Forget Pattern
The receiver ensures GitHub receives responses within the 10-second timeout:
- Validate signature (< 10ms)
- Process/normalize event (< 5ms)
- Return HTTP response immediately (target < 100ms)
- Spawn async tasks for handlers (non-blocking)
§Security
Webhook signature validation uses HMAC-SHA256 with constant-time comparison to prevent timing attacks. All validation operations complete in under 100ms.
§Complete Usage Example
§Basic Webhook Handler
use github_bot_sdk::webhook::{WebhookHandler, WebhookReceiver, WebhookRequest};
use github_bot_sdk::auth::SecretProvider;
use github_bot_sdk::events::{EventProcessor, ProcessorConfig, EventEnvelope};
use async_trait::async_trait;
use std::sync::Arc;
use std::collections::HashMap;
// Define your handler
struct MyBotHandler;
#[async_trait]
impl WebhookHandler for MyBotHandler {
async fn handle_event(
&self,
envelope: &EventEnvelope,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
match envelope.event_type.as_str() {
"pull_request" => {
println!("Processing PR event: {}", envelope.event_id);
// Add your PR processing logic here
}
"issues" => {
println!("Processing issue event: {}", envelope.event_id);
// Add your issue processing logic here
}
_ => {
println!("Ignoring event type: {}", envelope.event_type);
}
}
Ok(())
}
}
// Setup receiver with processor
let processor = EventProcessor::new(ProcessorConfig::default());
let mut receiver = WebhookReceiver::new(secret_provider, processor);
// Register your handler
receiver.add_handler(Arc::new(MyBotHandler)).await;
// Process incoming webhook (typically called from HTTP server)
let headers = HashMap::from([
("x-github-event".to_string(), "pull_request".to_string()),
("x-github-delivery".to_string(), "12345-67890".to_string()),
("x-hub-signature-256".to_string(), "sha256=abc...".to_string()),
]);
let body = bytes::Bytes::from_static(b"{\"action\":\"opened\",\"number\":1}");
let request = WebhookRequest::new(headers, body);
let response = receiver.receive_webhook(request).await;
println!("Response status: {}", response.status_code());§Multiple Handlers
use github_bot_sdk::webhook::{WebhookHandler, WebhookReceiver};
use github_bot_sdk::events::EventEnvelope;
use async_trait::async_trait;
use std::sync::Arc;
// Define specialized handlers
struct PullRequestHandler;
struct IssueHandler;
struct SecurityHandler;
#[async_trait]
impl WebhookHandler for PullRequestHandler {
async fn handle_event(&self, envelope: &EventEnvelope) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
if envelope.event_type == "pull_request" {
println!("PR Handler: Processing {}", envelope.event_id);
// PR-specific logic
}
Ok(())
}
}
#[async_trait]
impl WebhookHandler for IssueHandler {
async fn handle_event(&self, envelope: &EventEnvelope) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
if envelope.event_type == "issues" {
println!("Issue Handler: Processing {}", envelope.event_id);
// Issue-specific logic
}
Ok(())
}
}
#[async_trait]
impl WebhookHandler for SecurityHandler {
async fn handle_event(&self, envelope: &EventEnvelope) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// Security monitoring across all event types
println!("Security: Auditing event {}", envelope.event_id);
Ok(())
}
}
// Register multiple handlers - all will be invoked concurrently
receiver.add_handler(Arc::new(PullRequestHandler)).await;
receiver.add_handler(Arc::new(IssueHandler)).await;
receiver.add_handler(Arc::new(SecurityHandler)).await;§HTTP Server Integration (Axum Example)
ⓘ
use github_bot_sdk::webhook::{WebhookReceiver, WebhookRequest, WebhookResponse};
use axum::{
extract::State,
http::{HeaderMap, StatusCode},
response::{IntoResponse, Response},
Json, Router,
routing::post,
};
use bytes::Bytes;
use std::sync::Arc;
// Application state with receiver
#[derive(Clone)]
struct AppState {
receiver: Arc<WebhookReceiver>,
}
// HTTP handler for webhook endpoint
async fn handle_webhook(
State(state): State<AppState>,
headers: HeaderMap,
body: Bytes,
) -> Response {
// Convert HTTP headers to HashMap
let header_map: std::collections::HashMap<String, String> = headers
.iter()
.map(|(k, v)| (k.as_str().to_lowercase(), v.to_str().unwrap_or("").to_string()))
.collect();
// Create webhook request
let request = WebhookRequest::new(header_map, body);
// Process webhook
let response = state.receiver.receive_webhook(request).await;
// Convert to HTTP response
let status = StatusCode::from_u16(response.status_code()).unwrap();
let message = response.message().to_string();
(status, Json(serde_json::json!({
"message": message
}))).into_response()
}
let state = AppState { receiver };
let app = Router::new()
.route("/webhook", post(handle_webhook))
.with_state(state);
// Run server
// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
// axum::serve(listener, app).await?;§Direct Signature Validation
If you need to validate signatures independently:
use github_bot_sdk::webhook::SignatureValidator;
use github_bot_sdk::auth::SecretProvider;
use std::sync::Arc;
let validator = SignatureValidator::new(secret_provider);
let payload = b"{\"action\":\"opened\",\"number\":1}";
let signature = "sha256=5c4a..."; // From X-Hub-Signature-256 header
let is_valid = validator.validate(payload, signature).await?;
if is_valid {
println!("Webhook signature is valid");
} else {
println!("Invalid webhook signature - possible tampering");
}Re-exports§
pub use handler::WebhookHandler;pub use receiver::WebhookReceiver;pub use receiver::WebhookRequest;pub use receiver::WebhookResponse;pub use validation::SignatureValidator;
Modules§
- handler
- Webhook handler trait and types for application-provided processing logic.
- receiver
- Webhook receiver for HTTP intake and async processing coordination.
- validation
- Webhook signature validation implementation.