gen_audit_cli/
gen_audit_cli.rs

1//! Generate valid test audit files for CLI testing
2//! Run with: cargo run --example gen_audit_cli
3
4use chrono::Utc;
5use std::fs::File;
6use std::io::Write;
7use uuid::Uuid;
8use vex_core::{AuditEvent, AuditEventType, Hash, MerkleTree};
9use vex_persist::audit_store::AuditExport;
10
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12    let agent_id = Uuid::new_v4();
13
14    // Event 1: Root Creation
15    let e1 = AuditEvent::new(
16        AuditEventType::AgentCreated,
17        Some(agent_id),
18        serde_json::json!({"role": "Root Agent", "model": "deepseek-chat"}),
19        0,
20    );
21
22    // Event 2: Execution (chained)
23    let e2 = AuditEvent::chained(
24        AuditEventType::AgentExecuted,
25        Some(agent_id),
26        serde_json::json!({"prompt": "What is the meaning of life?", "confidence": 0.95}),
27        e1.hash.clone(),
28        1,
29    );
30
31    // Event 3: Another execution (chained)
32    let e3 = AuditEvent::chained(
33        AuditEventType::AgentExecuted,
34        Some(agent_id),
35        serde_json::json!({"prompt": "Follow-up question", "confidence": 0.87}),
36        e2.hash.clone(),
37        2,
38    );
39
40    let events = vec![e1.clone(), e2.clone(), e3.clone()];
41
42    // Build Merkle Tree
43    let leaves: Vec<(String, Hash)> = events
44        .iter()
45        .map(|e| (e.id.to_string(), e.hash.clone()))
46        .collect();
47    let tree = MerkleTree::from_leaves(leaves);
48
49    let export = AuditExport {
50        events: events.clone(),
51        merkle_root: tree.root_hash().map(|h| h.to_string()),
52        exported_at: Utc::now(),
53        verified: true,
54    };
55
56    // 1. Save Valid Audit
57    let valid_json = serde_json::to_string_pretty(&export)?;
58    let mut file = File::create("audit_valid.json")?;
59    file.write_all(valid_json.as_bytes())?;
60    println!("✓ Generated audit_valid.json (3 events)");
61
62    // 2. Save Tampered Audit (Change data but keep original hash/root)
63    let mut tampered_export = export.clone();
64    tampered_export.events[1].data = serde_json::json!({"prompt": "TAMPERED DATA"});
65    // Note: Hash is NOT updated, so verification should FAIL
66
67    let tampered_json = serde_json::to_string_pretty(&tampered_export)?;
68    let mut file = File::create("audit_tampered.json")?;
69    file.write_all(tampered_json.as_bytes())?;
70    println!("✓ Generated audit_tampered.json (data tampered)");
71
72    // 3. Save Tampered Root
73    let mut tampered_root_export = export.clone();
74    tampered_root_export.merkle_root = Some("fake_root_abc123".to_string());
75
76    let tampered_root_json = serde_json::to_string_pretty(&tampered_root_export)?;
77    let mut file = File::create("audit_tampered_root.json")?;
78    file.write_all(tampered_root_json.as_bytes())?;
79    println!("✓ Generated audit_tampered_root.json (root tampered)");
80
81    println!("\nTest with:");
82    println!("  vex verify -a audit_valid.json          # Should pass");
83    println!("  vex verify -a audit_tampered.json       # Should fail (hash mismatch)");
84    println!("  vex verify -a audit_tampered_root.json  # Should fail (root mismatch)");
85
86    Ok(())
87}