use std::net::TcpListener;
use std::os::unix::fs::PermissionsExt;
use std::time::Duration;
use super::{
CENTRAL_ISSUER, CENTRAL_SERVER, init, init_open, init_open_named, refuse_unanswered_loopback,
};
type TestResult = Result<(), Box<dyn std::error::Error>>;
const BOUND: Duration = Duration::from_millis(2_000);
#[test]
fn seat_init_writes_the_central_addresses_private_and_never_a_pass() -> TestResult {
let dir = tempfile::tempdir()?;
let out = dir.path().join("seat.toml");
init("agent-7", &dir.path().join("agent.key"), &out)?;
let mode = std::fs::metadata(&out)?.permissions().mode() & 0o777;
assert_eq!(mode, 0o600);
let text = std::fs::read_to_string(&out)?;
assert!(
text.contains(&format!("server = \"{CENTRAL_SERVER}\"")),
"{text}"
);
assert!(
text.contains(&format!("issuer = \"{CENTRAL_ISSUER}\"")),
"{text}"
);
assert!(
!text.contains("127.0.0.1") && !text.contains("token"),
"{text}"
);
let config = crate::Config::load(&out)?;
assert_eq!(config.server, CENTRAL_SERVER);
Ok(())
}
#[test]
fn seat_init_never_replaces_a_seat_file() -> TestResult {
let dir = tempfile::tempdir()?;
let out = dir.path().join("seat.toml");
std::fs::write(&out, "kept")?;
let refused = init("agent-7", &dir.path().join("agent.key"), &out);
assert!(refused.is_err_and(|e| e.to_string().starts_with("liminal_seat_unwritable")));
assert_eq!(std::fs::read_to_string(&out)?, "kept");
Ok(())
}
#[test]
fn an_agent_id_that_would_break_the_file_is_refused() -> TestResult {
let dir = tempfile::tempdir()?;
for agent in ["", "a\"b", "a\nb"] {
assert!(init(agent, &dir.path().join("k"), &dir.path().join("s.toml")).is_err());
}
Ok(())
}
#[test]
fn a_loopback_address_nothing_answers_on_is_refused_by_name() -> TestResult {
let port = TcpListener::bind("127.0.0.1:0")?.local_addr()?.port();
for address in [
format!("127.0.0.1:{port}"),
format!("ws://127.0.0.1:{port}/ws"),
format!("http://localhost:{port}"),
] {
let refused = refuse_unanswered_loopback(&address, BOUND);
assert_eq!(
refused,
Err(format!(
"liminal_mcp_loopback_unanswered: nothing answers at {address}"
))
);
}
Ok(())
}
#[test]
fn a_loopback_address_that_answers_and_any_remote_address_pass() -> TestResult {
let listener = TcpListener::bind("127.0.0.1:0")?;
let port = listener.local_addr()?.port();
assert_eq!(
refuse_unanswered_loopback(&format!("127.0.0.1:{port}"), BOUND),
Ok(())
);
assert_eq!(refuse_unanswered_loopback(CENTRAL_SERVER, BOUND), Ok(()));
assert_eq!(refuse_unanswered_loopback(CENTRAL_ISSUER, BOUND), Ok(()));
Ok(())
}
#[test]
fn a_seat_that_names_no_server_and_no_issuer_reads_as_the_central_services() -> TestResult {
let dir = tempfile::tempdir()?;
let out = dir.path().join("seat.toml");
std::fs::write(
&out,
"channel = \"c\"\n\n[lys]\nagent = \"agent-7\"\nkey_file = \"agent.key\"\n\n\
[limits]\nframe_bytes = 65536\nrecord_bytes = 1048576\nreply_timeout_ms = 10000\n\
flow_steps = 8\nrequest_bytes = 65536\n",
)?;
let config = crate::Config::load(&out)?;
assert_eq!(config.server, CENTRAL_SERVER);
let crate::config::Credential::Lys(lys) = &config.credential else {
return Err("the seat's credential is not Lys".into());
};
assert_eq!(lys.issuer, CENTRAL_ISSUER);
Ok(())
}
#[test]
fn access011_seat_init_open_writes_the_reach_only_off_loopback() -> TestResult {
let dir = tempfile::tempdir()?;
let lan = dir.path().join("lan.toml");
init_open("ws://192.168.50.40:7902/ws", &lan)?;
let mode = std::fs::metadata(&lan)?.permissions().mode() & 0o777;
assert_eq!(mode, 0o600);
let text = std::fs::read_to_string(&lan)?;
assert!(text.contains("[open]\nreach = \"network\""), "{text}");
assert!(!text.contains("[lys]") && !text.contains("token"), "{text}");
let config = crate::Config::load(&lan)?;
assert!(
matches!(config.credential, crate::Credential::Open { .. }),
"{config:?}"
);
assert_eq!(config.server, "ws://192.168.50.40:7902/ws");
let local = dir.path().join("local.toml");
init_open("127.0.0.1:7900", &local)?;
let text = std::fs::read_to_string(&local)?;
assert!(!text.contains("[open]"), "{text}");
let config = crate::Config::load(&local)?;
assert!(
matches!(config.credential, crate::Credential::Open { .. }),
"{config:?}"
);
Ok(())
}
#[test]
fn access011_seat_init_open_refuses_an_unprintable_server_and_an_existing_file() -> TestResult {
let dir = tempfile::tempdir()?;
let out = dir.path().join("seat.toml");
let refusal = init_open("127.0.0.1:7900\"\n", &out)
.err()
.map(|e| e.to_string())
.ok_or("an unprintable server was accepted")?;
assert!(refusal.contains("liminal_seat_server_invalid"), "{refusal}");
assert!(!out.exists());
std::fs::write(&out, "kept")?;
let refusal = init_open("127.0.0.1:7900", &out)
.err()
.map(|e| e.to_string())
.ok_or("an existing seat file was replaced")?;
assert!(refusal.contains("liminal_seat_unwritable"), "{refusal}");
assert_eq!(std::fs::read_to_string(&out)?, "kept");
Ok(())
}
#[test]
fn access012_seat_init_open_writes_the_name_it_is_given() -> TestResult {
let dir = tempfile::tempdir()?;
let named = dir.path().join("named.toml");
init_open_named("127.0.0.1:7900", Some("hermes"), &named)?;
let text = std::fs::read_to_string(&named)?;
assert!(text.contains("[open]\nname = \"hermes\""), "{text}");
let config = crate::Config::load(&named)?;
assert_eq!(config.credential.holder(), "open:hermes");
let lan = dir.path().join("lan.toml");
init_open_named("192.168.50.40:7900", Some("hermes"), &lan)?;
let text = std::fs::read_to_string(&lan)?;
assert!(
text.contains("[open]\nreach = \"network\"\nname = \"hermes\""),
"{text}"
);
assert_eq!(
crate::Config::load(&lan)?.credential.holder(),
"open:hermes"
);
let refused = init_open_named(
"127.0.0.1:7900",
Some("Hermes!"),
&dir.path().join("bad.toml"),
);
assert!(
matches!(refused, Err(crate::seat::SeatInitError::Name)),
"{refused:?}"
);
Ok(())
}