liminal-cli 0.3.1

The liminal command: serve the network, maintain its stores, or serve its discovery MCP over stdio
Documentation
//! SDK-017 R1: every missing or zero field is refused by name (the server
//! alone defaults, to the central exchange, AGT-006 R3), and the pass's bytes
//! appear in no error and no Debug.

use std::error::Error;
use std::path::Path;

use super::{Config, Credential};

const FIELDS: [&str; 8] = [
    "server",
    "channel",
    "token_file",
    "frame_bytes",
    "record_bytes",
    "reply_timeout_ms",
    "flow_steps",
    "request_bytes",
];

fn written(token: &Path, without: Option<&str>, zero: Option<&str>) -> String {
    let mut top = String::new();
    let mut limits = String::new();
    for field in FIELDS {
        if without == Some(field) {
            continue;
        }
        let value = match field {
            "server" => "\"127.0.0.1:4100\"".to_owned(),
            "channel" => "\"events\"".to_owned(),
            "token_file" => format!("{:?}", token.display().to_string()),
            _ if zero == Some(field) => "0".to_owned(),
            _ => "16".to_owned(),
        };
        if matches!(field, "server" | "channel" | "token_file") {
            top.extend([field, " = ", value.as_str(), "\n"]);
        } else {
            limits.extend([field, " = ", value.as_str(), "\n"]);
        }
    }
    format!("{top}\n[limits]\n{limits}")
}

#[test]
fn config_refuses_each_missing_or_zero_field_by_name() -> Result<(), Box<dyn Error>> {
    let dir = tempfile::tempdir()?;
    let token = dir.path().join("token");
    std::fs::write(&token, "pass-bytes\n")?;
    let path = dir.path().join("ticket.toml");
    // AGT-006 R3: a seat that names no server is the central exchange.
    std::fs::write(&path, written(&token, Some("server"), None))?;
    assert_eq!(Config::load(&path)?.server, crate::seat::CENTRAL_SERVER);
    // ACCESS-010 R3: token_file may be absent (an open seat); every other
    // field is still named when missing.
    for field in FIELDS[1..].iter().filter(|field| **field != "token_file") {
        std::fs::write(&path, written(&token, Some(field), None))?;
        let refusal = Config::load(&path).err().map(|e| e.to_string());
        let refusal = refusal.ok_or("a missing field was accepted")?;
        assert!(refusal.contains(field), "missing {field}: {refusal}");
    }
    for field in &FIELDS[3..] {
        std::fs::write(&path, written(&token, None, Some(field)))?;
        let refusal = Config::load(&path).err().map(|e| e.to_string());
        let refusal = refusal.ok_or("a zero field was accepted")?;
        assert!(refusal.contains(field), "zero {field}: {refusal}");
    }
    std::fs::write(&path, written(&token, None, None))?;
    let config = Config::load(&path)?;
    assert_eq!(config.limits.flow_steps, 16);
    let Credential::Token(token) = &config.credential else {
        return Err("a token_file configuration did not hold a token".into());
    };
    assert_eq!(token.as_str(), "pass-bytes");
    Ok(())
}

#[test]
fn pass_bytes_appear_in_no_debug_and_no_error() -> Result<(), Box<dyn Error>> {
    let dir = tempfile::tempdir()?;
    let token = dir.path().join("token");
    std::fs::write(&token, "distinct-pass-7f3a\n")?;
    let path = dir.path().join("ticket.toml");
    std::fs::write(&path, written(&token, None, None))?;
    let config = Config::load(&path)?;
    let debug = format!("{config:?}");
    assert!(!debug.contains("distinct-pass-7f3a"), "{debug}");
    assert!(debug.contains("Token(18 bytes)"), "{debug}");
    std::fs::write(&token, "")?;
    let refusal = Config::load(&path).err().map(|e| e.to_string());
    let refusal = refusal.ok_or("an empty token was accepted")?;
    assert!(refusal.contains("token file is empty"), "{refusal}");
    Ok(())
}

#[test]
fn agt001_listen_defaults_and_every_zero_bound_are_named() -> Result<(), Box<dyn Error>> {
    let directory = tempfile::tempdir()?;
    let token = directory.path().join("token");
    std::fs::write(&token, "fixture-pass")?;
    let path = directory.path().join("seat.toml");
    std::fs::write(&path, written(&token, None, None))?;
    let config = Config::load(&path)?;
    assert_eq!(config.listen.listen_bound, 16);
    assert_eq!(config.listen.content_bytes, 65536);
    for field in [
        "listen_bound",
        "content_bytes",
        "join_bound",
        "join_bytes",
        "batch_messages",
        "subject_bytes",
        "key_bytes",
        "agent_bytes",
        "issuer_response_bytes",
        "run_pass_bytes",
    ] {
        let text = format!("{}\n[listen]\n{field} = 0\n", written(&token, None, None));
        std::fs::write(&path, text)?;
        let error = Config::load(&path)
            .err()
            .ok_or("a zero listen bound was accepted")?;
        assert!(
            error.to_string().contains(field),
            "the listen refusal did not name its bound"
        );
    }
    Ok(())
}

#[test]
fn agt001_listen_refuses_unknown_fields_and_non_subject_text() -> Result<(), Box<dyn Error>> {
    let directory = tempfile::tempdir()?;
    let token = directory.path().join("token");
    std::fs::write(&token, "fixture-pass")?;
    let path = directory.path().join("seat.toml");
    for table in [
        "[listen]\nsubjects = [\"a..b\"]\n",
        "[listen]\nunknown = true\n",
    ] {
        std::fs::write(&path, format!("{}\n{table}", written(&token, None, None)))?;
        assert!(
            Config::load(&path).is_err(),
            "an invalid listen table was accepted"
        );
    }
    Ok(())
}

#[test]
fn access010_an_open_seat_carries_no_credential_and_reaches_loopback_only()
-> Result<(), Box<dyn Error>> {
    let dir = tempfile::tempdir()?;
    let token = dir.path().join("token");
    let path = dir.path().join("seat.toml");
    for server in ["127.0.0.1:4100", "localhost:7900", "ws://[::1]:7902/ws"] {
        let text = written(&token, Some("token_file"), None).replace("127.0.0.1:4100", server);
        std::fs::write(&path, text)?;
        let config = Config::load(&path)?;
        assert!(matches!(config.credential, Credential::Open), "{config:?}");
        assert_eq!(config.server, server);
    }
    assert!(!token.exists(), "an open seat reads no token file");
    for server in ["192.168.50.40:7900", "wss://liminal.ablative.com.au/ws"] {
        let text = written(&token, Some("token_file"), None).replace("127.0.0.1:4100", server);
        std::fs::write(&path, text)?;
        let refusal = Config::load(&path).err().map(|e| e.to_string());
        let refusal = refusal.ok_or("an open seat off loopback was accepted")?;
        assert!(
            refusal.contains(&format!(
                "an open seat (no token_file, no [lys]) reaches a loopback exchange only: server {server}"
            )),
            "{refusal}"
        );
    }
    // Both credentials given is still refused with its own words.
    std::fs::write(&token, "pass-bytes\n")?;
    let both = format!(
        "{}\n[lys]\nissuer = \"http://127.0.0.1:8490\"\nagent = \"agent-x\"\n",
        written(&token, None, None)
    );
    std::fs::write(&path, both)?;
    let refusal = Config::load(&path).err().map(|e| e.to_string());
    let refusal = refusal.ok_or("two credentials were accepted")?;
    assert!(
        refusal.contains("give exactly one of token_file and [lys]"),
        "{refusal}"
    );
    Ok(())
}