#![forbid(unsafe_code)]
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use crate::evidence::environment::Environment;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Manifest {
pub corpus: String,
pub corpus_hash: String,
pub revision: String,
pub ryg_rans_revision: String,
pub dsfb_revision: String,
pub kernel: String,
pub mount_config: String,
pub cpu_features: String,
pub command: String,
pub representation_distribution: BTreeMap<String, u64>,
pub logical_bytes: u64,
pub physical_reachable_bytes: u64,
pub total_backing_bytes: u64,
pub metadata_bytes: u64,
pub model_bytes: u64,
pub descriptor_bytes: u64,
pub residual_bytes: u64,
pub dedup_savings: u64,
pub encode_mbps: f64,
pub materialize_mbps: f64,
pub cold_read_mbps: f64,
pub warm_read_mbps: f64,
}
impl Manifest {
pub fn to_json(&self) -> String {
serde_json::to_string_pretty(self).unwrap_or_else(|_| "{}".into())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct EvidenceManifest {
pub schema_version: u32,
pub court_schema_version: String,
pub entropyfs_version: String,
pub git_revision: String,
pub format_major: u16,
pub format_minor: u16,
pub compat_bits: String,
pub ro_compat_bits: String,
pub incompat_bits: String,
pub entropy_universe_versions: Vec<String>,
pub representation_encoder_policy_version: String,
pub io_backend: String,
pub worker_scheduler: String,
pub kernel: String,
pub architecture: String,
pub distribution: String,
pub distribution_version: String,
pub container_image_digest: String,
pub host: String,
pub compiler_version: String,
pub rustc_version: String,
pub timestamp_unix: u64,
}
impl EvidenceManifest {
pub fn capture(
repo_root: &std::path::Path,
store_dir: &std::path::Path,
io_backend: &str,
worker_scheduler: &str,
container_image_digest: &str,
court_schema_version: &str,
) -> EvidenceManifest {
let env = Environment::capture(repo_root, store_dir, "n/a", "n/a");
let (dist, dist_ver) = os_release();
let arch = std::env::consts::ARCH.to_string();
EvidenceManifest {
schema_version: 1,
court_schema_version: court_schema_version.to_string(),
entropyfs_version: env!("CARGO_PKG_VERSION").to_string(),
git_revision: env.revision_full.clone(),
format_major: crate::format::version::FORMAT_MAJOR,
format_minor: crate::format::version::FORMAT_MINOR,
compat_bits: "0x0000000000000000".into(),
ro_compat_bits: "0x0000000000000000".into(),
incompat_bits: "0x0000000000000000".into(),
entropy_universe_versions: vec!["uniform-xof-v1".into()],
representation_encoder_policy_version: "none".into(),
io_backend: io_backend.to_string(),
worker_scheduler: worker_scheduler.to_string(),
kernel: env.kernel_release.clone(),
architecture: arch,
distribution: dist,
distribution_version: dist_ver,
container_image_digest: container_image_digest.to_string(),
host: format!("{} | {}", env.hostname, env.cpu_model),
compiler_version: rustc_version(),
rustc_version: rustc_version(),
timestamp_unix: env.timestamp_unix,
}
}
pub fn to_json(&self) -> String {
serde_json::to_string_pretty(self).unwrap_or_else(|_| "{}".into())
}
}
fn os_release() -> (String, String) {
let body = std::fs::read_to_string("/etc/os-release").unwrap_or_default();
let mut name = String::new();
let mut version = String::new();
for line in body.lines() {
if let Some(v) = line.strip_prefix("ID=") {
name = v.trim().trim_matches('"').to_string();
} else if let Some(v) = line.strip_prefix("VERSION_ID=") {
version = v.trim().trim_matches('"').to_string();
}
}
if name.is_empty() {
name = "unknown".into();
}
if version.is_empty() {
version = "unknown".into();
}
(name, version)
}
fn rustc_version() -> String {
std::process::Command::new("rustc")
.arg("--version")
.output()
.ok()
.filter(|o| o.status.success())
.map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
.unwrap_or_else(|| "unknown".into())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn manifest_json_roundtrip() {
let m = Manifest {
corpus: "corpus.case".into(),
corpus_hash: "deadbeef".into(),
logical_bytes: 1_000_000,
..Default::default()
};
let back: Manifest = serde_json::from_str(&m.to_json()).unwrap();
assert_eq!(back, m);
}
}