crates/installer/nordisk-narrate/src/lib.rs
//! **DEV-NARRATE: a box's early boot log, sealed, over UDP, to the installer.**
//!
//! # Why (owner, 2026-09-30)
//!
//! The owner watched boxes on the console and saw errors no test caught. The
//! installer's only log path is the mutual-TLS LOG DOOR over its WireGuard
//! link ([`nordisk_pairing`'s bootstrap listener]), so everything a box says
//! BEFORE that link is up — korp-start, the kernel, the product's first
//! seconds — and every box that never gets that far, is invisible to it. A
//! plain UDP narration existed (`korp.log_udp`) and was retired because it was
//! clear text to whoever held an address. This is its replacement, built so
//! that it can be ON on every dev box without being a leak:
//!
//! 1. **Buffered from the first line.** The box's source is the same in-RAM
//! boot log the log door reads (nordisk-pairing `BootLog`: the ESP's
//! `BOOTLOG.TXT` — the install phase, korp-start, this boot — then every
//! line the product says, cleaned by the same redaction). Nothing leaves
//! until the NIC has an address and the installer said hello; then the
//! buffer is flushed from line 0 and the stream is live.
//! 2. **Sealed.** Every datagram is a NaCl `crypto_box` (X25519 +
//! XSalsa20-Poly1305, RustCrypto `crypto_box`, audited by Cure53) from a
//! PER-BOOT ephemeral key of the box to the installer's X25519 public key —
//! the `installer_pubkey` already in the medium's seed. Only the holder of
//! the installer's private key (the operator's machine) can read it. The
//! box id, its boot id and the line sequence numbers are INSIDE the sealed
//! payload, so a replayed datagram is a duplicate and a forged one does not
//! open.
//! 3. **NAT-friendly, and no reflector.** The box cannot know where the
//! operator is. The installer KNOCKS on `udp/<PORT>` of each VM's public
//! address; the box answers a knock with ONE sealed `WHO` datagram (shorter
//! than the knock: no amplification) that carries its ephemeral public key.
//! The installer then sends a `HELLO` sealed from its OWN private key to that
//! ephemeral key — which only the installer can produce — and the box streams
//! to the address that authenticated hello came from, for as long as hellos
//! keep coming. Each hello carries the next sequence number the installer
//! needs, so a lost datagram is sent again.
//! 4. **Absent from a release.** The sender and the kernel follower exist only
//! under this crate's `dev-narrate` feature, which a product enables through
//! its own `dev-narrate` feature, which only the DEV medium's build asks for.
//! The installer side ([`receiver`]) is always here: it runs on the operator's
//! machine and sends nothing but knocks and hellos.
//!
//! Pure Rust, no shell (LAW).
pub mod receiver;
pub mod seedkey;
pub mod wire;
#[cfg(feature = "dev-narrate")]
pub mod kmsg;
#[cfg(feature = "dev-narrate")]
pub mod sender;
#[cfg(all(feature = "dev-narrate", feature = "bootlog"))]
pub mod boxside;
/// **The narration port** on every VM: udp/51822, beside the installer's
/// WireGuard link (51821) and the front's relay (51820). Opened in an estate's
/// firewall ONLY for a dev build.
pub const PORT: u16 = 51822;
/// **korp-start's WHOLE narration, handed to the app in RAM** — tunnr
/// korp-installer `bootlog::RAM_HANDOFF`, the same literal (two repositories,
/// no dependency edge; each side's test holds its spelling).
pub const KORP_START_HANDOFF: &str = "/run/korp/start.narration";
/// **korp-start's story when the ESP could not tell it** (feature
/// `dev-narrate`): when `esp` (the ESP's `BOOTLOG.TXT`, which the product's
/// capture pushes first) cannot be read, push korp-start's RAM hand-off
/// between two marker lines naming `product`. `false` = nothing pushed (the
/// ESP was readable, or there is no hand-off).
#[cfg(feature = "dev-narrate")]
pub fn korp_start_fallback(esp: &std::path::Path, handoff: &std::path::Path, product: &str, push: &dyn Fn(&str)) -> bool {
if std::fs::metadata(esp).is_ok() {
return false;
}
let Ok(text) = std::fs::read_to_string(handoff) else { return false };
push(&format!("── korp-start's narration, handed over in RAM ({}): {} could not be read ──", handoff.display(), esp.display()));
for l in text.lines() {
push(l.trim_end_matches('\r'));
}
push(&format!("── {product} ──"));
true
}
/// **The line a box says when its sender starts** — the kit reads it as the
/// proof a narration came from a DEV build.
pub const STARTED: &str = "dev-narrate: sealed narration to the installer's key on udp/51822 (a DEV build; a release build carries no narrate sender)";
#[cfg(all(test, feature = "dev-narrate"))]
mod tests {
#[test]
fn korp_starts_ram_story_is_pushed_only_when_the_esp_is_unreadable() {
let dir = std::env::temp_dir().join(format!("narrate-handoff-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let (esp, handoff) = (dir.join("BOOTLOG.TXT"), dir.join("start.narration"));
std::fs::write(&handoff, "INSTALLER: STAGE entered +0ms\r\nINSTALLER: STAGE exec +900ms\r\n").unwrap();
let got = std::cell::RefCell::new(Vec::<String>::new());
let push = |l: &str| got.borrow_mut().push(l.to_string());
assert!(super::korp_start_fallback(&esp, &handoff, "gunnar", &push), "no ESP: the RAM story is pushed");
assert_eq!(got.borrow()[1..3], ["INSTALLER: STAGE entered +0ms", "INSTALLER: STAGE exec +900ms"]);
assert_eq!(got.borrow().last().unwrap(), "── gunnar ──");
std::fs::write(&esp, "the ESP told it").unwrap();
got.borrow_mut().clear();
assert!(!super::korp_start_fallback(&esp, &handoff, "gunnar", &push) && got.borrow().is_empty(), "a readable ESP already told the story");
assert_eq!(super::KORP_START_HANDOFF, "/run/korp/start.narration", "tunnr korp-installer bootlog::RAM_HANDOFF writes this literal");
let _ = std::fs::remove_dir_all(&dir);
}
}