Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

crates/gunnar-front/tests/proof_medium.rs

//! **A PROOF medium's material** — a seed of kind `front` (and one of kind
//! `gunnar`) with the installer's material beside it, for composing and booting
//! the front medium on this box when no estate's material exists.
//!
//! NOT the estate's material: `private-gunnar-ops` (`estate install`,
//! `installer::seed_for_compose`) mints that per estate and composes its own
//! media with it. This is the same shape through the same edda types, so a
//! medium composed with it proves the build and the boot, and an installer run
//! with the material beside it can reach that box's listener.
//!
//! ```text
//! GUNNAR_FRONT_PROOF_MEDIUM=<dir> cargo test --manifest-path crates/gunnar-front/Cargo.toml --target-dir target --test proof_medium -- --ignored
//!   <dir>/seed-front.toml  seed-gunnar.toml   (0600: the bootstrap key and the link key)
//!   <dir>/material/{ca.cert.pem,ca.key.pem,installer.cert.pem,installer.key.pem,link.toml}
//! ```

use nordisk_pairing::installer::{
    Material, CA_CERT, CA_KEY, INSTALLER_CERT, INSTALLER_KEY, LINK_KEYS,
};
use nordisk_pairing::mtls::InstallerCa;
use nordisk_pairing::seed::{Front, Kind, LinkSeed, Seed, TunnelKind};
use std::path::Path;
use std::time::Duration;

fn write_private(path: &Path, text: &str) {
    use std::io::Write as _;
    use std::os::unix::fs::OpenOptionsExt as _;
    std::fs::create_dir_all(path.parent().unwrap()).unwrap();
    let mut f = std::fs::OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .mode(0o600)
        .open(path)
        .unwrap();
    f.write_all(text.as_bytes()).unwrap();
}

/// A WireGuard key pair (private b64, public b64), minted the way a box mints
/// its own `wg0.key` (gunnar-server `pairing::ensure_tunnel_key`).
fn keypair() -> (String, String) {
    let dir = tempfile::tempdir().unwrap();
    let private = gunnar_server::pairing::ensure_tunnel_key(dir.path()).unwrap();
    (private, gunnar_server::pairing::tunnel_pubkey(dir.path()))
}

#[test]
#[ignore = "writes a proof medium's material to $GUNNAR_FRONT_PROOF_MEDIUM"]
fn mint_a_proof_medium() {
    let Ok(dir) = std::env::var("GUNNAR_FRONT_PROOF_MEDIUM") else {
        panic!("set GUNNAR_FRONT_PROOF_MEDIUM=<dir>");
    };
    let dir = Path::new(&dir);
    let estate =
        std::env::var("GUNNAR_FRONT_PROOF_ESTATE").unwrap_or_else(|_| "proof.gunnar.local".into());
    let valid = Duration::from_secs(30 * 24 * 3600);
    let ca = InstallerCa::mint(&estate, valid).unwrap();
    let boot = ca.issue_bootstrap(valid).unwrap();
    let me = ca.issue_installer(valid).unwrap();
    let (inst_private_b64, inst_public_b64) = keypair();
    let (vm_private_b64, vm_public_b64) = keypair();
    let m = dir.join("material");
    write_private(&m.join(CA_CERT), &ca.cert_pem);
    write_private(&m.join(CA_KEY), &ca.key_pem);
    write_private(&m.join(INSTALLER_CERT), &me.cert_pem);
    write_private(&m.join(INSTALLER_KEY), &me.key_pem);
    write_private(
        &m.join(LINK_KEYS),
        &Material::link_file(&inst_private_b64, &vm_public_b64),
    );
    for kind in [Kind::Front, Kind::Gunnar] {
        let seed = Seed {
            estate: estate.clone(),
            tunnel: TunnelKind::Wireguard,
            front: Front::default(),
            kind,
            installer_ca_pem: ca.cert_pem.clone(),
            bootstrap_cert_pem: boot.cert_pem.clone(),
            bootstrap_key_pem: boot.key_pem.clone(),
            peers_expected: 3,
            mullvad: None,
            tailscale: None,
            installer_link: Some(LinkSeed {
                installer_pubkey: inst_public_b64.clone(),
                vm_private: vm_private_b64.clone(),
                port: nordisk_pairing::installer_link::LINK_PORT,
                psk: None,
            }),
        };
        let text = seed.render().unwrap();
        Seed::parse(&text).expect("the seed parses back");
        let name = if kind == Kind::Front {
            "seed-front.toml"
        } else {
            "seed-gunnar.toml"
        };
        write_private(&dir.join(name), &text);
    }
    Material::load(&m).expect("the installer's material loads");
    eprintln!("proof medium material in {}", dir.display());
}