pub struct CompiledPolicy<'p> { /* private fields */ }Expand description
A policy with all patterns compiled for one evaluation context.
Compile once per process (or per policy reload) and reuse for every tool
call; compilation dominates the cost of a single decision. It borrows the
policy (Self::compile) or owns it (Self::compile_owned, for a caller
such as openmoat-sdk that keeps one engine for as long as it likes).
Implementations§
Source§impl CompiledPolicy<'_>
impl CompiledPolicy<'_>
Sourcepub fn output_source(
&self,
action: &Action,
cwd: &str,
paths: &dyn PathResolver,
) -> Option<String>
pub fn output_source( &self, action: &Action, cwd: &str, paths: &dyn PathResolver, ) -> Option<String>
What the output of action, run in cwd, is, when it is content an
attacker may control (fetch https://docs.example/page): what session
taint calls untrusted (a fetch, a web search, an MCP result, an unknown
tool; a metadata tool too, which does not taint the session, since a
page sets the title and URL a tab list shows), and a shell command that
reads from a network host the policy does not allow or from a forge’s
command-line client (gh issue view). None for everything else: a
read of a file, a local command.
Sourcepub fn injected_tokens(
&self,
source: &Action,
cwd: &str,
output: &str,
) -> Vec<Token>
pub fn injected_tokens( &self, source: &Action, cwd: &str, output: &str, ) -> Vec<Token>
The tokens of output, the output of source (an action
Self::output_source names), worth keeping: hosts other than the
ones source itself reached and than loopback, absolute paths outside
the project, and commands of its code spans as the classifier reads
them. Hosts are kept in their canonical spelling
(host::canonical, ADR-063 §4), as a later call’s hosts are
compared. De-duplicated, at most MAX_TOKENS_PER_OUTPUT: URL hosts
first, then commands, paths, and words that look like hosts.
Sourcepub fn with_injected(
&self,
decision: Decision,
action: &Action,
paths: &dyn PathResolver,
seen: &dyn InjectedLookup,
) -> Decision
pub fn with_injected( &self, decision: Decision, action: &Action, paths: &dyn PathResolver, seen: &dyn InjectedLookup, ) -> Decision
decision for action, tightened by the tokens of untrusted content
seen knows: a shell command or a write needs review when a host it
reaches, a file it writes or a command it runs came from that content,
and the policy does not allow that atom. A command counts only when the
call also reaches a host or a file outside the project that the policy
does not allow. Never loosens; a deny stays.
Source§impl CompiledPolicy<'_>
impl CompiledPolicy<'_>
Sourcepub fn collection(
&self,
action: &Action,
cwd: &str,
paths: &dyn PathResolver,
is_dir: &dyn Fn(&str) -> bool,
) -> Staging
pub fn collection( &self, action: &Action, cwd: &str, paths: &dyn PathResolver, is_dir: &dyn Fn(&str) -> bool, ) -> Staging
What running action in cwd collected outside the project
(ADR-061): its reads outside it, as files or folders (is_dir tells
them apart; the core does no I/O), and, when it read any, the files a
packing or encoding command of it wrote. The caller passes only calls
that ran.
Sourcepub fn with_staging(
&self,
decision: Decision,
action: &Action,
paths: &dyn PathResolver,
staging: &Staging,
is_dir: &dyn Fn(&str) -> bool,
) -> Decision
pub fn with_staging( &self, decision: Decision, action: &Action, paths: &dyn PathResolver, staging: &Staging, is_dir: &dyn Fn(&str) -> bool, ) -> Decision
decision for action with the @staging-egress <host> atom of each
host a send of it goes to, once staging (with what this call itself
collects, when the session already collected any) reached a threshold of the policy’s staging: section and the
send carries a body, or the send names a staged file. Where a deny or
review rule names the atom, its decision is merged (strictest wins);
otherwise a reason records it and the verdict stays as it was.
Source§impl CompiledPolicy<'_>
impl CompiledPolicy<'_>
Sourcepub fn exposure(
&self,
action: &Action,
cwd: &str,
paths: &dyn PathResolver,
) -> Taint
pub fn exposure( &self, action: &Action, cwd: &str, paths: &dyn PathResolver, ) -> Taint
What running action in cwd exposed its session to: secret material
from a read the secrets-paths group names, untrusted content from a
fetch, a web search, an unknown tool or an MCP result, except a
metadata tool’s (taint.metadata_tools). The caller passes only calls that ran; the parts
of an action that cannot be classified expose nothing they can name.
Sourcepub fn untrusted_read(
&self,
action: &Action,
cwd: &str,
paths: &dyn PathResolver,
) -> Option<(UntrustedKind, String)>
pub fn untrusted_read( &self, action: &Action, cwd: &str, paths: &dyn PathResolver, ) -> Option<(UntrustedKind, String)>
The first untrusted content running action in cwd read, with what
kind it is: the same atoms CompiledPolicy::exposure counts, for
reports that say where the content came from (ADR-056).
Sourcepub fn with_taint(
&self,
decision: Decision,
action: &Action,
paths: &dyn PathResolver,
taint: &Taint,
) -> Decision
pub fn with_taint( &self, decision: Decision, action: &Action, paths: &dyn PathResolver, taint: &Taint, ) -> Decision
decision for action, tightened by taint: after secret material,
network to any host but the secret’s own, and every MCP call, web
search and unknown tool (the hosts they reach are unknown), needs review; after untrusted content, a write to
a protected path needs review. Merging keeps the strictest verdict, so this
never loosens a decision.
Source§impl<'p> CompiledPolicy<'p>
impl<'p> CompiledPolicy<'p>
Sourcepub fn compile(
policy: &'p Policy,
ctx: &EvalContext,
) -> Result<Self, PolicyError>
pub fn compile( policy: &'p Policy, ctx: &EvalContext, ) -> Result<Self, PolicyError>
Compile every pattern of policy for ctx. Fails on a pattern that does
not compile, and on a moved_dirs entry whose default could alias every
pattern (empty, bare /, or not an absolute or ~/-rooted directory).
Sourcepub fn compile_owned(
policy: Policy,
ctx: &EvalContext,
) -> Result<CompiledPolicy<'static>, PolicyError>
pub fn compile_owned( policy: Policy, ctx: &EvalContext, ) -> Result<CompiledPolicy<'static>, PolicyError>
Self::compile for a policy the result keeps, so it borrows nothing.
Sourcepub fn context(&self) -> &EvalContext
pub fn context(&self) -> &EvalContext
The context this was compiled for.
Sourcepub fn evaluate_atomic(&self, action: &AtomicAction) -> Option<Decision>
pub fn evaluate_atomic(&self, action: &AtomicAction) -> Option<Decision>
Evaluate one atomic action: deny → allow → review → defer → default, with a
repository policy’s review rules (Policy::repo_review) tried before allow.
A repository review never softens what the user’s policy alone decides
for the atom: per atom the result is the stricter of the two (ADR-022),
so a repository’s review: [{net: ['*']}] leaves a host the net: deny
default refuses denied.
Returns None for a whole-pipeline atom that no rule mentions: pipelines
are only there so rules like curl * | sh can see across |; the
per-sub-command atoms carry the default verdict.
Source§impl CompiledPolicy<'_>
impl CompiledPolicy<'_>
Sourcepub fn decide(&self, action: &Action) -> Decision
pub fn decide(&self, action: &Action) -> Decision
Decide one host action without executable resolution.
Unparseable input yields the policy’s catch-all verdict (review or
defer) with the parser’s reason, never allow.
Sourcepub fn atoms(
&self,
action: &Action,
paths: &dyn PathResolver,
) -> (Vec<AtomicAction>, Option<String>)
pub fn atoms( &self, action: &Action, paths: &dyn PathResolver, ) -> (Vec<AtomicAction>, Option<String>)
The atomic actions Self::decide_with evaluates for action, with an
extra atom for every path an unquoted glob operand names in the
directories paths lists, and for every read or write paths resolves
through a symlink; and the reason when part of the action cannot be
classified or a glob not expanded in full (review).
Sourcepub fn pushes(&self, action: &Action) -> Vec<Push>
pub fn pushes(&self, action: &Action) -> Vec<Push>
The commands of action that publish local commits (git push, gh pr create), each with the directories it may run in. Only a shell command
has any.
Sourcepub fn executed(&self, action: &Action, paths: &dyn PathResolver) -> Vec<String>
pub fn executed(&self, action: &Action, paths: &dyn PathResolver) -> Vec<String>
The files action runs as code (ADR-039): a script an interpreter or a
shell runs (python3 x.py, bash x.sh, source x), a file it loads
first (node -r ./x.js) and a program named by a path (./x), through
every wrapper the classifier unwraps (env, time, bash -c '…'), as
canonical paths, each also as paths resolves it through a symlink.
Only a shell command runs any; a test runner, build tool or package
script (pytest, npm test, go run .) names none.
Sourcepub fn decide_with(
&self,
action: &Action,
resolver: &dyn ProgramResolver,
paths: &dyn PathResolver,
) -> Decision
pub fn decide_with( &self, action: &Action, resolver: &dyn ProgramResolver, paths: &dyn PathResolver, ) -> Decision
Decide one host action, resolving shell programs through resolver so
that executables pins and installation pins are enforced, and paths
through paths so a symlink cannot move a read or write past a rule.