agentguard/commands/
sim.rs

1use agentguard_core::authorize::build_entities;
2use agentguard_core::{AgentRequest, Authorizer, PolicyStore};
3use anyhow::Result;
4use std::path::Path;
5use tokio::io::AsyncReadExt;
6
7pub async fn run(
8    store: impl AsRef<Path>,
9    request: impl AsRef<Path>,
10    entities_path: Option<impl AsRef<Path>>,
11    output: &str,
12) -> Result<()> {
13    let text = if request.as_ref().as_os_str() == "-" {
14        let mut buf = String::new();
15        tokio::io::stdin().read_to_string(&mut buf).await?;
16        buf
17    } else {
18        tokio::fs::read_to_string(request.as_ref()).await?
19    };
20    let req: AgentRequest = serde_json::from_str(&text)?;
21
22    let entities = if let Some(p) = entities_path {
23        let path = p.as_ref().to_path_buf();
24        tokio::task::spawn_blocking(move || -> Result<cedar_policy::Entities> {
25            let text = std::fs::read_to_string(&path)?;
26            let arr: Vec<serde_json::Value> = serde_json::from_str(&text)?;
27            Ok(build_entities(arr)?)
28        })
29        .await
30        .map_err(|e| anyhow::anyhow!("blocking task: {e}"))??
31    } else {
32        cedar_policy::Entities::empty()
33    };
34
35    let store_path = store.as_ref().to_path_buf();
36    let req_for_blocking = req.clone();
37    let entities_for_blocking = entities.clone();
38    let decision =
39        tokio::task::spawn_blocking(move || -> Result<agentguard_core::authorize::Decision> {
40            let store = PolicyStore::open(&store_path)?;
41            let engine = Authorizer::new(store)?;
42            Ok(engine.authorize(&req_for_blocking, &entities_for_blocking)?)
43        })
44        .await
45        .map_err(|e| anyhow::anyhow!("blocking task: {e}"))??;
46
47    if output == "json" {
48        println!("{}", serde_json::to_string_pretty(&decision)?);
49    } else {
50        let sym = match decision.effect {
51            agentguard_core::authorize::Effect::Allow => "✓ ALLOW",
52            _ => "✗ DENY ",
53        };
54        println!(
55            "{}  {} → {} on {}",
56            sym, req.principal, req.action, req.resource
57        );
58        if !decision.policies.is_empty() {
59            println!("    policies: {}", decision.policies.join(", "));
60        }
61        for r in &decision.reasons {
62            println!("    reason:   {}", r);
63        }
64    }
65    Ok(())
66}