Expand description
P5-1 (COMPOSABLE-HARNESS-DESIGN.md §5.3 risk 1, D-3): the command canonicalizer — the security-critical parser rule-matching depends on.
Why tree-sitter, not a hand-rolled splitter (risk-1 mitigation, §5.3:
“tree-sitter-based parsing (oc’s proven approach, oc§1) rather than a
hand-rolled splitter”): a regex/split-on-; approach cannot distinguish a
real separator from one that’s quoted (echo "a; b" is ONE command), and
cannot recurse into $(...)/backtick command substitution without
reimplementing a chunk of shell grammar by hand — exactly the class of bug
this design calls “a silent privilege escalation” (§5.3 risk 1). This
module instead asks tree-sitter-bash (the same grammar opencode’s own
parser uses, oc§1) to build a real parse tree and walks it.
Fail-closed contract (the load-bearing invariant): canonicalize
NEVER returns a silently-empty or silently-optimistic result for input it
can’t fully make sense of. Any parse error (an ERROR/MISSING node
anywhere in the tree) yields CanonResult::Unparseable — callers MUST
treat that as “requires approval”, never “allow” (see
crate::permissions::rules::evaluate_command, which does exactly this).
Structs§
- Canon
Subcommand - One extracted sub-command: its canonicalized argv, and whether it is
“opaque” — a wrapper whose real effect can’t be statically resolved, so
crate::permissions::rules::evaluate_commandmust never let it resolve toAllowpurely by absence of a matching rule.
Enums§
- Canon
Result - The result of
canonicalize: either a flat list of every sub-command found (top-level compounds, and every command nested inside a$(...)/backtick substitution anywhere in the tree — see the module doc for why a single recursivecommand-node walk is sufficient to find both), or a fail-closed reason a caller must treat as REQUIRING approval.
Functions§
- canonicalize
- Parse
command(a bash command string, as a model would pass to thebash/shelltool) into its canonical sub-commands — the D-3 security core every rule-engine decision incrate::permissions::rulesis built on. See the module doc comment for the fail-closed contract.