supercode-harness 0.4.6

The optional native Supercode agent and tool harness
Documentation
//! P5-1 (COMPOSABLE-HARNESS-DESIGN.md §2 modules 10-11, §2.1 D-3, §2.2 C5,
//! §5.3 risk 1): the permissions engine — command canonicalization + rule
//! algebra + approval policy/cache + oc/cx import translators.
//!
//! **Risk 1 (§5.3): "a wrong translation is a SILENT privilege escalation."**
//! This module is built to that standard: ONE engine, ONE evaluation order
//! (deny→ask→allow first-match, [`rules`]); a tree-sitter-based canonicalizer
//! that fails CLOSED on anything it can't parse cleanly ([`canon`]); an
//! import translator that WARNS (never silently) when a translated rule's
//! fixed point differs from its source ([`translate`]); and a golden-vector +
//! adversarial-bypass test suite (`crates/harness/tests/permissions_engine.rs`)
//! pinning the documented cc§4/oc§4 semantics as a regression bar.
//!
//! **Integration.** The engine activates via
//! `capabilities.permissions.enabled` ([`crate::Config::permissions_enabled`],
//! populated by `crate::configfile::materialize_config`) and is consumed at
//! `crate::agent::Agent`'s tool-dispatch gate
//! (`Agent::prepare_tool_call`). DEFAULT: disabled — the gate falls through
//! to the pre-P5-1 [`crate::Config::needs_approval`] path byte-for-byte, so
//! every existing test and today's default posture (approval=never,
//! sandbox=none) is unchanged.
//!
//! **`protected_paths` coverage, honestly stated (F4, Fable-5 adversarial
//! review; corrected by the F6/F7 delta review, the round-3 delta review,
//! then the round-4 delta review below).**
//! `capabilities.permissions.protected_paths` is a RULE-LAYER floor, not an
//! OS-level one: it is enforced for file-tool calls (`read_file`/
//! `write_file`/`edit_file`), for a bash command's direct shell redirect
//! targets and a best-effort set of known argv-writers (`tee`, `dd of=`,
//! `cp`/`mv`/`install`/`ln` — including their `-t DIR`/
//! `--target-directory=DIR` form (F6) and its getopt-bundled short-flag
//! equivalent `-ft DIR`/`-Dt DIR`/… (round-3) — `sed -i`, `truncate`,
//! `sort -o FILE`, `split`'s PREFIX (round-3 hardening) — see
//! `canon::known_writer_targets`'s doc comment for that heuristic's named
//! gaps), and for `apply_patch`'s target path(s). A write this layer
//! RECOGNIZES but can't statically resolve to a concrete destination — an
//! opaque wrapper, a `$VAR`/`` `cmd` `` dynamic target, an unquoted glob
//! metacharacter (`*`/`?`/`[`) that bash would pathname-expand before the
//! write (F7), or a known argv-writer flag shape [`canon::
//! known_writer_targets`] can't confidently resolve to a destination token
//! (F6, including its round-3 bundled-short-flag extension, and — round-4 —
//! the SAME bundled-short-flag extension now also covering `sed -i` and
//! `sort -o`) — is forced to at least `Ask`, NEVER silently `Allow`. This is
//! now true without exception for every write shape this rule layer claims
//! to cover (the F6/F7 delta review found and closed two forms where it
//! wasn't; the round-3 delta review found and closed a third: F6's own fix
//! didn't yet recognize a getopt-BUNDLED short-flag `-t`, e.g.
//! `cp -ft .git a`; the round-4 delta review found and closed a fourth:
//! round-3's bundled-short-flag fix was only made `-t`-specific, leaving
//! the identical blind spot open on `sed -i`/`sort -o` — `sed -ni
//! s/../PWNED/ .env` and `sort -uo .env a` both still fell through to a
//! silent `Allow`). Round-4 closes this as a CLASS, not a third patched
//! instance: every flag-driven known-writer detection (`-t` for
//! cp/mv/install/ln, `-i` for sed, `-o` for sort) now routes through one
//! shared, generalized bundled-short-flag scan
//! (`canon::known_writer_targets`'s doc comment names it) — a future
//! flag-driven writer inherits the fix by construction instead of needing
//! its own bundled-flag audit.
//!
//! **What "claims to cover" does NOT mean, stated plainly (round-3
//! hardening; then STOP enumerating).** `sort -o`/`split` (round-3) are new
//! ADDITIONS to the enumerated-writer set, not a fix to a row already
//! claimed covered — before that change, a write via `sort -o`/`split`
//! simply wasn't recognized AT ALL, i.e. a false-`Allow` gap of exactly the
//! same shape every OTHER un-enumerated writer still is today: any
//! interpreter's own file-write builtins, a compiler's `-o`, a database
//! client's export command, or any other bash construct this rule layer
//! doesn't specifically parse. This module does not, and does not claim to,
//! enumerate every file-writing command that could ever appear in a bash
//! tool call — doing so is an unbounded, always-incomplete list. What IS
//! true, and load-bearing, is the narrower claim above: for every write
//! SHAPE this rule layer *does* recognize (the enumerated writers, shell
//! redirects, `apply_patch`), fail-closed holds without exception — an
//! unresolvable target never silently resolves to `Allow`. An
//! un-enumerated writer is a false NEGATIVE at this rule layer (nothing
//! flagged, default policy decides), honestly named here rather than
//! silently claimed covered — complete OS-level write confinement of
//! arbitrary bash, which closes that gap entirely regardless of which
//! command wrote the file, is `capabilities.permissions.sandbox`'s job (P5
//! module 10, a later unit), not this rule-layer heuristic's. See
//! [`crate::Config::permissions_protected_paths`]'s doc comment for the
//! same note where the config field is defined.

pub mod approval;
pub mod canon;
pub mod rules;
pub mod translate;

pub use approval::{
    decision_to_approved, resolve_ask, ApprovalCache, ApprovalOutcome, ApprovalRequest,
    PermissionsApprovalHandler,
};
pub use canon::{canonicalize, CanonResult, CanonSubcommand};
pub use rules::{
    evaluate_command, evaluate_path, evaluate_path_safe, evaluate_path_subject_safe,
    protected_path_deny_rules, Decision, PathKind, RuleSet,
};
pub use translate::{
    opencode_default_policy, translate_last_match_to_first_match, SourceRule, Translated,
};