Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ breaking entries are marked **BREAKING**.
- **Wrapped commands** (`kaish_kernel::tools::wrapped`, `subprocess` feature):
register an external program as a tool with a declared grammar. Verbs and flags
are deny-by-default, refused with exit 2 before any spawn; the kernel renders
argv. Runs with `allow_external_commands` off. See `docs/wrapped_command.md`.
argv. It narrows rather than widens: `allow_external_commands = false` plus
named wrappers is the intended shape. See `docs/wrapped_command.md`.
- **`ValidationIssue::command`** — the command an issue concerns, when one is
genuinely known (`UndefinedCommand`'s name, a builtin's own regex/schema
failure), so an embedder can route on it instead of parsing `message`.
Expand Down
8 changes: 8 additions & 0 deletions crates/kaish-kernel/src/tools/wrapped.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
//! renders the argv itself, so a value is never parsed as a flag by the child
//! unless the declaration put it in flag position.
//!
//! This narrows what a kernel can run; it does not widen it.
//! `allow_external_commands` chooses between "no word spawns anything" and
//! "every program on `$PATH` spawns, with any arguments." A wrapped command is
//! the setting between: the executable is pinned at registration, so a changed
//! `$PATH` changes nothing, and an undeclared verb or flag is refused before
//! any spawn. Registering wrappers with the switch left `false` is the intended
//! shape, not a way around it.
//!
//! ```no_run
//! use kaish_kernel::tools::wrapped::{Flag, Positional, Verb, WrappedCommand};
//!
Expand Down
10 changes: 7 additions & 3 deletions docs/wrapped_command.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,9 +430,13 @@ and the two names that collide:
optional slot without it.
- A relative `path_under(root)` — the root must be an absolute path.

A wrapped command is a registered tool, not an external command. It runs when
`allow_external_commands` is `false`. It needs the `subprocess` feature; a
sandbox build has no `wrapped` module.
A wrapped command is a registered tool, not an external command, so
`allow_external_commands` does not gate it. That switch is not a lock a wrapper
picks: it decides whether an arbitrary word becomes a `$PATH` lookup. A wrapper
is the narrower grant beside it — one pinned executable, one declared grammar.
Leaving the switch `false` and registering a wrapper is the point.

It needs the `subprocess` feature; a sandbox build has no `wrapped` module.

## What the kernel owns, and what the embedder owns

Expand Down