mirror of
https://github.com/ruvnet/RuView
synced 2026-08-08 20:11:43 +00:00
fix(security): audit — fix RUSTSEC vulns, clippy warnings, dead code (#769)
- Upgrade openssl to 0.10.78 (CVE-2026-41676), jsonwebtoken to 9.4 - Suppress unmaintained-only/no-CVE advisories in .cargo/audit.toml with per-entry rationale - Fix all `cargo clippy --all-targets -- -D warnings` errors across 35 crates: derivable_impls, needless_range_loop, map_or→is_some_and/ is_none_or, await_holding_lock (drop MutexGuard before .await), ptr_arg (&mut Vec→&mut [T]), useless_conversion, approximate_constant (2.718→E, 3.14→PI), field_reassign_with_default, manual_inspect, useless_vec, lines_filter_map_ok, print_literal, dead_code - Apply `cargo fmt --all` - Pre-existing test failure in wifi-densepose-signal (test_estimate_occupancy_noise_only) is not introduced by this PR
This commit is contained in:
@@ -238,9 +238,6 @@ mod tests {
|
||||
let x = (2.0 * std::f64::consts::PI * f_off * t).cos();
|
||||
last = lockin.process(x);
|
||||
}
|
||||
assert!(
|
||||
last.abs() < 0.1,
|
||||
"off-resonance output {last} should be ~0"
|
||||
);
|
||||
assert!(last.abs() < 0.1, "off-resonance output {last} should be ~0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +217,10 @@ mod tests {
|
||||
let mut bytes = MagFrame::empty(0).to_bytes();
|
||||
bytes[4..6].copy_from_slice(&99_u16.to_le_bytes());
|
||||
let err = MagFrame::from_bytes(&bytes).unwrap_err();
|
||||
assert!(matches!(err, crate::NvsimError::UnsupportedVersion { got: 99, .. }));
|
||||
assert!(matches!(
|
||||
err,
|
||||
crate::NvsimError::UnsupportedVersion { got: 99, .. }
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -18,7 +18,7 @@ use crate::sensor::{NvSensor, NvSensorConfig};
|
||||
use crate::source::scene_field_at;
|
||||
|
||||
/// Pipeline configuration.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
|
||||
pub struct PipelineConfig {
|
||||
/// Sensor / digitiser sampling parameters.
|
||||
pub digitiser: DigitiserConfig,
|
||||
@@ -28,16 +28,6 @@ pub struct PipelineConfig {
|
||||
pub dt_s: Option<f64>,
|
||||
}
|
||||
|
||||
impl Default for PipelineConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
digitiser: DigitiserConfig::default(),
|
||||
sensor: NvSensorConfig::default(),
|
||||
dt_s: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Forward-only NV-diamond pipeline.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Pipeline {
|
||||
@@ -50,14 +40,21 @@ impl Pipeline {
|
||||
/// Construct a pipeline. `seed` makes shot-noise reproducible — same
|
||||
/// `(scene, config, seed)` produces byte-identical output.
|
||||
pub fn new(scene: Scene, config: PipelineConfig, seed: u64) -> Self {
|
||||
Self { scene, config, seed }
|
||||
Self {
|
||||
scene,
|
||||
config,
|
||||
seed,
|
||||
}
|
||||
}
|
||||
|
||||
/// Run `n_samples` of the pipeline. Returns one [`MagFrame`] per
|
||||
/// (sensor × sample) — i.e. `n_samples · scene.sensors.len()` frames
|
||||
/// in scene-major / sample-minor order.
|
||||
pub fn run(&self, n_samples: usize) -> Vec<MagFrame> {
|
||||
let dt = self.config.dt_s.unwrap_or(1.0 / self.config.digitiser.f_s_hz);
|
||||
let dt = self
|
||||
.config
|
||||
.dt_s
|
||||
.unwrap_or(1.0 / self.config.digitiser.f_s_hz);
|
||||
let dt_us = (dt * 1.0e6) as u64;
|
||||
let nv = NvSensor::new(self.config.sensor);
|
||||
|
||||
@@ -82,11 +79,11 @@ impl Pipeline {
|
||||
// saturation flag if any axis clips.
|
||||
let mut adc_sat = false;
|
||||
let mut b_pt = [0.0_f32; 3];
|
||||
for k in 0..3 {
|
||||
for (k, b) in b_pt.iter_mut().enumerate() {
|
||||
let (code, sat) = adc_quantise(reading.b_recovered[k]);
|
||||
adc_sat |= sat;
|
||||
let recovered_t = code as f64 * crate::digitiser::ADC_LSB_T;
|
||||
b_pt[k] = (recovered_t * 1.0e12) as f32; // T → pT
|
||||
*b = (recovered_t * 1.0e12) as f32; // T → pT
|
||||
}
|
||||
let sigma_pt = [
|
||||
(reading.sigma_per_axis[0] * 1.0e12) as f32,
|
||||
@@ -98,8 +95,7 @@ impl Pipeline {
|
||||
frame.t_us = (sample as u64) * dt_us;
|
||||
frame.b_pt = b_pt;
|
||||
frame.sigma_pt = sigma_pt;
|
||||
frame.noise_floor_pt_sqrt_hz =
|
||||
(reading.noise_floor_t_sqrt_hz * 1.0e12) as f32;
|
||||
frame.noise_floor_pt_sqrt_hz = (reading.noise_floor_t_sqrt_hz * 1.0e12) as f32;
|
||||
frame.temperature_k = 295.0;
|
||||
if near_field {
|
||||
frame.set_flag(flag::SATURATION_NEAR_FIELD);
|
||||
@@ -198,11 +194,11 @@ mod tests {
|
||||
let (b_analytic, _) = scene_field_at(&scene, scene.sensors[0]);
|
||||
for f in &frames {
|
||||
assert!(f.has_flag(flag::SHOT_NOISE_DISABLED));
|
||||
for k in 0..3 {
|
||||
let recovered_t = f.b_pt[k] as f64 * 1.0e-12;
|
||||
for (k, (&b_pt, &b_ref)) in f.b_pt.iter().zip(b_analytic.iter()).enumerate() {
|
||||
let recovered_t = b_pt as f64 * 1.0e-12;
|
||||
let lsb_t = crate::digitiser::ADC_LSB_T;
|
||||
assert!(
|
||||
(recovered_t - b_analytic[k]).abs() <= lsb_t,
|
||||
(recovered_t - b_ref).abs() <= lsb_t,
|
||||
"noise-off recovery error > 1 LSB for axis {k}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -58,12 +58,12 @@ pub struct LosSegment {
|
||||
pub fn material_loss_db_per_m(m: Material) -> f64 {
|
||||
match m {
|
||||
Material::Air => 0.0,
|
||||
Material::Drywall => 0.0, // conjecture: gypsum non-ferromagnetic
|
||||
Material::Brick => 0.0, // conjecture: same logic as drywall
|
||||
Material::ConcreteDry => 0.5, // conjecture: Ulrich 2002 proxy
|
||||
Material::Drywall => 0.0, // conjecture: gypsum non-ferromagnetic
|
||||
Material::Brick => 0.0, // conjecture: same logic as drywall
|
||||
Material::ConcreteDry => 0.5, // conjecture: Ulrich 2002 proxy
|
||||
Material::ReinforcedConcrete => 20.0, // proxy + warning flag (plan §2.2)
|
||||
Material::SheetSteel => 100.0, // frequency-dependent in reality;
|
||||
// representative DC bulk loss
|
||||
Material::SheetSteel => 100.0, // frequency-dependent in reality;
|
||||
// representative DC bulk loss
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,10 +92,7 @@ pub fn attenuate(b_in: Vec3, segments: &[LosSegment]) -> (Vec3, bool) {
|
||||
heavy |= material_is_heavy(seg.material);
|
||||
}
|
||||
let scale = 10.0_f64.powf(-total_db / 20.0);
|
||||
(
|
||||
[b_in[0] * scale, b_in[1] * scale, b_in[2] * scale],
|
||||
heavy,
|
||||
)
|
||||
([b_in[0] * scale, b_in[1] * scale, b_in[2] * scale], heavy)
|
||||
}
|
||||
|
||||
/// Aggregate "propagator" type — currently a stateless wrapper over
|
||||
@@ -175,8 +172,8 @@ mod tests {
|
||||
}];
|
||||
let (b_out, heavy) = attenuate(b_in, &segs);
|
||||
let expected = 10.0_f64.powf(-4.0 / 20.0);
|
||||
for k in 0..3 {
|
||||
assert_relative_eq!(b_out[k], expected, max_relative = 1e-12);
|
||||
for &val in &b_out {
|
||||
assert_relative_eq!(val, expected, max_relative = 1e-12);
|
||||
}
|
||||
assert!(heavy, "reinforced concrete must raise heavy_flag");
|
||||
}
|
||||
|
||||
@@ -63,12 +63,7 @@ pub const DEFAULT_N_SPINS: f64 = 1.0e12;
|
||||
/// Tetrahedral 〈111〉 family in the diamond lattice.
|
||||
pub fn nv_axes() -> [[f64; 3]; 4] {
|
||||
let s = 1.0 / 3.0_f64.sqrt();
|
||||
[
|
||||
[s, s, s],
|
||||
[s, -s, -s],
|
||||
[-s, s, -s],
|
||||
[-s, -s, s],
|
||||
]
|
||||
[[s, s, s], [s, -s, -s], [-s, s, -s], [-s, -s, s]]
|
||||
}
|
||||
|
||||
/// Sensor configuration. All defaults match plan §2.3 / Barry 2020 Table III
|
||||
@@ -163,8 +158,9 @@ impl NvSensor {
|
||||
/// per-sample noise σ in T.
|
||||
pub fn shot_noise_floor_t_sqrt_hz(&self, integration_s: f64) -> f64 {
|
||||
let t = integration_s.max(self.config.t2_star_s);
|
||||
let denom =
|
||||
GAMMA_E * self.config.contrast * (self.config.n_spins * t * self.config.t2_star_s).sqrt();
|
||||
let denom = GAMMA_E
|
||||
* self.config.contrast
|
||||
* (self.config.n_spins * t * self.config.t2_star_s).sqrt();
|
||||
if denom <= 0.0 {
|
||||
f64::INFINITY
|
||||
} else {
|
||||
@@ -316,13 +312,10 @@ mod tests {
|
||||
];
|
||||
for &b_in in &inputs {
|
||||
let r = s.sample(b_in, 1.0e-3, 0xCAFE_BABE);
|
||||
for k in 0..3 {
|
||||
let denom = b_in[k].abs().max(1e-30);
|
||||
let rel = (r.b_recovered[k] - b_in[k]).abs() / denom;
|
||||
assert!(
|
||||
rel < 0.01,
|
||||
"LSQ residual {rel:.4} exceeds 1% for axis {k}"
|
||||
);
|
||||
for (k, (&b_recovered, &b_orig)) in r.b_recovered.iter().zip(b_in.iter()).enumerate() {
|
||||
let denom = b_orig.abs().max(1e-30);
|
||||
let rel = (b_recovered - b_orig).abs() / denom;
|
||||
assert!(rel < 0.01, "LSQ residual {rel:.4} exceeds 1% for axis {k}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,19 +331,19 @@ mod tests {
|
||||
let mut sum = [0.0_f64; 3];
|
||||
for i in 0..n {
|
||||
let r = s.sample([0.0; 3], dt, 0xDEAD_BEEF + i as u64);
|
||||
for k in 0..3 {
|
||||
sum[k] += r.b_recovered[k];
|
||||
for (s, &b) in sum.iter_mut().zip(r.b_recovered.iter()) {
|
||||
*s += b;
|
||||
}
|
||||
}
|
||||
let mean = [sum[0] / n as f64, sum[1] / n as f64, sum[2] / n as f64];
|
||||
// Stat margin: σ_mean = σ / √n. Allow ≤ 1σ_mean (loose).
|
||||
let r = s.sample([0.0; 3], dt, 0);
|
||||
let sigma_mean = r.sigma_per_axis[0] / (n as f64).sqrt();
|
||||
for k in 0..3 {
|
||||
for (k, &m) in mean.iter().enumerate() {
|
||||
assert!(
|
||||
mean[k].abs() <= sigma_mean,
|
||||
m.abs() <= sigma_mean,
|
||||
"axis {k} zero-input mean {} exceeds σ_mean {}",
|
||||
mean[k],
|
||||
m,
|
||||
sigma_mean
|
||||
);
|
||||
}
|
||||
@@ -392,6 +385,9 @@ mod tests {
|
||||
// form depends on this. Verify the matrix.
|
||||
let axes = nv_axes();
|
||||
let mut ata = [[0.0_f64; 3]; 3];
|
||||
// Compute AᵀA using explicit 2D indexing — clippy::needless_range_loop
|
||||
// cannot be avoided here without losing clarity in this matrix formula.
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for j in 0..3 {
|
||||
for k in 0..3 {
|
||||
let mut acc = 0.0;
|
||||
@@ -401,6 +397,7 @@ mod tests {
|
||||
ata[j][k] = acc;
|
||||
}
|
||||
}
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for j in 0..3 {
|
||||
for k in 0..3 {
|
||||
let expected = if j == k { 4.0 / 3.0 } else { 0.0 };
|
||||
|
||||
@@ -132,7 +132,11 @@ pub fn scene_field_at(scene: &Scene, sensor_pos: Vec3) -> (Vec3, bool) {
|
||||
|
||||
/// Total field at every sensor location in a scene, in scene order.
|
||||
pub fn scene_field_at_sensors(scene: &Scene) -> Vec<(Vec3, bool)> {
|
||||
scene.sensors.iter().map(|&p| scene_field_at(scene, p)).collect()
|
||||
scene
|
||||
.sensors
|
||||
.iter()
|
||||
.map(|&p| scene_field_at(scene, p))
|
||||
.collect()
|
||||
}
|
||||
|
||||
// ────────────────────── vec3 helpers ─────────────────────────────────────
|
||||
|
||||
@@ -46,8 +46,8 @@ impl WasmPipeline {
|
||||
pub fn new(scene_json: &str, config_json: &str, seed: f64) -> Result<WasmPipeline, JsValue> {
|
||||
let scene: Scene =
|
||||
serde_json::from_str(scene_json).map_err(|e| js_err(format!("scene parse: {e}")))?;
|
||||
let config: PipelineConfig = serde_json::from_str(config_json)
|
||||
.map_err(|e| js_err(format!("config parse: {e}")))?;
|
||||
let config: PipelineConfig =
|
||||
serde_json::from_str(config_json).map_err(|e| js_err(format!("config parse: {e}")))?;
|
||||
let seed_u64 = seed as u64;
|
||||
Ok(WasmPipeline {
|
||||
inner: Pipeline::new(scene, config, seed_u64),
|
||||
@@ -184,8 +184,8 @@ pub fn run_transient(
|
||||
) -> Result<JsValue, JsValue> {
|
||||
let scene: crate::scene::Scene =
|
||||
serde_json::from_str(scene_json).map_err(|e| js_err(format!("scene parse: {e}")))?;
|
||||
let config: crate::pipeline::PipelineConfig = serde_json::from_str(config_json)
|
||||
.map_err(|e| js_err(format!("config parse: {e}")))?;
|
||||
let config: crate::pipeline::PipelineConfig =
|
||||
serde_json::from_str(config_json).map_err(|e| js_err(format!("config parse: {e}")))?;
|
||||
let pipeline = crate::pipeline::Pipeline::new(scene, config, seed as u64);
|
||||
let (frames, witness) = pipeline.run_with_witness(n_samples);
|
||||
|
||||
@@ -217,7 +217,11 @@ pub fn run_transient(
|
||||
let s_arr = js_sys::Float64Array::new_with_length(3);
|
||||
s_arr.copy_from(&avg_s_pt);
|
||||
js_sys::Reflect::set(&obj, &JsValue::from_str("bRecoveredT"), &b_arr)?;
|
||||
js_sys::Reflect::set(&obj, &JsValue::from_str("bMagT"), &JsValue::from_f64(bmag_t))?;
|
||||
js_sys::Reflect::set(
|
||||
&obj,
|
||||
&JsValue::from_str("bMagT"),
|
||||
&JsValue::from_f64(bmag_t),
|
||||
)?;
|
||||
js_sys::Reflect::set(
|
||||
&obj,
|
||||
&JsValue::from_str("noiseFloorPtSqrtHz"),
|
||||
@@ -230,6 +234,10 @@ pub fn run_transient(
|
||||
&JsValue::from_f64(frames.len() as f64),
|
||||
)?;
|
||||
let witness_hex = crate::proof::Proof::hex(&witness);
|
||||
js_sys::Reflect::set(&obj, &JsValue::from_str("witnessHex"), &JsValue::from_str(&witness_hex))?;
|
||||
js_sys::Reflect::set(
|
||||
&obj,
|
||||
&JsValue::from_str("witnessHex"),
|
||||
&JsValue::from_str(&witness_hex),
|
||||
)?;
|
||||
Ok(obj.into())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user