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

32 lines
1.1 KiB
TOML

[package]
name = "hanzo-shell"
version = "0.1.0"
edition = "2021"
rust-version = "1.88"
license = "MIT"
repository = "https://github.com/hanzoai/mcp"
description = "Reads a shell command as a shell does and says allow, ask or deny: the classifier behind hanzo-mcp's exec, in pure Rust, with a wasm build."
[lib]
crate-type = ["rlib", "cdylib"]
[dependencies]
# bash grammar (MIT). A pure-Rust PEG parser and word expander; the parse is the AST this
# crate walks, so no regex or word list decides what a command is.
brush-parser = "=0.4.0"
# Python 3 grammar (MIT), pure Rust, no build step. Fails closed on syntax newer than its
# grammar (PEP 701 f-strings, 3.14), which is read as "cannot be read".
rustpython-parser = "=0.4.0"
rustpython-ast = { version = "=0.4.0", features = ["visitor"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
wasm-bindgen = { version = "=0.2.127", optional = true }
[features]
default = []
# The wasm-bindgen surface: `classify(command, options_json) -> verdict_json`.
wasm = ["dep:wasm-bindgen"]
[dev-dependencies]
tempfile = "3"