liminal-cli 0.2.0

The liminal command: serve the network, maintain its stores, or serve its discovery MCP over stdio
Documentation
//! The ticket's pass request: the attestation bytes Lys verifies, the key
//! read from a seat file, and the configuration refused by name.

use std::io::Write as _;

use base64::Engine as _;

use super::{LysAgent, LysTable, PKCS8_ED25519_PREFIX, SigningKey, attest, hex, read_key};

const SEED: &[u8; 32] = b"lys-cose-conformance-test-seed01";
const MILLIS: u64 = 1_700_000_000_000;
/// The issuer's golden attestation for this seed, payload and time, as Lys,
/// Cambium's seat MCP and haem mcp pin it.
const GOLDEN: &str = "d2845850a301270378276170706c69636174696f6e2f766e642e6c79732e6174746573746174696f6e2e76322b63626f72045820214e41cc8475f5bc9af68dbf33fa56e8adf5144a4a81134268f4ae379e103bfda0582ea20158209404f8b8cec8ad98a88b106d9345d518c273f012c1306b8af5103e865997191e021b0000018bcfe568005840ba6eae66b3a04f25e6116e7278ae8b0e2174a2964bb0917ae53ab2ef326c22a706e90cae6886b20ecd086fee4b515de046d450f90de81f9aa46a9b34bd7f1a09";

#[test]
fn attestation_matches_the_issuer_golden_bytes() {
    let key = SigningKey::from_bytes(SEED);
    let cose = attest(&key, b"lys attestation conformance payload\n", MILLIS);
    assert_eq!(hex(&cose), GOLDEN);
}

#[test]
fn a_seat_file_yields_its_key() -> Result<(), Box<dyn std::error::Error>> {
    let der = [PKCS8_ED25519_PREFIX.as_slice(), SEED].concat();
    let pem = format!(
        "-----BEGIN PRIVATE KEY-----\n{}\n-----END PRIVATE KEY-----\n",
        base64::engine::general_purpose::STANDARD.encode(der)
    );
    let mut seat = tempfile::NamedTempFile::new()?;
    seat.write_all(
        serde_json::json!({ "privateKeyPem": pem })
            .to_string()
            .as_bytes(),
    )?;
    let key = read_key(seat.path()).map_err(|error| error.0)?;
    assert_eq!(key.to_bytes(), *SEED);
    Ok(())
}

#[test]
fn a_remote_http_issuer_and_a_relative_key_are_refused() {
    let table = |issuer: &str, key: &str| LysTable {
        issuer: issuer.to_owned(),
        agent: "agent-1".to_owned(),
        key_file: key.into(),
    };
    let timeout = std::time::Duration::from_secs(1);
    assert!(LysAgent::new(&table("http://lys.example", "/k"), timeout).is_err());
    assert!(LysAgent::new(&table("http://127.0.0.1:8490", "k"), timeout).is_err());
    assert!(LysAgent::new(&table("http://127.0.0.1:8490", "/k"), timeout).is_ok());
    assert!(LysAgent::new(&table("https://lys.example", "/k"), timeout).is_ok());
}