diff --git a/.claude/CHANGELOG.md b/.claude/CHANGELOG.md index 5e3ec50..649e506 100644 --- a/.claude/CHANGELOG.md +++ b/.claude/CHANGELOG.md @@ -9,76 +9,53 @@ The format is based on the regulated environment requirements: --- -## [2026-04-30 14:00] - Phases 5 + 6 of security audit: RBAC tightening + defence-in-depth docs - -**Author:** Erick Bourgeois - -### Changed (Phase 5 — RBAC tightening) -- `deploy/deployment/rbac/clusterrole.yaml`: removed `update` verb from - the `nodes` rule. Audit of `src/reconcilers/` confirmed every Node - touchpoint uses `.get` or `.patch` only — cordon, reclaim-agent - label, applied taints, drain-related reads. Granting only the verbs - actually exercised reduces blast radius if the controller's - ServiceAccount token is compromised. -- `deploy/deployment/rbac/clusterrole.yaml`: documented why the - `update` verb is **retained** on `coordination.k8s.io/leases` — - `kube_lease_manager` (the upstream leader-election library used in - `src/main.rs`) currently uses HTTP PUT semantics on lease renewal. - Dropping `update` would break leader election. Tracked alongside the - Phase 5 entry in the security audit roadmap; will be removed when - the upstream library switches to merge-patch. - -### Changed (Phase 6 — defence-in-depth + documentation) -- `src/reconcilers/helpers.rs` (`add_machine_to_cluster`): added a - `debug_assert_eq!` at the top guarding the same-namespace ownerRef - contract (bootstrap/infra/Machine MUST be created in the SM's own - namespace; Kubernetes' GC silently ignores cross-namespace - ownerReferences). Rustdoc gained a new `# Invariants` section - explaining why the assertion exists and what would break without it. -- `src/crd.rs` (`EmbeddedResource` rustdoc): expanded the doc comment - to document the pass-through trust boundary explicitly — the - reconciler validates the envelope (`apiVersion` group allowlist, - `kind`) but does NOT inspect provider-specific fields like - k0smotron's `cloudInit` or `RemoteMachine.address`. Operators in - multi-tenant clusters must layer a complementary policy. -- `docs/src/concepts/scheduled-machine.md`: new "Security: Provider - payload pass-through" section before the "Related" links. Spells - out the trust boundary, names the high-risk fields per provider - (k0smotron cloudInit, RemoteMachine address), and gives three - concrete remediation options for multi-tenant operators (pre-stage - approved specs, layer CEL policy, scope `create` to trusted teams). -- `docs/src/security/crd-attack-surface.md`: new page. Per-field - validation status and downstream sinks for every attacker-controllable - field on the CRD (spec + status), framed against the "namespace-scoped - tenant with `create scheduledmachines`" threat model. Marks - `bootstrapSpec.spec` and `infrastructureSpec.spec` as intentional - pass-throughs and points at the narrative section. Notes that the - status fields are no longer used for security-critical routing as of - Phase 3 of this audit. -- `docs/src/security/index.md`: added the new page to the Documents - list. -- `docs/mkdocs.yml`: registered the new page in the Security nav. - -### Why -Phase 5 of the 2026-04-25 security audit roadmap closes the over-broad -`update` verb on `nodes` (a long-standing finding from the cluster-role -audit). Phase 6 surfaces two latent invariants — the same-namespace -ownerRef contract and the provider-payload pass-through trust -boundary — that today are correct by convention but were not -documented anywhere a future refactor would notice. Both now have a -loud failure mode: the `debug_assert!` for the ownerRef, and a -discoverable docs page for the pass-through. - -### Impact -- [ ] Breaking change -- [x] Requires cluster rollout (the controller's ClusterRole no - longer requests `update` on `nodes` — existing deployments - should `kubectl apply` the new manifest. No code-side change is - required; the controller already only uses verbs it is now - granted.) +## [2026-05-02 12:00] - warp 0.4.2 migration (PR #52 follow-up) + +**Author:** Erick Bourgeois + +### Changed +- `Cargo.toml`: pin `warp = { version = "0.4", default-features = false, features = ["server"] }`. + warp 0.4 made every previously-default feature opt-in; we only need + `server` (used by `src/main.rs::run_metrics_server` and + `src/health.rs::start_health_server`). `default-features = false` + also drops `multipart`, `websocket`, and `test`, which we don't + use, shrinking the supply-chain surface visible to cargo-deny / + Grype / auto-VEX. +- `src/health.rs`: every closure body that returned `&'static str` + now returns `String` (warp 0.4's `Reply` impl on `&str` is gated + to `&'static str` only and the if/else inference would otherwise + pick a non-'static lifetime). Final filter chain calls `.boxed()` + to type-erase into `BoxedFilter` — without it the filter type + carries a higher-ranked `AsRef` bound from the new generic + `path::path>` signature, which propagates through + `tokio::spawn` and fails `Send + 'static`. +- `src/main.rs`: `warp::serve(metrics.boxed())` for the same + HRTB / Send reason as health.rs. +- `Cargo.lock`: regenerated (warp 0.3.7 → 0.4.2; drops the legacy + hyper 0.14 / http 0.2 / h2 0.3 / base64 0.21 / encoding_rs / + displaydoc duplicate-stack now that warp pulls hyper 1). + +### Why +PR #52 (Dependabot) bumped warp 0.3 → 0.4; the upstream release is +breaking (server/test feature-gated, hyper 1 underneath, narrower +Reply bounds, generic `path()`). The bump is the unfinished tail of +the auto-VEX Phase 3 work in `5spot-automated-vex-generation.md` — +warp 0.3 sits on hyper 0.14 which is end-of-life upstream and visible +to the supply-chain scanners tracked in +`5spot-code-scanning-remediation.md`. + +### Impact +- [ ] Breaking change (no API surface change; internal-only) +- [x] Requires cluster rollout (new binary) - [ ] Config change only - [ ] Documentation only +### Verification +- `cargo build` clean. +- `cargo test`: 397 passed, 0 failed. +- `cargo fmt --check`: clean. +- `cargo clippy --all-targets -- -D warnings`: clean. + --- ## [2026-04-26 00:30] - Phase 4 of security audit: reclaim-agent host-identity verification diff --git a/Cargo.lock b/Cargo.lock index 292d403..b4b5747 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,12 +163,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -196,12 +190,6 @@ version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.11.1" @@ -425,17 +413,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "downcast" version = "0.11.0" @@ -466,15 +443,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "enum-ordinalize" version = "4.3.2" @@ -575,9 +543,9 @@ dependencies = [ "chrono-tz", "clap", "futures", - "http 1.4.0", + "http", "http-body-util", - "hyper 1.9.0", + "hyper", "hyper-util", "k8s-openapi", "kube", @@ -785,25 +753,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.13" @@ -815,7 +764,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http", "indexmap", "slab", "tokio", @@ -851,14 +800,14 @@ checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "headers" -version = "0.3.9" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" dependencies = [ - "base64 0.21.7", + "base64", "bytes", "headers-core", - "http 0.2.12", + "http", "httpdate", "mime", "sha1", @@ -866,11 +815,11 @@ dependencies = [ [[package]] name = "headers-core" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 0.2.12", + "http", ] [[package]] @@ -896,17 +845,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.4.0" @@ -917,17 +855,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -935,7 +862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http", ] [[package]] @@ -946,8 +873,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -963,30 +890,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.27", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.9.0" @@ -997,9 +900,9 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2 0.4.13", - "http 1.4.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -1015,8 +918,8 @@ version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "http 1.4.0", - "hyper 1.9.0", + "http", + "hyper", "hyper-util", "log", "rustls", @@ -1032,7 +935,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.9.0", + "hyper", "hyper-util", "pin-project-lite", "tokio", @@ -1045,18 +948,18 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-channel", "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "hyper 1.9.0", + "http", + "http-body", + "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2", "system-configuration", "tokio", "tower-layer", @@ -1089,88 +992,6 @@ dependencies = [ "cc", ] -[[package]] -name = "icu_collections" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" - -[[package]] -name = "icu_properties" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" - -[[package]] -name = "icu_provider" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - [[package]] name = "id-arena" version = "2.3.0" @@ -1183,27 +1004,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - [[package]] name = "indexmap" version = "2.14.0" @@ -1309,7 +1109,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b326f5219dd55872a72c1b6ddd1b830b8334996c667449c29391d657d78d5e" dependencies = [ - "base64 0.22.1", + "base64", "jiff", "schemars", "serde", @@ -1335,14 +1135,14 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fcaf2d1f1a91e1805d4cd82e8333c022767ae8ffd65909bbef6802733a7dd40" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "either", "futures", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.9.0", + "hyper", "hyper-rustls", "hyper-timeout", "hyper-util", @@ -1358,7 +1158,7 @@ dependencies = [ "serde_yaml", "thiserror 2.0.18", "tokio", - "tokio-tungstenite 0.28.0", + "tokio-tungstenite", "tokio-util", "tower", "tower-http", @@ -1373,7 +1173,7 @@ checksum = "f126d2db7a8b532ec1d839ece2a71e2485dc3bbca6cc3c3f929becaa810e719e" dependencies = [ "derive_more", "form_urlencoded", - "http 1.4.0", + "http", "jiff", "json-patch", "k8s-openapi", @@ -1406,7 +1206,7 @@ checksum = "159a11dbcf655bb619f6479081e565ea889bb860c5d7d830f3ad90adc74fb90a" dependencies = [ "k8s-openapi", "kube", - "rand 0.9.4", + "rand", "thiserror 2.0.18", "tokio", "tracing", @@ -1469,12 +1269,6 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" -[[package]] -name = "litemap" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" - [[package]] name = "lock_api" version = "0.4.14" @@ -1558,24 +1352,6 @@ dependencies = [ "syn", ] -[[package]] -name = "multer" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http 0.2.12", - "httparse", - "log", - "memchr", - "mime", - "spin", - "version_check", -] - [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -1656,7 +1432,7 @@ version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64 0.22.1", + "base64", "serde_core", ] @@ -1768,15 +1544,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -dependencies = [ - "zerovec", -] - [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1911,35 +1678,14 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" -[[package]] -name = "rand" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "rand_chacha", + "rand_core", ] [[package]] @@ -1949,16 +1695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", + "rand_core", ] [[package]] @@ -2383,16 +2120,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.3" @@ -2403,18 +2130,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - [[package]] name = "strsim" version = "0.11.1" @@ -2444,17 +2159,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "system-configuration" version = "0.7.0" @@ -2576,16 +2280,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "tinystr" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tokio" version = "1.52.1" @@ -2598,7 +2292,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -2646,18 +2340,6 @@ dependencies = [ "tokio-stream", ] -[[package]] -name = "tokio-tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.21.0", -] - [[package]] name = "tokio-tungstenite" version = "0.28.0" @@ -2667,7 +2349,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.28.0", + "tungstenite", ] [[package]] @@ -2746,11 +2428,11 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "base64 0.22.1", + "base64", "bitflags", "bytes", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "mime", "pin-project-lite", "tower", @@ -2866,25 +2548,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.4.0", - "httparse", - "log", - "rand 0.8.6", - "sha1", - "thiserror 1.0.69", - "url", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.28.0" @@ -2893,10 +2556,10 @@ checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", - "http 1.4.0", + "http", "httparse", "log", - "rand 0.9.4", + "rand", "sha1", "thiserror 2.0.18", "utf-8", @@ -2944,30 +2607,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - [[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" version = "0.2.2" @@ -2997,20 +2642,21 @@ dependencies = [ [[package]] name = "warp" -version = "0.3.7" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" +checksum = "51d06d9202adc1f15d709c4f4a2069be5428aa912cc025d6f268ac441ab066b0" dependencies = [ "bytes", - "futures-channel", "futures-util", "headers", - "http 0.2.12", - "hyper 0.14.32", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", "log", "mime", "mime_guess", - "multer", "percent-encoding", "pin-project", "scoped-tls", @@ -3018,7 +2664,6 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", - "tokio-tungstenite 0.21.0", "tokio-util", "tower-service", "tracing", @@ -3388,35 +3033,6 @@ dependencies = [ "wasmparser", ] -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - -[[package]] -name = "yoke" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - [[package]] name = "zerocopy" version = "0.8.48" @@ -3437,66 +3053,12 @@ dependencies = [ "syn", ] -[[package]] -name = "zerofrom" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - [[package]] name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -[[package]] -name = "zerotrie" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "zmij" version = "1.0.21" diff --git a/Cargo.toml b/Cargo.toml index de81f36..faa9611 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,11 @@ http-body-util = "0.1" tower = "0.5" regex = "1" lazy_static = "1.5" -warp = "0.3" +# warp 0.4 made every previously-default feature opt-in. We use +# `warp::serve` for the metrics + health/readiness HTTP servers +# (src/main.rs and src/health.rs), so the `server` feature must be +# enabled explicitly. +warp = { version = "0.4", default-features = false, features = ["server"] } toml = "1.1" [[bin]] diff --git a/src/health.rs b/src/health.rs index eb832e5..d924dd1 100644 --- a/src/health.rs +++ b/src/health.rs @@ -95,24 +95,37 @@ pub async fn start_health_server(port: u16, health_state: HealthState) { let health_state_status = health_state; // /healthz - Kubernetes liveness probe - // Returns 200 if the process is alive + // Returns 200 if the process is alive. + // + // Body type is `String` (not `&str`) because `Reply` is only implemented + // for `&'static str`; using owned `String` avoids inferring a non-'static + // closure return type. The `.boxed()` on the final filter chain is the + // companion fix — without it, the warp 0.4 filter type carries a higher- + // ranked `AsRef` bound that propagates through `tokio::spawn` and + // fails `Send + 'static`. let healthz = warp::path("healthz").map(move || { if health_state_healthz.is_healthy() { - warp::reply::with_status("OK", warp::http::StatusCode::OK) + warp::reply::with_status("OK".to_string(), warp::http::StatusCode::OK) } else { error!("Health check failed"); - warp::reply::with_status("UNHEALTHY", warp::http::StatusCode::SERVICE_UNAVAILABLE) + warp::reply::with_status( + "UNHEALTHY".to_string(), + warp::http::StatusCode::SERVICE_UNAVAILABLE, + ) } }); // /readyz - Kubernetes readiness probe - // Returns 200 if the controller is ready to serve traffic + // Returns 200 if the controller is ready to serve traffic. let readyz = warp::path("readyz").map(move || { if health_state_readyz.is_ready() { - warp::reply::with_status("OK", warp::http::StatusCode::OK) + warp::reply::with_status("OK".to_string(), warp::http::StatusCode::OK) } else { debug!("Readiness check failed - controller not ready"); - warp::reply::with_status("NOT READY", warp::http::StatusCode::SERVICE_UNAVAILABLE) + warp::reply::with_status( + "NOT READY".to_string(), + warp::http::StatusCode::SERVICE_UNAVAILABLE, + ) } }); @@ -122,17 +135,18 @@ pub async fn start_health_server(port: u16, health_state: HealthState) { warp::reply::json(&status) }); - // Legacy endpoints for backward compatibility - let health_legacy = - warp::path("health").map(|| warp::reply::with_status("OK", warp::http::StatusCode::OK)); - let ready_legacy = - warp::path("ready").map(|| warp::reply::with_status("OK", warp::http::StatusCode::OK)); + // Legacy endpoints for backward compatibility. + let health_legacy = warp::path("health") + .map(|| warp::reply::with_status("OK".to_string(), warp::http::StatusCode::OK)); + let ready_legacy = warp::path("ready") + .map(|| warp::reply::with_status("OK".to_string(), warp::http::StatusCode::OK)); let routes = healthz .or(readyz) .or(status) .or(health_legacy) - .or(ready_legacy); + .or(ready_legacy) + .boxed(); warp::serve(routes).run(([0, 0, 0, 0], port)).await; } diff --git a/src/main.rs b/src/main.rs index 9326dfd..a9b4e50 100644 --- a/src/main.rs +++ b/src/main.rs @@ -406,7 +406,7 @@ async fn run_metrics_server(port: u16) { } }); - warp::serve(metrics).run(([0, 0, 0, 0], port)).await; + warp::serve(metrics.boxed()).run(([0, 0, 0, 0], port)).await; } #[cfg(test)]