Floor
NAME
MCP::Client::Policy::Floor - the danger floor: a fixed, auditable set of rules for the operations that are dangerous no matter who asked
DESCRIPTION
The danger floor is a permission posture no preset relaxes: the handful of operations that destroy work, hand over the machine, or let the agent edit its own permissions. It is deliberately a plain rule list plus a few named predicates ā never a classifier ā so it can be read, tested and reasoned about line by line.
Two pieces plug into a MCP::Client::Policy:
danger-floor(...)returns the rules, in the ordinaryMCP::Client::Policy::Rulesschema. Prepend them to a policy's rules (they are just data). Most are expressible as command/args matches; the few that need to look at what a command targets carry acheck.floor-checks(...)returns thechecksmap thosecheckrules name ā the target analysis forrm, and the shell-redirect analysis for writes to protected files. These are code, passed to the policy aschecks.
The split
Almost everything asks (grantable, but the prompt is shown in red because each
rule carries severity => 'danger' and a note saying why). Only two
things are a hard deny that even the bypass preset cannot waive: a recursive
delete of the filesystem root or your home directory, and a write to the
agent's own policy/config. Everything else ā force-pushes, reset --hard,
sudo, curl | sh, shutdown, dd ā is a red ask.
What the floor leaves to the sandbox
The write checks are lexical and best-effort: they resolve ~, ~user and
.., and read both redirection targets and path arguments (so tee, cp
and sed -i are caught as well as >). Three shapes they deliberately do
not catch, because the target is not knowable lexically, are left to the OS
sandbox layer (which makes $SADNA_HOME read-only): a redirect to an
unreadable variable (> $CFG), a purely relative path (no working
directory to measure from), and a glob whose expansion is unknown
(> ~/.sadna/conf* ā the literal prefix is under the config dir, but the
decomposer drops the whole word once any part of it expands). The floor is the
approval layer; the sandbox is the containment layer, and the two are meant to
be composed.
SYNOPSIS
use MCP::Client::Policy;
use MCP::Client::Policy::Floor;
my $home = %*ENV<HOME>;
my $sadna = "$home/.sadna";
my $policy = MCP::Client::Policy.new(
:$provider,
rules => [ |danger-floor(:$home, sadna-home => $sadna), |@my-rules ],
checks => floor-checks(:$home, sadna-home => $sadna),
);