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)
}