Skip to main content

Crate safe_chains

Crate safe_chains 

Source

Re-exports§

pub use verdict::SafetyLevel;
pub use verdict::Verdict;

Modules§

allowlist
cli
cst
docs
engine
The behavioral capability model engine (docs/design/behavioral-taxonomy-v1.4.md).
parse
pathctx
The directory context the harness supplies (HP-19): the working directory a command runs in, and the project root. It exists to make relative-path classification honest — cd /etc && echo > ./x must be seen as writing /etc/x, not a worktree file.
pathgate
Cross-cutting path-operand gate (adversarial-review audit fix). The engine gates its 15 resolved commands’ file reads/writes by locus (HP-20); the ~1600 legacy commands are a parallel surface. pathgates.toml describes, per legacy command, the ROLE each path argument plays — read (a disclosing read), write (a write-target), or ignore (a URL, an -i identity, a converter’s transcode input) — and a single walker here gates each path by the matching locus face. Roles come from a positional policy (with skip_first / last_write / remote_aware modifiers) plus a per-flag map; the three flat lists (read / read_after_first / write) are shorthand for the common positional policies. awk is gated in its own handler instead (its regex programs contain / and $).
policy
registry
suggest
--suggest: generate the minimal custom-command TOML that would let safe-chains recognize a command it currently denies because the command NAME is unknown.
targets
verdict

Enums§

ReachReason
Why a not-auto-approved command’s path reach was flagged — so the nudge can explain the actual reason instead of a one-size-fits-all “outside the working directory”. A peer’s hidden file and a path genuinely above cwd both deny, but the remedy differs, and conflating them is what reads as “directory parsing is broken”.

Functions§

command_verdict
command_verdict_at_level
Classify command against an UPPER-band level (local-admin/network-admin/yolo), which has no 3-value legacy ceiling. Every engine-resolved leaf is decided by Level::admits against level instead of the lower-band projection; a Denied on any segment dominates. Legacy (unresolved) leaves keep their local-safe SafeWrite-or-below verdict, which every upper level admits. The result is Allowed(SafeWrite) (accepted by the shared upper ceiling) or Denied.
command_verdict_ceilinged
The ceilinged verdict: classify command at (threshold, engine_level), gating the projected level <= threshold. The single seam both the CLI (--level) and the hook (configured level) funnel through. engine_level = Some classifies via Level::admits (the fine per-level model); None uses the 3-band projection. Either way the result is gated to threshold, so a legacy leaf that bypasses the engine (a redirect write → SafeWrite) is still held under a lower ceiling.
command_verdict_in
Classify command with the harness-supplied directory context installed (HP-19), so relative paths resolve against the real cwd/root. command_verdict(cmd) is the no-context form (PathCtx::default()), preserving every existing caller.
configured_hook_ceiling
The auto-approve ceiling the HOOK evaluates at, from the write-protected user config (~/.config/safe-chains.toml, level = "…"). No config, or an unknown name → the default developer band (SafeWrite, no engine level) — fail-safe. Honored ONLY from the user config, never a repo .safe-chains.toml; the file is write-denied, so an agent cannot set its own ceiling.
explain_with_coverage_at_level
The coverage-fallback explanation (built-in classifier + the user’s permissions.allow patterns), computed UNDER the configured engine level so a covered command honors that level’s rule — a worktree destroy an editor plan forbids classifies as denied here too, not re-admitted. None engine level → the plain 3-band coverage (paranoid/reader/default). The caller still gates the result’s overall <= threshold; running under the level closes the last path a lower plan’s tighter rule could leak through.
is_safe_command
level_ceiling
Resolve a level NAME to its (3-band ceiling, engine level for admits), or None for an unknown name. The ceiling gates the projected verdict; the engine level (when present) classifies per-level via admits, exposing distinctions the 3-band projection flattens — editor (no destroy, no sibling write) vs developer, and the upper band (git push, bulk-object-read, sudo). paranoid/ reader are pure ceilings (their read/inert bands need no admits), and developer IS the default band, so those carry no engine level. Legacy aliases (safe-write) canonicalize first.
upper_level_by_name
The &'static Level for an UPPER-band level name, or None for the lower band (which the 3-value ceiling already handles) or an unknown name. The caller passes the CANONICAL name (legacy aliases already resolved).
workspace_overreach
If a NOT-auto-approved command reaches a path OUTSIDE the workspace, return that path (its original spelling) and WHY, so the hook can nudge instead of silently prompting. Resolves against the ambient cwd/root: relative worktree paths, /tmp, and /dev streams are admitted and skipped; an absolute or home path that isn’t admitted for read or write is the reach. A credential store outranks the hidden-peer wording; a hidden peer path outranks the generic outside-workspace reason.