feat: add whoami, health, and check-key CLI subcommands

Three new subcommands for M4 CLI groundwork:
- whoami: show local identity key, fingerprint, hybrid key and group status
- health: check server connectivity via health RPC
- check-key: non-consuming lookup of a peer hybrid public key

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-22 12:50:40 +01:00
parent 00b0aa92a1
commit 230205a152
2 changed files with 131 additions and 2 deletions

View File

@@ -66,6 +66,85 @@ pub fn init_auth(ctx: ClientAuth) {
// -- Subcommand implementations -----------------------------------------------
/// Print local identity information from the state file (no server connection).
pub fn cmd_whoami(state_path: &Path, password: Option<&str>) -> anyhow::Result<()> {
let state = load_existing_state(state_path, password)?;
let identity = IdentityKeypair::from_seed(state.identity_seed);
let pk_bytes = identity.public_key_bytes();
let fingerprint = sha256(&pk_bytes);
println!("identity_key : {}", hex::encode(&pk_bytes));
println!("fingerprint : {}", hex::encode(&fingerprint));
println!(
"hybrid_key : {}",
if state.hybrid_key.is_some() {
"present (X25519 + ML-KEM-768)"
} else {
"not generated"
}
);
println!(
"group : {}",
if state.group.is_some() {
"active"
} else {
"none"
}
);
println!("state_file : {}", state_path.display());
Ok(())
}
/// Check server connectivity via the health RPC.
pub async fn cmd_health(server: &str, ca_cert: &Path, server_name: &str) -> anyhow::Result<()> {
let sent_at = current_timestamp_ms();
let client = connect_node(server, ca_cert, server_name).await?;
let req = client.health_request();
let resp = req.send().promise.await.context("health RPC failed")?;
let status = resp
.get()
.context("health: bad response")?
.get_status()
.context("health: missing status")?
.to_str()
.unwrap_or("invalid");
let rtt_ms = current_timestamp_ms().saturating_sub(sent_at);
println!("server : {server}");
println!("status : {status}");
println!("rtt : {rtt_ms}ms");
Ok(())
}
/// Check if a peer identity has registered a hybrid public key (non-consuming).
pub async fn cmd_check_key(
server: &str,
ca_cert: &Path,
server_name: &str,
identity_key_hex: &str,
) -> anyhow::Result<()> {
let identity_key = decode_identity_key(identity_key_hex)?;
let node_client = connect_node(server, ca_cert, server_name).await?;
let hybrid_pk = fetch_hybrid_key(&node_client, &identity_key).await?;
println!("identity_key : {identity_key_hex}");
println!(
"hybrid_key : {}",
if hybrid_pk.is_some() {
"available (X25519 + ML-KEM-768)"
} else {
"not found"
}
);
Ok(())
}
/// Connect to `server`, call health, and print RTT over QUIC/TLS.
pub async fn cmd_ping(server: &str, ca_cert: &Path, server_name: &str) -> anyhow::Result<()> {
let sent_at = current_timestamp_ms();