From b60b103c0f0073693b3c6593483911b59bfb302c Mon Sep 17 00:00:00 2001 From: jedarden Date: Fri, 8 May 2026 10:17:53 -0400 Subject: [PATCH] fix(starter-rust): fix compilation errors in Rust starter kit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Clone derive to AppState for axum compatibility - Import Digest trait from sha2 for hash computation - Use String instead of &str in response headers for lifetime safety - Add Position import to grid.rs module - Make Position Copy for easier cloning - Replace constant_time_eq with custom hmac_equal function - Add musl-dev to Dockerfile for Alpine build compatibility The Rust starter kit now compiles and builds successfully with cargo check and Docker, matching the requirements from plan §5.3 and §12 (Phase 2). Co-Authored-By: Claude Opus 4.7 --- .needle-predispatch-sha | 2 +- starters/rust/Dockerfile | 2 +- starters/rust/src/grid.rs | 1 + starters/rust/src/main.rs | 34 ++++++++++++++++++++-------------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/.needle-predispatch-sha b/.needle-predispatch-sha index 8ff8409..01032eb 100644 --- a/.needle-predispatch-sha +++ b/.needle-predispatch-sha @@ -1 +1 @@ -b31c306013e5d99cdf1224c14c7ff887139f187d +dff235e19318f50109a3f29edcd1f01b6cc94857 diff --git a/starters/rust/Dockerfile b/starters/rust/Dockerfile index 7b4b723..0ec0b04 100644 --- a/starters/rust/Dockerfile +++ b/starters/rust/Dockerfile @@ -4,7 +4,7 @@ WORKDIR /app COPY Cargo.toml ./ COPY src ./src -RUN cargo build --release +RUN apk add --no-cache musl-dev && cargo build --release FROM alpine:3.21 diff --git a/starters/rust/src/grid.rs b/starters/rust/src/grid.rs index f8d44fb..bb11caf 100644 --- a/starters/rust/src/grid.rs +++ b/starters/rust/src/grid.rs @@ -3,6 +3,7 @@ //! Provides toroidal distance calculations, neighbor enumeration, //! and BFS pathfinding on a wrapping grid. +use crate::Position; use std::collections::{HashMap, VecDeque}; /// Manhattan distance with wrap-around on a toroidal grid. diff --git a/starters/rust/src/main.rs b/starters/rust/src/main.rs index 469106b..7c11278 100644 --- a/starters/rust/src/main.rs +++ b/starters/rust/src/main.rs @@ -10,11 +10,11 @@ use axum::{ extract::State, http::{HeaderMap, StatusCode}, routing::{get, post}, - Json, Router, + Router, }; use hmac::{Hmac, Mac}; use serde::{Deserialize, Serialize}; -use sha2::Sha256; +use sha2::{Digest, Sha256}; use std::env; type HmacSha256 = Hmac; @@ -57,7 +57,7 @@ struct You { score: u32, } -#[derive(Deserialize, Serialize, Clone)] +#[derive(Deserialize, Serialize, Clone, Copy, PartialEq, Eq)] pub struct Position { pub row: u32, pub col: u32, @@ -87,6 +87,7 @@ struct Move { direction: String, } +#[derive(Clone)] struct AppState { secret: String, } @@ -117,7 +118,7 @@ async fn handle_turn( State(state): State, headers: HeaderMap, body: Bytes, -) -> Result<(StatusCode, [(&str, String); 2], String), StatusCode> { +) -> Result<(StatusCode, [(String, String); 2], String), StatusCode> { let signature = headers .get("X-ACB-Signature") .and_then(|v| v.to_str().ok()) @@ -171,8 +172,8 @@ async fn handle_turn( Ok(( StatusCode::OK, [ - ("Content-Type".to_string(), "application/json".to_string()), - ("X-ACB-Signature".to_string(), response_sig), + ("Content-Type".to_owned(), "application/json".to_owned()), + ("X-ACB-Signature".to_owned(), response_sig), ], response_body, )) @@ -241,7 +242,6 @@ fn verify_signature( body: &[u8], signature: &str, ) -> bool { - use hex::FromHex; let body_hash = sha2::Sha256::digest(body); let signing_string = format!( "{}.{}.{}.{}", @@ -254,15 +254,21 @@ fn verify_signature( let mut mac = HmacSha256::new_from_slice(secret.as_bytes()).expect("HMAC key error"); mac.update(signing_string.as_bytes()); - let expected = mac.finalize().into_bytes(); + let expected = hex::encode(mac.finalize().into_bytes()); - match Vec::from_hex(signature) { - Ok(sig_bytes) => { - let sig_truncated: &[u8] = &sig_bytes; - hmac::digest::constant_time_eq(sig_truncated, &expected) - } - Err(_) => false, + hmac_equal(signature, &expected) +} + +/// Constant-time string comparison +fn hmac_equal(a: &str, b: &str) -> bool { + if a.len() != b.len() { + return false; } + a.as_bytes() + .iter() + .zip(b.as_bytes().iter()) + .fold(0, |acc, (x, y)| acc | (x ^ y)) + == 0 } fn sign_response(secret: &str, match_id: &str, turn: u32, body: &[u8]) -> String {