liminal-cli 0.3.21

The liminal command: serve the network, maintain its stores, or serve its discovery MCP over stdio
Documentation
//! ACCESS-011 R4 (a): an exchange with no `[auth]` and `[open] reach =
//! "network"` listens on every address, says so on its started line and in
//! one WARN per address, and a seat with no credential at the machine's own
//! network address lists, calls and sends through the liminal binary; the
//! same seat without the table is refused at load with ACCESS-010's words.

use std::error::Error;

use serde_json::json;

use super::network::{OpenServer, lan_address};
use super::open_mode::open_worker;
use super::{CHANNEL, Host, SUBJECT, Ticket};

/// A seat with no credential on `address`, with `open` (an `[open]` table or
/// nothing) between the channel and the limits.
fn seat_text(address: &str, open: &str) -> String {
    format!(
        "server = \"{address}\"\nchannel = \"{CHANNEL}\"\n{open}\n[limits]\nframe_bytes = 65536\n\
         record_bytes = 1048576\nreply_timeout_ms = 5000\nflow_steps = 8\nrequest_bytes = 65536\n"
    )
}

#[test]
fn access011_an_open_exchange_reaches_the_network_and_an_open_seat_dials_it_from_the_machines_address()
-> Result<(), Box<dyn Error>> {
    let dir = tempfile::tempdir()?;
    let lan = lan_address()?;
    let server = OpenServer::start_on_with(dir.path(), "0.0.0.0", "[open]\nreach = \"network\"\n")?;
    let port = server.address.port();
    let _worker = open_worker(&format!("127.0.0.1:{port}"))?;

    let seat = dir.path().join("seat.toml");
    std::fs::write(
        &seat,
        seat_text(&format!("{lan}:{port}"), "\n[open]\nreach = \"network\"\n"),
    )?;
    let mut host = Host::open(Ticket::spawn(&seat)?, true)?;

    let listed = host.tool("list", &json!({}))?;
    assert_eq!(listed["isError"], false, "{listed}");
    assert!(
        listed["structuredContent"]["stations"]
            .to_string()
            .contains(SUBJECT),
        "{listed}"
    );
    let answer = host.tool(
        "call",
        &json!({ "subject": SUBJECT, "input": { "text": "across" } }),
    )?;
    assert_eq!(answer["isError"], false, "{answer}");
    assert_eq!(
        answer["structuredContent"]["echoed"]["text"], "across",
        "{answer}"
    );
    let published = host.tool(
        "send",
        &json!({ "subject": CHANNEL, "text": "{\"note\":\"across\"}", "key": "across-1" }),
    )?;
    assert_eq!(published["isError"], false, "{published}");
    let (stderr, code) = host.ticket.close()?;
    assert_eq!(code, 0, "{stderr}");

    // The same seat without the table reaches loopback only (ACCESS-010 R3).
    let bare = dir.path().join("bare.toml");
    std::fs::write(&bare, seat_text(&format!("{lan}:{port}"), ""))?;
    let (stderr, code) = Ticket::spawn(&bare)?.close()?;
    assert_ne!(code, 0, "{stderr}");
    assert!(
        stderr.contains("an open seat (no token_file, no [lys]) reaches a loopback exchange only"),
        "{stderr}"
    );

    let log = server.log()?;
    assert!(log.contains("mode=open reach=network"), "{log}");
    assert!(
        log.contains(&format!(
            "open mode reaches the network: every connection on 0.0.0.0:{port} is admitted and \
             nothing is asked of Lys"
        )),
        "{log}"
    );
    Ok(())
}