diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 384750d..e359336 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,9 +79,9 @@ jobs: with: repository: pulseengine/relay path: relay - - uses: dtolnay/rust-toolchain@master - with: - toolchain: "1.85.0" + # Kani-verifier (the installer) needs newer Rust than our MSRV. + # Kani itself uses an internal nightly for the proofs. + - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 with: workspaces: wohl @@ -128,7 +128,10 @@ jobs: workspaces: wohl key: fuzz - name: Install cargo-fuzz - run: cargo install --locked cargo-fuzz + # NOT --locked: cargo-fuzz 0.13.1's lockfile pins rustix 0.36.5 which + # uses unstable rustc_attrs that current nightly no longer accepts. + # Unlocked resolution picks newer rustix that compiles cleanly. + run: cargo install cargo-fuzz - name: Fuzz fuzz_leak working-directory: wohl run: cargo fuzz run fuzz_leak -- -max_total_time=60 @@ -147,9 +150,8 @@ jobs: with: repository: pulseengine/rivet path: rivet - - uses: dtolnay/rust-toolchain@master - with: - toolchain: "1.85.0" + # rivet-cli's deps need Rust 1.89+; we don't care about MSRV for tooling. + - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 with: workspaces: rivet diff --git a/crates/wohl-air/plain/src/engine.rs b/crates/wohl-air/plain/src/engine.rs index f596bd3..ffd3a84 100644 --- a/crates/wohl-air/plain/src/engine.rs +++ b/crates/wohl-air/plain/src/engine.rs @@ -117,7 +117,7 @@ impl AirMonitor { return false; } - let base = config.zone_id * 6; + let base = config.zone_id.saturating_mul(6); let thresholds = [ config.co2_warn, config.co2_critical, @@ -148,7 +148,7 @@ impl AirMonitor { alerts: [AirAlert::empty(); MAX_ALERTS_PER_READING], alert_count: 0, }; - let base = reading.zone_id * 6; + let base = reading.zone_id.saturating_mul(6); let values = [ reading.co2_ppm, reading.co2_ppm, diff --git a/crates/wohl-leak/plain/src/engine.rs b/crates/wohl-leak/plain/src/engine.rs index 8ca7286..79af308 100644 --- a/crates/wohl-leak/plain/src/engine.rs +++ b/crates/wohl-leak/plain/src/engine.rs @@ -75,19 +75,16 @@ impl LeakDetector { if wet { if was_wet { return LeakAction::AlreadyWet; - } else { - self.zones[idx].wet = true; - self.zones[idx].detected_at = timestamp_sec; - return LeakAction::NewLeak; - } - } else { - if was_wet { - self.zones[idx].wet = false; - return LeakAction::Cleared; - } else { - return LeakAction::AlreadyDry; } + self.zones[idx].wet = true; + self.zones[idx].detected_at = timestamp_sec; + return LeakAction::NewLeak; + } + if was_wet { + self.zones[idx].wet = false; + return LeakAction::Cleared; } + return LeakAction::AlreadyDry; } i += 1; } diff --git a/crates/wohl-temp/plain/src/engine.rs b/crates/wohl-temp/plain/src/engine.rs index 38a2282..15a937a 100644 --- a/crates/wohl-temp/plain/src/engine.rs +++ b/crates/wohl-temp/plain/src/engine.rs @@ -102,11 +102,14 @@ impl TempAlert { // Watchpoint ID encoding: zone_id * 2 + offset // offset 0 = freeze watchpoint (LessOrEqual) // offset 1 = overheat watchpoint (GreaterOrEqual) +// Uses saturating_mul/add so adversarial u32 zone_ids cannot panic on overflow. +// Real zone_ids are bounded by MAX_ZONES (32), so saturation only affects +// pathological inputs and never collides in practice. fn freeze_wp_id(zone_id: u32) -> u32 { - zone_id * 2 + zone_id.saturating_mul(2) } fn overheat_wp_id(zone_id: u32) -> u32 { - zone_id * 2 + 1 + zone_id.saturating_mul(2).saturating_add(1) } impl Default for TemperatureMonitor {