crates/mock-upcloud/kvm-guest/src/bin/faithful_guest_proof.rs
//! **The measurement, re-run: a real gunnar medium on the machine UpCloud hands out.**
//!
//! What it must show, and what the oden run of 2026-09-20 showed:
//!
//! * **zero bytes on stdout** — there is no serial console, so the guest's whole
//! narration reaches nobody;
//! * **two screendumps that hash differently** — the guest really progressed,
//! and the pixels are the only place that is visible;
//! * **the qcow2 grew** — the install really wrote.
//!
//! There is no log to quote for any of it. That is the point.
//!
//! cargo run --release --bin faithful-guest-proof -- \
//! --iso /home/rickard/scratch/fullk/gunnar-installer-open-fullk.iso \
//! --root /tmp/t12-proof --frame-ms 200 --budget 90 --vnc 127.0.0.1:91
use std::path::PathBuf;
use std::time::Duration;
use draupnir::qemu;
use draupnir_guest::DraupnirGuest;
use mock_upcloud::kvm::{GuestOutcome, GuestSpec};
fn parse_machine(v: Option<String>) -> Result<draupnir::MachineType, String> {
match v.as_deref() {
Some("pc") => Ok(draupnir::MachineType::Pc),
Some("q35") => Ok(draupnir::MachineType::Q35),
other => Err(format!("--machine wants pc or q35, got {other:?}")),
}
}
fn main() {
let mut iso: Option<String> = None;
let mut root = PathBuf::from("/tmp/faithful-guest-proof");
let mut gap = 200u64;
let mut budget = 90u64;
let mut vnc = "127.0.0.1:91".to_string();
let mut disk_gib = 8u64;
let mut machine = draupnir::MachineType::Pc;
let mut args = std::env::args().skip(1);
while let Some(a) = args.next() {
match a.as_str() {
"--iso" => iso = args.next(),
"--root" => root = PathBuf::from(args.next().expect("--root <dir>")),
"--frame-ms" => {
gap = args
.next()
.and_then(|s| s.parse().ok())
.expect("--frame-ms <n>")
}
"--budget" => {
budget = args
.next()
.and_then(|s| s.parse().ok())
.expect("--budget <n>")
}
"--vnc" => vnc = args.next().expect("--vnc <spec>"),
"--machine" => {
machine = parse_machine(args.next()).unwrap_or_else(|e| {
eprintln!("{e}");
std::process::exit(2)
})
}
"--disk-gib" => {
disk_gib = args
.next()
.and_then(|s| s.parse().ok())
.expect("--disk-gib <n>")
}
other => {
eprintln!("unknown argument {other}");
std::process::exit(2);
}
}
}
let Some(iso) = iso else {
eprintln!(
"--iso <path to a real product medium> is required: this proof is worthless \
against a synthetic image"
);
std::process::exit(2);
};
let iso_len = std::fs::metadata(&iso).map(|m| m.len()).unwrap_or(0);
if iso_len == 0 {
eprintln!("{iso}: not on this host");
std::process::exit(2);
}
std::fs::create_dir_all(&root).expect("root");
let disk = root.join("appliance.qcow2");
let _ = std::fs::remove_file(&disk);
qemu::create_qcow2(&disk, disk_gib << 30).expect("qcow2");
let engine = DraupnirGuest {
root: root.clone(),
install_budget: Duration::from_secs(budget),
frame_gap: Duration::from_millis(gap),
vnc: Some(vnc.clone()),
machine,
..DraupnirGuest::default()
};
let mut spec = GuestSpec::new("appliance", disk.display().to_string());
spec.medium = Some(iso.clone());
spec.cdrom_first = true;
println!("medium {iso} ({iso_len} bytes)");
println!(
"disk {} ({} bytes virtual)",
disk.display(),
disk_gib << 30
);
let ev = engine.run(&spec);
println!("\nargv {}", ev.argv.join(" "));
println!("workdir {}", ev.workdir.display());
println!("\n── the evidence, and there is no other ──");
println!(
"stdout bytes {} (behaviour 13: nothing narrates it)",
ev.stdout_bytes
);
for (i, f) in ev.frames.iter().enumerate() {
println!("frame {i} {f}");
}
println!(
"frames {} distinct, sampled every {gap} ms: {}",
ev.frames.len(),
if ev.frames.len() >= draupnir_guest::PROGRESS_FRAMES {
"DIFFERENT — the guest progressed"
} else {
"no second distinct frame — nothing was seen to progress"
}
);
println!(
"qcow2 {} → {} bytes ({:+})",
ev.disk_bytes.0,
ev.disk_bytes.1,
ev.disk_bytes.1 as i64 - ev.disk_bytes.0 as i64
);
println!("outcome {}", ev.outcome);
// The proof's own verdict, so a run cannot be read as green by eye.
let mut reds = Vec::new();
if ev.stdout_bytes != 0 {
reds.push("the guest put bytes on stdout: it HAS a serial console");
}
if ev.frames.len() < draupnir_guest::PROGRESS_FRAMES {
reds.push("fewer than three distinct screendumps: a blinking cursor alone makes two");
}
if ev.disk_bytes.1 <= ev.disk_bytes.0 {
reds.push("the qcow2 did not grow: nothing was written");
}
if let GuestOutcome::Refused { clause, why } = &ev.outcome {
println!("\nREFUSED {clause}: {why}");
std::process::exit(1);
}
if reds.is_empty() {
println!("\nPROVEN: the narration arrived on the framebuffer, with zero bytes on stdout.");
} else {
println!();
for r in &reds {
println!("RED: {r}");
}
std::process::exit(1);
}
}