use super::*;
#[test]
fn loopback_literals_are_local() {
assert!(is_local_address("127.0.0.1"));
assert!(is_local_address("127.5.6.7"));
assert!(is_local_address("0.0.0.0"));
assert!(is_local_address("[::1]"));
assert!(is_local_address("::1"));
assert!(is_local_address("[::]"));
}
#[test]
fn private_and_link_local_literals_are_local() {
assert!(is_local_address("10.0.0.5"));
assert!(is_local_address("172.16.0.1"));
assert!(is_local_address("172.31.255.255"));
assert!(is_local_address("192.168.1.10"));
assert!(is_local_address("169.254.1.1")); assert!(is_local_address("100.64.0.1")); assert!(is_local_address("[fe80::1]")); assert!(is_local_address("[fc00::1]")); }
#[test]
fn ipv4_mapped_loopback_is_local() {
assert!(is_local_address("[::ffff:127.0.0.1]"));
}
#[test]
fn site_local_and_transition_literals_are_local() {
assert!(is_local_address("[fec0::1]"));
assert!(is_local_address("[64:ff9b::7f00:1]"));
assert!(is_local_address("[2002:c0a8:1::]"));
assert!(is_local_address("[2001:0:7f00:1::]"));
assert!(!is_local_address("[64:ff9b::808:808]")); }
#[test]
fn localhost_hostname_family_is_local() {
assert!(is_local_address("localhost"));
assert!(is_local_address("LOCALHOST"));
assert!(is_local_address("api.localhost"));
assert!(is_local_address("foo.bar.localhost"));
}
#[test]
fn public_addresses_are_not_local() {
assert!(!is_local_address("8.8.8.8"));
assert!(!is_local_address("1.1.1.1"));
assert!(!is_local_address("198.51.100.7"));
assert!(!is_local_address("172.32.0.1")); assert!(!is_local_address("192.169.1.1")); assert!(!is_local_address("[2001:4860:4860::8888]"));
}
#[test]
fn real_dns_names_are_not_local() {
assert!(!is_local_address("api.openai.com"));
assert!(!is_local_address("example.com"));
assert!(!is_local_address("notlocalhost.com"));
assert!(!is_local_address(""));
}
#[test]
fn endpoint_host_port_parses_explicit_and_default_ports() {
assert_eq!(
endpoint_host_port("http://127.0.0.1:1234"),
Some(("127.0.0.1".to_string(), 1234))
);
assert_eq!(
endpoint_host_port("http://127.0.0.1/v1"),
Some(("127.0.0.1".to_string(), 80))
);
assert_eq!(
endpoint_host_port("https://localhost"),
Some(("localhost".to_string(), 443))
);
assert_eq!(endpoint_host_port("just some text"), None);
assert_eq!(endpoint_host_port(""), None);
}
#[test]
fn local_egress_entry_only_for_local_endpoints() {
assert_eq!(
local_egress_entry("http://127.0.0.1:1234/v1"),
Some("127.0.0.1:1234".to_string())
);
assert_eq!(
local_egress_entry("http://localhost:11434"),
Some("localhost:11434".to_string())
);
assert_eq!(
local_egress_entry("http://192.168.1.50:8080"),
Some("192.168.1.50:8080".to_string())
);
assert_eq!(local_egress_entry("https://api.openai.com/v1"), None);
assert_eq!(local_egress_entry("not a url"), None);
}
#[test]
fn record_creates_file_and_section() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("config.toml");
record_local_egress(&path, "openai-compat", "127.0.0.1:1234").expect("record");
let content = std::fs::read_to_string(&path).expect("read back");
let doc: toml::Value = toml::from_str(&content).expect("valid toml");
let list = doc["security"]["capsule_local_egress"]["openai-compat"]
.as_array()
.expect("array");
assert_eq!(list.len(), 1);
assert_eq!(list[0].as_str(), Some("127.0.0.1:1234"));
}
#[test]
fn record_preserves_existing_config_and_appends() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("config.toml");
std::fs::write(
&path,
"# operator config\n\
[security]\n\
require_signatures = true\n\
\n\
[security.capsule_local_egress]\n\
other-capsule = [\"10.0.0.1:9000\"]\n",
)
.expect("seed");
record_local_egress(&path, "openai-compat", "127.0.0.1:1234").expect("record");
let content = std::fs::read_to_string(&path).expect("read back");
assert!(content.contains("require_signatures = true"));
assert!(content.contains("# operator config"));
let doc: toml::Value = toml::from_str(&content).expect("valid toml");
let egress = &doc["security"]["capsule_local_egress"];
assert_eq!(egress["other-capsule"][0].as_str(), Some("10.0.0.1:9000"));
assert_eq!(egress["openai-compat"][0].as_str(), Some("127.0.0.1:1234"));
}
#[test]
fn record_is_idempotent() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("config.toml");
record_local_egress(&path, "cap", "127.0.0.1:1234").expect("first");
record_local_egress(&path, "cap", "127.0.0.1:1234").expect("second");
record_local_egress(&path, "cap", "127.0.0.1:1234").expect("third");
let content = std::fs::read_to_string(&path).expect("read back");
let doc: toml::Value = toml::from_str(&content).expect("valid toml");
let list = doc["security"]["capsule_local_egress"]["cap"]
.as_array()
.expect("array");
assert_eq!(list.len(), 1, "duplicate entries must not accumulate");
}
#[test]
fn record_appends_distinct_ports_for_same_capsule() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("config.toml");
record_local_egress(&path, "cap", "127.0.0.1:1234").expect("first");
record_local_egress(&path, "cap", "127.0.0.1:5678").expect("second");
let content = std::fs::read_to_string(&path).expect("read back");
let doc: toml::Value = toml::from_str(&content).expect("valid toml");
let list = doc["security"]["capsule_local_egress"]["cap"]
.as_array()
.expect("array");
assert_eq!(list.len(), 2);
}
#[test]
fn record_leaves_no_temp_sibling() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("config.toml");
record_local_egress(&path, "cap", "127.0.0.1:1234").expect("record");
let names: Vec<String> = std::fs::read_dir(dir.path())
.expect("read_dir")
.map(|e| e.expect("entry").file_name().to_string_lossy().into_owned())
.collect();
assert_eq!(names, vec!["config.toml".to_string()], "got {names:?}");
}
#[test]
fn non_interactive_path_does_not_read_stdin_or_write_config() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("config.toml");
let mut read_called = false;
prompt_and_record("openai-compat", "http://127.0.0.1:1234/v1", &path, || {
read_called = true;
None
});
assert!(!path.exists(), "no config should be written without a yes");
assert!(read_called, "reader is the sole seam exercised here");
}
#[test]
fn prompt_skips_reader_for_non_local_value() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("config.toml");
prompt_and_record("cap", "https://api.openai.com/v1", &path, || {
panic!("read_answer must not be called for a non-local value");
});
assert!(!path.exists());
}
#[test]
fn prompt_yes_writes_config() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("config.toml");
prompt_and_record("cap", "http://127.0.0.1:1234/v1", &path, || {
Some("y\n".to_string())
});
let content = std::fs::read_to_string(&path).expect("read back");
let doc: toml::Value = toml::from_str(&content).expect("valid toml");
assert_eq!(
doc["security"]["capsule_local_egress"]["cap"][0].as_str(),
Some("127.0.0.1:1234")
);
}