Skip to content

Commit ae7971c

Browse files
committed
Upgrade warp to 0.4.2
Signed-off-by: Erick Bourgeois <erick@jeb.ca>
1 parent 420c3dc commit ae7971c

5 files changed

Lines changed: 83 additions & 14 deletions

File tree

.claude/CHANGELOG.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,55 @@ The format is based on the regulated environment requirements:
99

1010
---
1111

12+
## [2026-05-02 12:00] - warp 0.4.2 migration (PR #52 follow-up)
13+
14+
**Author:** Erick Bourgeois
15+
16+
### Changed
17+
- `Cargo.toml`: pin `warp = { version = "0.4", default-features = false, features = ["server"] }`.
18+
warp 0.4 made every previously-default feature opt-in; we only need
19+
`server` (used by `src/main.rs::run_metrics_server` and
20+
`src/health.rs::start_health_server`). `default-features = false`
21+
also drops `multipart`, `websocket`, and `test`, which we don't
22+
use, shrinking the supply-chain surface visible to cargo-deny /
23+
Grype / auto-VEX.
24+
- `src/health.rs`: every closure body that returned `&'static str`
25+
now returns `String` (warp 0.4's `Reply` impl on `&str` is gated
26+
to `&'static str` only and the if/else inference would otherwise
27+
pick a non-'static lifetime). Final filter chain calls `.boxed()`
28+
to type-erase into `BoxedFilter` — without it the filter type
29+
carries a higher-ranked `AsRef<str>` bound from the new generic
30+
`path::path<P: AsRef<str>>` signature, which propagates through
31+
`tokio::spawn` and fails `Send + 'static`.
32+
- `src/main.rs`: `warp::serve(metrics.boxed())` for the same
33+
HRTB / Send reason as health.rs.
34+
- `Cargo.lock`: regenerated (warp 0.3.7 → 0.4.2; drops the legacy
35+
hyper 0.14 / http 0.2 / h2 0.3 / base64 0.21 / encoding_rs /
36+
displaydoc duplicate-stack now that warp pulls hyper 1).
37+
38+
### Why
39+
PR #52 (Dependabot) bumped warp 0.3 → 0.4; the upstream release is
40+
breaking (server/test feature-gated, hyper 1 underneath, narrower
41+
Reply bounds, generic `path()`). The bump is the unfinished tail of
42+
the auto-VEX Phase 3 work in `5spot-automated-vex-generation.md`
43+
warp 0.3 sits on hyper 0.14 which is end-of-life upstream and visible
44+
to the supply-chain scanners tracked in
45+
`5spot-code-scanning-remediation.md`.
46+
47+
### Impact
48+
- [ ] Breaking change (no API surface change; internal-only)
49+
- [x] Requires cluster rollout (new binary)
50+
- [ ] Config change only
51+
- [ ] Documentation only
52+
53+
### Verification
54+
- `cargo build` clean.
55+
- `cargo test`: 397 passed, 0 failed.
56+
- `cargo fmt --check`: clean.
57+
- `cargo clippy --all-targets -- -D warnings`: clean.
58+
59+
---
60+
1261
## [2026-04-26 00:30] - Phase 4 of security audit: reclaim-agent host-identity verification
1362

1463
**Author:** Erick Bourgeois

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ http-body-util = "0.1"
4949
tower = "0.5"
5050
regex = "1"
5151
lazy_static = "1.5"
52-
warp = "0.4"
52+
# warp 0.4 made every previously-default feature opt-in. We use
53+
# `warp::serve` for the metrics + health/readiness HTTP servers
54+
# (src/main.rs and src/health.rs), so the `server` feature must be
55+
# enabled explicitly.
56+
warp = { version = "0.4", default-features = false, features = ["server"] }
5357
toml = "1.1"
5458

5559
[[bin]]

src/health.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,24 +95,37 @@ pub async fn start_health_server(port: u16, health_state: HealthState) {
9595
let health_state_status = health_state;
9696

9797
// /healthz - Kubernetes liveness probe
98-
// Returns 200 if the process is alive
98+
// Returns 200 if the process is alive.
99+
//
100+
// Body type is `String` (not `&str`) because `Reply` is only implemented
101+
// for `&'static str`; using owned `String` avoids inferring a non-'static
102+
// closure return type. The `.boxed()` on the final filter chain is the
103+
// companion fix — without it, the warp 0.4 filter type carries a higher-
104+
// ranked `AsRef<str>` bound that propagates through `tokio::spawn` and
105+
// fails `Send + 'static`.
99106
let healthz = warp::path("healthz").map(move || {
100107
if health_state_healthz.is_healthy() {
101-
warp::reply::with_status("OK", warp::http::StatusCode::OK)
108+
warp::reply::with_status("OK".to_string(), warp::http::StatusCode::OK)
102109
} else {
103110
error!("Health check failed");
104-
warp::reply::with_status("UNHEALTHY", warp::http::StatusCode::SERVICE_UNAVAILABLE)
111+
warp::reply::with_status(
112+
"UNHEALTHY".to_string(),
113+
warp::http::StatusCode::SERVICE_UNAVAILABLE,
114+
)
105115
}
106116
});
107117

108118
// /readyz - Kubernetes readiness probe
109-
// Returns 200 if the controller is ready to serve traffic
119+
// Returns 200 if the controller is ready to serve traffic.
110120
let readyz = warp::path("readyz").map(move || {
111121
if health_state_readyz.is_ready() {
112-
warp::reply::with_status("OK", warp::http::StatusCode::OK)
122+
warp::reply::with_status("OK".to_string(), warp::http::StatusCode::OK)
113123
} else {
114124
debug!("Readiness check failed - controller not ready");
115-
warp::reply::with_status("NOT READY", warp::http::StatusCode::SERVICE_UNAVAILABLE)
125+
warp::reply::with_status(
126+
"NOT READY".to_string(),
127+
warp::http::StatusCode::SERVICE_UNAVAILABLE,
128+
)
116129
}
117130
});
118131

@@ -122,17 +135,18 @@ pub async fn start_health_server(port: u16, health_state: HealthState) {
122135
warp::reply::json(&status)
123136
});
124137

125-
// Legacy endpoints for backward compatibility
126-
let health_legacy =
127-
warp::path("health").map(|| warp::reply::with_status("OK", warp::http::StatusCode::OK));
128-
let ready_legacy =
129-
warp::path("ready").map(|| warp::reply::with_status("OK", warp::http::StatusCode::OK));
138+
// Legacy endpoints for backward compatibility.
139+
let health_legacy = warp::path("health")
140+
.map(|| warp::reply::with_status("OK".to_string(), warp::http::StatusCode::OK));
141+
let ready_legacy = warp::path("ready")
142+
.map(|| warp::reply::with_status("OK".to_string(), warp::http::StatusCode::OK));
130143

131144
let routes = healthz
132145
.or(readyz)
133146
.or(status)
134147
.or(health_legacy)
135-
.or(ready_legacy);
148+
.or(ready_legacy)
149+
.boxed();
136150

137151
warp::serve(routes).run(([0, 0, 0, 0], port)).await;
138152
}

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ async fn run_metrics_server(port: u16) {
406406
}
407407
});
408408

409-
warp::serve(metrics).run(([0, 0, 0, 0], port)).await;
409+
warp::serve(metrics.boxed()).run(([0, 0, 0, 0], port)).await;
410410
}
411411

412412
#[cfg(test)]

0 commit comments

Comments
 (0)