Files
zeekay 25c6f62cff feat(rust): hanzo-shell reads exec's command and says allow, ask or deny
A pure-Rust classifier for the `Classify` seam. brush-parser (MIT) gives the bash AST
and rustpython-parser (MIT) the Python one; every simple command, redirection,
substitution and nested script (bash -c, here-documents, a script the command wrote and
runs, python -c, ssh host '...') is read in the order the shell runs them, and the policy
over paths decides what each costs. rust/shell is its own crate with a wasm-bindgen build,
so kai-gateway can replace safety.ts with it.

exec: an ask is refused until the call carries approve: true (never lifts a deny); the
interpreter must be a shell the classifier reads; the env is read beside the command;
the git tool asks the same classifier and runs with core.fsmonitor=false; ui install no
longer hands the component name to sh -c.

On 408,231 Bash commands: safety.ts flags 20.69% (15.27% unparsed); this answers
allow 88.2 / ask 9.6 / deny 2.2 (roots set), cannot read 0.22%, p99 0.6 ms.
2026-10-14 16:32:13 -07:00

24 lines
832 B
Rust

//! `classify [--cwd DIR] [--home DIR] [--root DIR]... COMMAND`: prints the report as JSON.
use hanzo_shell::{classify, Context};
fn main() {
let mut args = std::env::args().skip(1);
let mut ctx = Context::new(None, None);
let mut command = None;
while let Some(a) = args.next() {
match a.as_str() {
"--cwd" => ctx.cwd = args.next(),
"--home" => ctx.home = args.next(),
"--root" => ctx.roots.extend(args.next()),
"--remote" => ctx.remote = true,
_ => command = Some(a),
}
}
let Some(command) = command else {
eprintln!("usage: classify [--cwd DIR] [--home DIR] [--root DIR] COMMAND");
std::process::exit(2);
};
println!("{}", serde_json::to_string_pretty(&classify(&command, &ctx)).unwrap_or_default());
}