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

16 lines
840 B
JavaScript

// Smoke test of the wasm build: node rust/shell/tests/wasm.mjs <dir with hanzo_shell.js>
import { createRequire } from "node:module";
import assert from "node:assert/strict";
const { classify } = createRequire(import.meta.url)(process.argv[2] + "/hanzo_shell.js");
const options = JSON.stringify({ cwd: "/work/app", home: "/home/me" });
const risk = (c) => JSON.parse(classify(c, options)).risk;
assert.equal(risk("ls -la"), "allow");
assert.equal(risk("rm -rf build"), "allow");
assert.equal(risk("rm -rf /"), "deny");
assert.equal(risk("git push origin main"), "ask");
assert.equal(risk("python3 -c \"import os; os.system('sudo id')\""), "deny");
assert.equal(risk("cat .env"), "deny");
const report = JSON.parse(classify("sudo id", options));
assert.deepEqual(report.findings.map((f) => f.kind), ["privilege"]);
console.log("wasm ok");