use serde_json::Value;
use vta_cli_common::render::{DIM, GREEN, RED, RESET, bin_name};
use crate::vtc::{self, VtcTarget};
pub async fn cmd_verify(
keyring_key: &str,
target: &VtcTarget,
) -> Result<(), Box<dyn std::error::Error>> {
let vtc = vtc::connect(keyring_key, target).await?;
let body: Value = vtc.client.audit_verify().await.map_err(|e| {
vtc::super_admin_call_error("VTC audit verify", e, &vtc.client_did, bin_name())
})?;
let verified = body["verified"].as_bool().unwrap_or(false);
let examined = body["entriesExamined"].as_u64().unwrap_or(0);
let chain_verified = body["entriesVerified"].as_u64().unwrap_or(0);
let legacy = body["legacySkipped"].as_u64().unwrap_or(0);
let unparseable = body["unparseableSkipped"].as_u64().unwrap_or(0);
if verified {
println!("{GREEN}✓ audit chain verified{RESET}");
} else {
println!("{RED}✗ audit chain BROKEN{RESET}");
}
println!(" {DIM}entries examined:{RESET} {examined}");
println!(" {DIM}chain-verified: {RESET} {chain_verified}");
if let Some(head) = body["head"].as_str() {
println!(" {DIM}chain head: {RESET} {head}");
}
if legacy > 0 {
println!(
" {RED}legacy rows skipped: {legacy}{RESET} \
{DIM}(pre-v2 rows are not chain-checked — on a store that should\n\
\x20 have none, this is itself a finding){RESET}"
);
}
if unparseable > 0 {
println!(
" {RED}unparseable rows skipped: {unparseable}{RESET} \
{DIM}(corrupt or forward-version rows, also unchecked){RESET}"
);
}
let checkpoints = checkpoint_block(&body);
let cp_status = checkpoints["status"].as_str().unwrap_or("unknown");
let cp_detail = checkpoints["detail"].as_str();
let cp_broken = !matches!(cp_status, "consistent" | "noCheckpoints");
println!();
match cp_status {
"consistent" => {
let attested = checkpoints["attestedEntries"].as_u64().unwrap_or(0);
let unattested = checkpoints["unattestedEntries"].as_u64().unwrap_or(0);
let count = checkpoints["verifiedCheckpoints"].as_u64().unwrap_or(0);
println!(
"{GREEN}✓ signed checkpoints consistent{RESET} {DIM}({count} verified){RESET}"
);
println!(" {DIM}attested entries:{RESET} {attested}");
if let Some(at) = checkpoints["newestCheckpointAt"].as_str() {
println!(" {DIM}newest checkpoint:{RESET} {at}");
}
if unattested > 0 {
println!(
" {DIM}unattested tail: {RESET} {unattested} {DIM}(written since the last checkpoint — signed by nothing yet){RESET}"
);
}
}
"noCheckpoints" => {
println!("{RED}! no signed checkpoints{RESET}");
if let Some(d) = cp_detail {
println!(" {DIM}{d}{RESET}");
}
}
_ => {
println!("{RED}✗ signed checkpoints FAILED ({cp_status}){RESET}");
if let Some(d) = cp_detail {
println!(" {RED}{d}{RESET}");
}
}
}
if let Some(brk) = body.get("chainBreak").filter(|v| !v.is_null()) {
let kind = brk["kind"].as_str().unwrap_or("?");
let index = brk["index"].as_u64().unwrap_or(0);
let event_id = brk["eventId"].as_str().unwrap_or("?");
println!();
println!(" {RED}break:{RESET} {kind} at index {index} (event {event_id})");
match kind {
"tamperedEntry" => {
println!(" {DIM}That envelope's content changed after it was written.{RESET}")
}
"brokenLink" => println!(
" {DIM}An entry was reordered, dropped, or inserted at this point.{RESET}"
),
_ => {}
}
}
if !verified {
println!();
println!(
"{DIM}Note: the chain alone proves internal consistency, not authenticity —\n\
it is unsigned, so an adversary with store write access can restamp a\n\
forged suffix. The checkpoint result above is the signed half.{RESET}"
);
return Err("audit chain verification failed".into());
}
if cp_broken {
println!();
if matches!(cp_status, "truncated" | "headMismatch" | "chainBroken") {
println!(
"{RED}The hash chain is internally consistent but contradicts a signature made\n\
with the community key. That is what a store-level tamper looks like:\n\
the surviving log was re-stamped to look correct.{RESET}"
);
} else {
println!(
"{RED}The VTC's report carries no checkpoint result this client can read\n\
(status `{cp_status}`), so the signed half is unverified. Upgrade `cnm` or\n\
the VTC so both speak the same audit/verify report.{RESET}"
);
}
return Err("audit checkpoint verification failed".into());
}
Ok(())
}
fn checkpoint_block(body: &Value) -> &Value {
let ext = &body["ext"]["org.openvtc"]["checkpoints"];
if ext.is_object() {
ext
} else {
&body["checkpoints"]
}
}
#[cfg(test)]
mod tests {
use super::checkpoint_block;
use serde_json::json;
#[test]
fn checkpoints_are_read_from_ext_and_from_the_old_top_level_place() {
let current = json!({ "verified": true,
"ext": { "org.openvtc": { "checkpoints": { "status": "truncated" } } } });
assert_eq!(checkpoint_block(¤t)["status"], "truncated");
let legacy = json!({ "verified": true, "checkpoints": { "status": "consistent" } });
assert_eq!(checkpoint_block(&legacy)["status"], "consistent");
assert!(checkpoint_block(&json!({}))["status"].is_null());
}
}