From 4f6a98332e28974a50914c95c7b812dac6561647 Mon Sep 17 00:00:00 2001 From: Zac Lou <97340247+ZacLou@users.noreply.github.com> Date: Fri, 28 Aug 2026 08:00:12 +0800 Subject: [PATCH 1/3] feat: add request ID middleware to API (#27) --- crates/api/src/middleware.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/crates/api/src/middleware.rs b/crates/api/src/middleware.rs index 382733f..bc5e756 100644 --- a/crates/api/src/middleware.rs +++ b/crates/api/src/middleware.rs @@ -1,4 +1,5 @@ // API key authentication middleware for admin routes. +// + Request ID middleware for trace propagation across services. use axum::{ body::Body, extract::State, @@ -11,6 +12,31 @@ use serde_json::json; use crate::state::AppState; + +// Request ID middleware: reads X-Request-Id header or generates a UUIDv4, +// injects it into response headers, and attaches it to the tracing span. +pub async fn request_id( + req: Request, + next: Next, +) -> Response { + let request_id = req + .headers() + .get("x-request-id") + .and_then(|v| v.to_str().ok()) + .map(str::to_string) + .unwrap_or_else(|| uuid::Uuid::new_v4().to_string()); + + tracing::Span::current().record("request_id", &request_id); + + let mut response = next.run(req).await; + response.headers_mut().insert( + "x-request-id", + request_id.parse().unwrap(), + ); + response +} + + pub async fn require_admin_key( State(state): State, req: Request, From 279f3a79fed02da1bd57141b45c871a61c53c4da Mon Sep 17 00:00:00 2001 From: Zac Lou <97340247+ZacLou@users.noreply.github.com> Date: Fri, 28 Aug 2026 08:00:14 +0800 Subject: [PATCH 2/3] feat: wire request ID middleware into API router (#27) From efd588d437792fdcf8d6b5bea4bedb0efc32f2b1 Mon Sep 17 00:00:00 2001 From: Zac Lou <97340247+ZacLou@users.noreply.github.com> Date: Fri, 28 Aug 2026 08:00:17 +0800 Subject: [PATCH 3/3] feat: add request ID middleware to gateway (#27) --- crates/gateway/src/routes.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/crates/gateway/src/routes.rs b/crates/gateway/src/routes.rs index 861394a..d67d749 100644 --- a/crates/gateway/src/routes.rs +++ b/crates/gateway/src/routes.rs @@ -20,11 +20,37 @@ use crate::attestation::{ use crate::state::AppState; use crate::webhook::{parse_merge_event, verify_github_signature}; +// Request ID middleware for trace propagation across services. +async fn request_id(req: Request, next: Next) -> Response { + use axum::body::Body; + use axum::http::Request; + use axum::middleware::Next; + use axum::response::Response; + + let request_id = req + .headers() + .get("x-request-id") + .and_then(|v| v.to_str().ok()) + .map(str::to_string) + .unwrap_or_else(|| uuid::Uuid::new_v4().to_string()); + + tracing::Span::current().record("request_id", &request_id); + + let mut response = next.run(req).await; + response.headers_mut().insert( + "x-request-id", + request_id.parse().unwrap(), + ); + response +} + + pub fn router(state: AppState) -> Router { Router::new() .route("/health", get(health)) .route("/ready", get(ready)) .route("/webhooks/github", post(github_webhook)) + .layer(axum::middleware::from_fn(request_id)) .with_state(state) }