use std::fs; use std::path::PathBuf; use anyhow::Context; use anyhow::Result; use clap::Parser; use codex_execpolicy2::PolicyParser; /// CLI for evaluating exec policies #[derive(Parser)] #[command(name = "codex-execpolicy2")] enum Cli { /// Evaluate a command against a policy. Check { #[arg(short, long, value_name = "PATH", required = true)] policies: Vec, /// Command tokens to check. #[arg( value_name = "COMMAND", required = true, trailing_var_arg = true, allow_hyphen_values = true )] command: Vec, }, } fn main() -> Result<()> { let cli = Cli::parse(); match cli { Cli::Check { policies, command } => cmd_check(policies, command), } } fn cmd_check(policies: Vec, args: Vec) -> Result<()> { let policy = load_policies(&policies)?; let eval = policy.check(&args); let json = serde_json::to_string_pretty(&eval)?; println!("{json}"); Ok(()) } fn load_policies(policy_paths: &[PathBuf]) -> Result { let loaded_policies: Vec<(String, String)> = policy_paths .iter() .map(|policy_path| { let policy_file_contents = fs::read_to_string(policy_path) .with_context(|| format!("failed to read policy at {}", policy_path.display()))?; let policy_identifier = policy_path.to_string_lossy().to_string(); Ok((policy_identifier, policy_file_contents)) }) .collect::>() .context("failed to load policy files")?; let mut parser = PolicyParser::new(); for (policy_identifier, policy_file_contents) in &loaded_policies { parser.parse(policy_identifier, policy_file_contents)?; } Ok(parser.build()) }