Skip to main content

Module shell_allowlist

Module shell_allowlist 

Source
Expand description

Shell command lexing and the registered shell-allowlist gate.

The lexical layer (lexer, heredocs, tokenizer, compound and case constructs, PowerShell statements) and the security mode live here in the Engine. The allowlist POLICY (enforcement, approval, self-reconfiguration and side-door checks) lives above the Engine in crates/lean-ctx-shell-policy (lib lean_ctx_shell_policy): an edit there re-checks that crate, not the Engine. The Engine’s own callers reach the policy through register_gate, which the policy crate installs; without a registration every check fails closed.

Structs§

ShellGate
The shell-allowlist policy as the Engine sees it.

Enums§

Dialect
The shell that actually executes the checked line. The check cannot read this from the process: ctx_execute always runs bash -c on Unix and the hook for the Bash tool hands the line to bash, whatever shell this process resolves, while the PowerShell tool runs PowerShell.
ShellSecurity
Active shell-security posture. Order is least → most permissive only for readability; do not rely on ordinal values.

Constants§

MAX_VALIDATED_COMMAND_BYTES
Longest command the gate validates; a longer one is refused in enforce mode. Every check re-scans the line, and a hook that runs out of time fails open.

Functions§

check_registered
Check command against the registered policy. Fails closed (refuses) when no policy is registered, so a binary that forgot the registration can never run unchecked commands.
contains_double_semicolon
Quote-aware scan for a ;; terminator (the case arm separator).
expand_to_leaf_segments
Expand a (possibly compound) command into the list of simple-command leaves that must each satisfy the allowlist. This is what makes for … do CMD; done, if COND; then CMD; fi, while …; do CMD; done and balanced ( CMD ) subshells usable in restricted mode without weakening deny-by-default: every leaf is still validated, headers/terminators contribute nothing, and any form this conservative walker cannot prove safe (case/esac, ;;, a subshell with trailing content, deep nesting) is rejected — it over-blocks, never under-blocks.
find_shell_word
Return the first standalone unquoted shell word word at or after start.
gate_registered
Whether a policy gate is installed.
heredoc_delims
The delimiters of the heredoc operators in line, in source order (only quoted ones with quoted_only). A << inside quotes, ${…} or arithmetic is no operator; a <<< here-string has no body.
read_heredoc_delim
Parse a heredoc delimiter token starting at start, returning its bare name (quotes/escapes removed), whether any part was quoted, and the index just past the token. None when no delimiter is present.
register_gate
Install the policy gate. The first registration wins and is never replaced: returns false when a gate was already registered, so the caller can refuse to start instead of running under a gate it did not install.
rewrite_case_constructs
Replace each case construct with all of its arm bodies. Pattern labels select which body runs, but they are not commands and must not enter the allowlist walk. Including every body preserves deny-by-default validation: every command that could execute for any pattern must be allowlisted.
strip_all_heredoc_bodies
Like strip_quoted_heredoc_bodies but strips bodies for all heredocs (quoted and unquoted delimiters). Use for checks that must never interpret heredoc body content as commands or redirects (#931).
strip_for_analysis
command without heredoc bodies (only quoted ones with quoted_only) and, with comments, without comments — in one lexer pass over the raw text, so neither strip can misread what the other one removed.
warn_only_reason_registered
The warn-only reason through the registered policy (the message itself when none is registered).
with_dialect
Runs f with the allowlist reading the line for the shell that will execute it, instead of the one this process resolves.