You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracks ADR 0005 D3 — the default confined-shell engine for this pass (L3 is the boundary, L2 is convenience). No brush fork, no upstream dependency.
Why
The brush CommandInterceptor (L2) requires a fork crates.io won't let us publish and that waits on reubeno/brush#1184 (#20) — so today the shell is a fail-closed stub (ADR 0003). ADR 0005 decouples: ship a usable, honestly-advisory confined shell now where bridle is the exec funnel, and let L3 (#31) become the boundary.
Scope — implement directly (no shell interpreter)
Pipelinesa | b — spawn N processes, wire stdout→stdin via OS pipes; check each argv0 against exec scope at the funnel.
Globs*.rs — expand with the glob crate against fs_read scope; refuse expansions that escape scope.
Sequencing/branching&&, ||, ; — exit-code logic over argv commands.
Redirections>, >>, <, 2>&1 — bridle opens the target (canonical fs_read/fs_write check, I6) and wires the fd.
Safe scalar expansion ($HOME-style env), quoting/word-splitting for argv parsing.
Reuse the shared leash plumbing: ToolContext, the Denial sink, the result envelope (sandbox_kind, I9).
Structurally refuse (least authority by construction — ADR 0001 "opaque ⇒ never cleared")
Command substitution $(...) / backticks; eval; process substitution <(...)/>(...); dynamic $VAR-as-command; functions; control flow with computed command names. Refused with a legible message (these are the undecidable interiors; they belong on the --yolo path, ADR 0003 / D5).
Notes
Even as L2 "convenience," this is a stronger advisory posture than an in-process hook over full bash: it never runs the dynamic attack surface and is the funnel for every spawn.
Tracks ADR 0005 D3 — the default confined-shell engine for this pass (L3 is the boundary, L2 is convenience). No brush fork, no upstream dependency.
Why
The brush
CommandInterceptor(L2) requires a fork crates.io won't let us publish and that waits on reubeno/brush#1184 (#20) — so today the shell is a fail-closed stub (ADR 0003). ADR 0005 decouples: ship a usable, honestly-advisory confined shell now where bridle is the exec funnel, and let L3 (#31) become the boundary.Scope — implement directly (no shell interpreter)
a | b— spawn N processes, wire stdout→stdin via OS pipes; check each argv0 againstexecscope at the funnel.*.rs— expand with theglobcrate againstfs_readscope; refuse expansions that escape scope.&&,||,;— exit-code logic over argv commands.>,>>,<,2>&1— bridle opens the target (canonicalfs_read/fs_writecheck, I6) and wires the fd.$HOME-style env), quoting/word-splitting for argv parsing.ToolContext, theDenialsink, the result envelope (sandbox_kind, I9).Structurally refuse (least authority by construction — ADR 0001 "opaque ⇒ never cleared")
$(...)/ backticks;eval; process substitution<(...)/>(...); dynamic$VAR-as-command; functions; control flow with computed command names. Refused with a legible message (these are the undecidable interiors; they belong on the--yolopath, ADR 0003 / D5).Notes
brush-bridle-coreengine (brush-bridle-core: optional full-bash shell engine (deferred, reversible — not the path to a usable shell) #20) is a feature-gated addition on the same seam, not a replacement.