commit 8eedb0a69161d8869ea986fec9905cff65b0dcd4
parent 714a918e302a5b28f6b0dbca7fe23069d6fec2c3
Author: triesap <tyson@radroots.org>
Date: Sun, 6 Sep 2026 23:17:22 +0000
chore: add governed Step 298 platform probe
- Emit the required macOS platform identity through xtask.
- Keep the execution within the frozen Cargo tool inventory.
- Bind the observation to the producing request digest.
- Preserve the authoritative root probe identity in evidence.
Diffstat:
2 files changed, 97 insertions(+), 0 deletions(-)
diff --git a/tools/xtask/src/main.rs b/tools/xtask/src/main.rs
@@ -39,6 +39,7 @@ mod release_preflight;
#[cfg_attr(coverage_nightly, coverage(off))]
mod release_qualification;
mod rshr_202_step_298_gate;
+mod rshr_202_step_298_platform;
mod safe_artifact_io;
#[cfg_attr(coverage_nightly, coverage(off))]
mod safety_qualification;
@@ -146,6 +147,11 @@ enum XtaskCommand {
#[arg(long)]
execution_request_sha256: String,
},
+ #[command(name = "rshr-step-298-platform-probe", hide = true)]
+ RshrStep298PlatformProbe {
+ #[arg(long)]
+ execution_request_sha256: String,
+ },
SourceLock {
#[arg(long)]
consumer_root: PathBuf,
@@ -606,6 +612,9 @@ fn run(args: &[String]) -> Result<(), String> {
platform,
execution_request_sha256,
}),
+ XtaskCommand::RshrStep298PlatformProbe {
+ execution_request_sha256,
+ } => rshr_202_step_298_platform::run(&execution_request_sha256),
XtaskCommand::SourceLock { consumer_root } => {
build_control::validate_consumer(&consumer_root).map(|_| ())
}
diff --git a/tools/xtask/src/rshr_202_step_298_platform.rs b/tools/xtask/src/rshr_202_step_298_platform.rs
@@ -0,0 +1,88 @@
+use std::process::Command;
+
+use serde_json::{Value, json};
+use sha2::{Digest, Sha256};
+
+const APPLE_TOOLCHAIN_IDENTITY_SHA256: &str =
+ "fd9bb9af273d0a834c2abff36910edf25f3e5b60c36fcc23b45b738c5c8b2d08";
+const PROBE_SOURCE_PATH: &str =
+ "tools/radroots_scripts/src/radroots_scripts/verify/rshr_200_series.py";
+const PROBE_SOURCE_SHA256: &str =
+ "add949c6c20a037123808230625dfd09dd6fa6c5afe5a856400227191f5de5b5";
+
+fn canonical(value: &Value) -> Result<Vec<u8>, String> {
+ serde_json::to_vec(value).map_err(|_| "Step 298 platform JSON encoding failed".to_owned())
+}
+
+fn sha256(bytes: &[u8]) -> String {
+ hex::encode(Sha256::digest(bytes))
+}
+
+fn uname(flag: &str) -> Result<String, String> {
+ let output = Command::new("/usr/bin/uname")
+ .arg(flag)
+ .output()
+ .map_err(|_| "Step 298 platform probe could not start uname".to_owned())?;
+ if !output.status.success() || !output.stderr.is_empty() {
+ return Err("Step 298 platform probe uname failed".to_owned());
+ }
+ let value = std::str::from_utf8(&output.stdout)
+ .map_err(|_| "Step 298 platform probe uname output is not UTF-8".to_owned())?
+ .strip_suffix('\n')
+ .ok_or_else(|| "Step 298 platform probe uname output differs".to_owned())?;
+ if value.is_empty() || value.contains('\n') || value.contains('\r') {
+ return Err("Step 298 platform probe uname output differs".to_owned());
+ }
+ Ok(value.to_owned())
+}
+
+pub(crate) fn run(execution_request_sha256: &str) -> Result<(), String> {
+ if execution_request_sha256.len() != 64
+ || !execution_request_sha256
+ .bytes()
+ .all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase())
+ {
+ return Err("Step 298 platform execution request differs".to_owned());
+ }
+
+ let kernel_name = uname("-s")?;
+ let kernel_release = uname("-r")?;
+ let kernel_version = uname("-v")?;
+ if kernel_name != "Darwin" || std::env::consts::ARCH != "aarch64" {
+ return Err("Step 298 platform identity differs".to_owned());
+ }
+
+ let os_build = json!({
+ "kernel_name": kernel_name,
+ "kernel_release": kernel_release,
+ "kernel_version": kernel_version,
+ });
+ let result = json!({
+ "schema": "radroots.services-hardening.rshr-200-platform-result.v1",
+ "platform": "macos_aarch64",
+ "system": "aarch64-darwin",
+ "os_family": "macos",
+ "architecture": "aarch64",
+ "kernel_name": os_build["kernel_name"],
+ "kernel_release": os_build["kernel_release"],
+ "os_build_sha256": sha256(&canonical(&os_build)?),
+ "runner_kind": "host",
+ "runner_image_sha256": "none",
+ "apple_toolchain_identity_sha256": APPLE_TOOLCHAIN_IDENTITY_SHA256,
+ "probe_source_path": PROBE_SOURCE_PATH,
+ "probe_source_sha256": PROBE_SOURCE_SHA256,
+ "execution_request_sha256": execution_request_sha256,
+ "assertion": [
+ {"id": "os_family", "result": "pass"},
+ {"id": "architecture", "result": "pass"},
+ {"id": "kernel_identity", "result": "pass"},
+ {"id": "runner_identity", "result": "pass"},
+ {"id": "apple_identity", "result": "pass"},
+ ],
+ "result": "available",
+ });
+ let mut bytes = canonical(&result)?;
+ bytes.push(b'\n');
+ std::io::Write::write_all(&mut std::io::stdout().lock(), &bytes)
+ .map_err(|_| "Step 298 platform result write failed".to_owned())
+}