safety_qualification.rs (10873B)
1 use std::collections::BTreeSet; 2 use std::fs; 3 use std::path::Path; 4 use std::process::Command; 5 6 use serde::Deserialize; 7 8 const CONTRACT_PATH: &str = "contracts/releases/safety_matrix.toml"; 9 10 #[derive(Debug, Deserialize)] 11 struct Contract { 12 schema_version: u16, 13 toolchain: String, 14 miri_flags: Vec<String>, 15 miri: Vec<MiriLane>, 16 sanitizer: Vec<SanitizerLane>, 17 exception: Vec<Exception>, 18 } 19 20 #[derive(Debug, Deserialize)] 21 struct MiriLane { 22 package: String, 23 filter: String, 24 authority: String, 25 } 26 27 #[derive(Debug, Deserialize)] 28 struct SanitizerLane { 29 kind: String, 30 targets: Vec<String>, 31 packages: Vec<String>, 32 authority: String, 33 } 34 35 #[derive(Debug, Deserialize)] 36 struct Exception { 37 lane: String, 38 targets: Vec<String>, 39 owner: String, 40 expires: String, 41 reason: String, 42 } 43 44 #[derive(Debug, Deserialize)] 45 struct Metadata { 46 packages: Vec<MetadataPackage>, 47 } 48 49 #[derive(Debug, Deserialize)] 50 struct MetadataPackage { 51 name: String, 52 } 53 54 pub fn run(root: &Path) -> Result<(), String> { 55 let contract = load(root)?; 56 let packages = workspace_packages(root)?; 57 validate(&contract, &packages)?; 58 qualify_miri(root, &contract)?; 59 qualify_sanitizers(root, &contract)?; 60 Ok(()) 61 } 62 63 fn load(root: &Path) -> Result<Contract, String> { 64 let path = root.join(CONTRACT_PATH); 65 let raw = fs::read_to_string(&path) 66 .map_err(|error| format!("failed to read {}: {error}", path.display()))?; 67 toml::from_str(&raw).map_err(|error| format!("failed to parse {}: {error}", path.display())) 68 } 69 70 fn workspace_packages(root: &Path) -> Result<BTreeSet<String>, String> { 71 let output = Command::new("cargo") 72 .args(["metadata", "--format-version", "1", "--no-deps", "--locked"]) 73 .current_dir(root) 74 .output() 75 .map_err(|error| format!("failed to start cargo metadata: {error}"))?; 76 if !output.status.success() { 77 return Err("cargo metadata failed while validating the safety matrix".to_owned()); 78 } 79 let metadata: Metadata = serde_json::from_slice(&output.stdout) 80 .map_err(|error| format!("failed to decode cargo metadata: {error}"))?; 81 Ok(metadata 82 .packages 83 .into_iter() 84 .map(|package| package.name) 85 .collect()) 86 } 87 88 fn validate(contract: &Contract, packages: &BTreeSet<String>) -> Result<(), String> { 89 if contract.schema_version != 1 90 || !contract.toolchain.starts_with("nightly-") 91 || contract.miri_flags != ["-Zmiri-strict-provenance", "-Zmiri-disable-isolation"] 92 || contract.miri.len() != 8 93 || contract.sanitizer.len() != 1 94 { 95 return Err("invalid safety qualification contract".to_owned()); 96 } 97 98 let miri = contract 99 .miri 100 .iter() 101 .map(|lane| (&lane.package, &lane.filter)) 102 .collect::<BTreeSet<_>>(); 103 if miri.len() != contract.miri.len() { 104 return Err("Miri package/filter pairs must be unique".to_owned()); 105 } 106 for lane in &contract.miri { 107 validate_identifier("Miri package", &lane.package)?; 108 validate_test_filter(&lane.filter)?; 109 validate_authority(&lane.authority)?; 110 if !packages.contains(&lane.package) { 111 return Err(format!( 112 "Miri package {} is not in the workspace", 113 lane.package 114 )); 115 } 116 } 117 118 for lane in &contract.sanitizer { 119 if lane.kind != "address" || lane.targets.len() != 4 || lane.packages.len() != 3 { 120 return Err("native sanitizer authority must cover address checks on four hosts and three boundaries".to_owned()); 121 } 122 validate_authority(&lane.authority)?; 123 let targets = lane.targets.iter().collect::<BTreeSet<_>>(); 124 let lane_packages = lane.packages.iter().collect::<BTreeSet<_>>(); 125 if targets.len() != lane.targets.len() || lane_packages.len() != lane.packages.len() { 126 return Err("sanitizer targets and packages must be unique".to_owned()); 127 } 128 for package in &lane.packages { 129 validate_identifier("sanitizer package", package)?; 130 if !packages.contains(package) { 131 return Err(format!( 132 "sanitizer package {package} is not in the workspace" 133 )); 134 } 135 } 136 } 137 138 if contract.exception.len() != 1 { 139 return Err( 140 "the unsupported sanitizer target authority must contain one bounded exception" 141 .to_owned(), 142 ); 143 } 144 let exception = &contract.exception[0]; 145 if exception.lane != "sanitizer" 146 || exception.owner != "radroots-security" 147 || exception.expires != "2026-10-01" 148 || exception.targets.len() != 3 149 || exception.reason.trim().is_empty() 150 { 151 return Err("invalid sanitizer target exception".to_owned()); 152 } 153 Ok(()) 154 } 155 156 fn validate_identifier(label: &str, value: &str) -> Result<(), String> { 157 if value.is_empty() 158 || !value 159 .bytes() 160 .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'_') 161 { 162 return Err(format!("{label} must be a lowercase snake_case identifier")); 163 } 164 Ok(()) 165 } 166 167 fn validate_test_filter(value: &str) -> Result<(), String> { 168 let segments = value.split("::").collect::<Vec<_>>(); 169 if segments.len() < 3 { 170 return Err("Miri filter must be a fully qualified test path".to_owned()); 171 } 172 for segment in segments { 173 validate_identifier("Miri test path segment", segment)?; 174 } 175 Ok(()) 176 } 177 178 fn validate_authority(value: &str) -> Result<(), String> { 179 if value.is_empty() 180 || !value 181 .bytes() 182 .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-') 183 { 184 return Err("safety authority must be a lowercase kebab-case identifier".to_owned()); 185 } 186 Ok(()) 187 } 188 189 fn qualify_miri(root: &Path, contract: &Contract) -> Result<(), String> { 190 let flags = contract.miri_flags.join(" "); 191 for lane in &contract.miri { 192 verify_test_exists(root, lane)?; 193 let args = [ 194 format!("+{}", contract.toolchain), 195 "miri".to_owned(), 196 "test".to_owned(), 197 "--locked".to_owned(), 198 "-p".to_owned(), 199 lane.package.clone(), 200 "--lib".to_owned(), 201 lane.filter.clone(), 202 "--".to_owned(), 203 "--exact".to_owned(), 204 ]; 205 run_cargo(root, &args, &[("MIRIFLAGS", flags.as_str())], "Miri")?; 206 } 207 Ok(()) 208 } 209 210 fn verify_test_exists(root: &Path, lane: &MiriLane) -> Result<(), String> { 211 let args = [ 212 "test", 213 "--locked", 214 "-p", 215 lane.package.as_str(), 216 "--lib", 217 lane.filter.as_str(), 218 "--", 219 "--exact", 220 "--list", 221 ]; 222 let output = Command::new("cargo") 223 .args(args) 224 .current_dir(root) 225 .output() 226 .map_err(|error| format!("failed to enumerate Miri test {}: {error}", lane.filter))?; 227 if !output.status.success() { 228 return Err(format!( 229 "failed to enumerate Miri test {} in {}", 230 lane.filter, lane.package 231 )); 232 } 233 let stdout = String::from_utf8(output.stdout) 234 .map_err(|error| format!("test enumeration emitted non-UTF-8 output: {error}"))?; 235 let expected = format!("{}: test", lane.filter); 236 if stdout.lines().any(|line| line == expected) { 237 Ok(()) 238 } else { 239 Err(format!( 240 "Miri authority {} does not resolve to exactly one library test in {}", 241 lane.filter, lane.package 242 )) 243 } 244 } 245 246 fn qualify_sanitizers(root: &Path, contract: &Contract) -> Result<(), String> { 247 let host = rustc_host(root, &contract.toolchain)?; 248 let mut matched = false; 249 for lane in &contract.sanitizer { 250 if !lane.targets.iter().any(|target| target == &host) { 251 continue; 252 } 253 matched = true; 254 let mut args = vec![ 255 format!("+{}", contract.toolchain), 256 "test".to_owned(), 257 "--locked".to_owned(), 258 "--target".to_owned(), 259 host.clone(), 260 ]; 261 for package in &lane.packages { 262 args.push("-p".to_owned()); 263 args.push(package.clone()); 264 } 265 args.push("--lib".to_owned()); 266 let rustflags = format!("-Zsanitizer={}", lane.kind); 267 run_cargo( 268 root, 269 &args, 270 &[ 271 ("RUSTFLAGS", rustflags.as_str()), 272 ("RUSTDOCFLAGS", rustflags.as_str()), 273 ("ASAN_OPTIONS", "detect_leaks=1:halt_on_error=1"), 274 ], 275 "sanitizer", 276 )?; 277 } 278 if matched { 279 return Ok(()); 280 } 281 if contract 282 .exception 283 .iter() 284 .any(|exception| exception.targets.iter().any(|target| target == &host)) 285 { 286 eprintln!("sanitizer qualification excluded for governed target {host}"); 287 return Ok(()); 288 } 289 Err(format!( 290 "host {host} has neither a sanitizer lane nor a governed exception" 291 )) 292 } 293 294 fn rustc_host(root: &Path, toolchain: &str) -> Result<String, String> { 295 let output = Command::new("rustc") 296 .args([format!("+{toolchain}"), "-vV".to_owned()]) 297 .current_dir(root) 298 .output() 299 .map_err(|error| format!("failed to start rustc: {error}"))?; 300 if !output.status.success() { 301 return Err(format!("rustc +{toolchain} -vV failed")); 302 } 303 let stdout = String::from_utf8(output.stdout) 304 .map_err(|error| format!("rustc -vV emitted non-UTF-8 output: {error}"))?; 305 stdout 306 .lines() 307 .find_map(|line| line.strip_prefix("host: ").map(str::to_owned)) 308 .ok_or_else(|| "rustc -vV did not report a host target".to_owned()) 309 } 310 311 fn run_cargo( 312 root: &Path, 313 args: &[String], 314 environment: &[(&str, &str)], 315 label: &str, 316 ) -> Result<(), String> { 317 eprintln!("cargo {}", args.join(" ")); 318 let status = Command::new("cargo") 319 .args(args) 320 .envs(environment.iter().copied()) 321 .current_dir(root) 322 .status() 323 .map_err(|error| format!("failed to start {label} qualification: {error}"))?; 324 if status.success() { 325 Ok(()) 326 } else { 327 Err(format!( 328 "{label} qualification failed: cargo {}", 329 args.join(" ") 330 )) 331 } 332 } 333 334 #[cfg(test)] 335 mod tests { 336 use super::{load, validate, workspace_packages}; 337 338 #[test] 339 fn current_contract_covers_governed_safety_boundaries() { 340 let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) 341 .parent() 342 .and_then(std::path::Path::parent) 343 .expect("workspace root"); 344 let packages = workspace_packages(root).expect("workspace packages"); 345 validate(&load(root).expect("contract"), &packages).expect("valid safety matrix"); 346 } 347 }