Draft 0.5: identity/registry spec; Phase A signed MA registry, mailbox challenge auth, key rotation, skew rejection

This commit is contained in:
George Coles
2026-09-15 05:45:02 -04:00
parent fb45cfa8cf
commit 559c260639
18 changed files with 1526 additions and 105 deletions
+141
View File
@@ -183,6 +183,147 @@ fn cli_init_refuses_overwrite_without_force() {
run_ok(&forced);
}
fn http_get(port: u16, path: &str) -> String {
use std::io::{Read, Write};
let mut stream = std::net::TcpStream::connect(("127.0.0.1", port)).unwrap();
stream
.write_all(format!("GET {path} HTTP/1.0\r\nHost: 127.0.0.1\r\n\r\n").as_bytes())
.unwrap();
let mut out = String::new();
stream.read_to_string(&mut out).unwrap();
out
}
#[test]
fn cli_registry_lifecycle() {
let root = tempfile::tempdir().unwrap();
let dir = root.path().join("reg");
let dir_arg = dir.display().to_string();
let stdout = run_ok(&[
"registry".to_string(),
"--dir".to_string(),
dir_arg.clone(),
"init".to_string(),
]);
assert!(stdout.contains("MA key"), "{stdout}");
assert!(dir.join("registry.json").exists());
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mode = fs::metadata(dir.join("ma-key.hex"))
.unwrap()
.permissions()
.mode()
& 0o777;
assert_eq!(mode, 0o600);
}
let stdout = run_ok(&[
"registry".to_string(),
"--dir".to_string(),
dir_arg.clone(),
"show".to_string(),
]);
assert!(stdout.contains("version 1"));
let stdout = run_ok(&[
"registry".to_string(),
"--dir".to_string(),
dir_arg.clone(),
"add".to_string(),
"alice.frx.example".to_string(),
"ab".repeat(32),
]);
assert!(stdout.contains("added alice.frx.example"));
let stdout = run_ok(&[
"registry".to_string(),
"--dir".to_string(),
dir_arg.clone(),
"add-key".to_string(),
"alice.frx.example".to_string(),
"cd".repeat(32),
]);
assert!(stdout.contains("added key"));
let stdout = run_ok(&[
"registry".to_string(),
"--dir".to_string(),
dir_arg.clone(),
"list".to_string(),
]);
assert!(stdout.contains("alice.frx.example [source] (2 key(s))"));
let stdout = run_ok(&[
"registry".to_string(),
"--dir".to_string(),
dir_arg.clone(),
"revoke-key".to_string(),
"alice.frx.example".to_string(),
"ab".repeat(32),
]);
assert!(stdout.contains("revoked key"));
let stdout = run_ok(&[
"registry".to_string(),
"--dir".to_string(),
dir_arg.clone(),
"list".to_string(),
]);
assert!(stdout.contains("(1 key(s))"));
let port = common::free_port();
let _service = spawn_service(
&[
"registry".to_string(),
"--dir".to_string(),
dir_arg,
"serve".to_string(),
"--listen".to_string(),
format!("127.0.0.1:{port}"),
],
"registry serving",
);
let body = http_get(port, "/registry.json");
assert!(body.contains("\"members\""), "{body}");
assert!(body.contains("alice.frx.example"), "{body}");
}
#[test]
fn cli_key_rotation() {
let root = tempfile::tempdir().unwrap();
let config = root.path().join("frxd.toml");
let data = root.path().join("data");
let config_arg = config.display().to_string();
run_ok(&init_args(&config, "alice", 0, 1, &data));
let first = run_ok(&[
"--config".to_string(),
config_arg.clone(),
"key".to_string(),
"show".to_string(),
]);
let first = first.trim().to_string();
assert_eq!(first.len(), 64);
let stdout = run_ok(&[
"--config".to_string(),
config_arg.clone(),
"key".to_string(),
"rotate".to_string(),
]);
assert!(stdout.contains("old pubkey"), "{stdout}");
assert!(stdout.contains("new pubkey"), "{stdout}");
let second = run_ok(&[
"--config".to_string(),
config_arg,
"key".to_string(),
"show".to_string(),
]);
assert_ne!(first, second.trim(), "key did not change");
assert!(data.join("key.hex.bak").exists());
}
#[test]
fn cli_full_network_pipeline() {
let root = tempfile::tempdir().unwrap();