Skip to main content

SecurityPolicy

Struct SecurityPolicy 

pub struct SecurityPolicy {
Show 26 fields pub autonomy: AutonomyLevel, pub risk_profile_name: String, pub delegation_policy: DelegationPolicy, pub workspace_dir: PathBuf, pub config_path: Option<PathBuf>, pub data_dir: Option<PathBuf>, pub workspace_only: bool, pub allowed_commands: Vec<String>, pub forbidden_paths: Vec<String>, pub allowed_roots: Vec<PathBuf>, pub allowed_roots_read_only: Vec<PathBuf>, pub allowed_roots_write_only: Vec<PathBuf>, pub max_actions_per_hour: u32, pub max_cost_per_day_cents: u32, pub require_approval_for_medium_risk: bool, pub block_high_risk_commands: bool, pub shell_env_passthrough: Vec<String>, pub shell_timeout_secs: u64, pub allowed_tools: Option<Vec<String>>, pub excluded_tools: Option<Vec<String>>, pub auto_approve: Vec<String>, pub always_ask: Vec<String>, pub sandbox_enabled: Option<bool>, pub sandbox_backend: Option<String>, pub firejail_args: Vec<String>, pub tracker: PerSenderTracker,
}

Fields§

§autonomy: AutonomyLevel§risk_profile_name: String

Name of the risk profile this policy was built from. Used to gate delegation: a Delegate may only target an agent sharing the caller’s risk profile. Empty when constructed outside the profile path.

§delegation_policy: DelegationPolicy

Whether and to which agents this profile may delegate.

§workspace_dir: PathBuf§config_path: Option<PathBuf>§data_dir: Option<PathBuf>§workspace_only: bool§allowed_commands: Vec<String>§forbidden_paths: Vec<String>§allowed_roots: Vec<PathBuf>

Directories the agent can read AND write under. Includes RiskProfileConfig.allowed_roots plus any cross-agent AccessMode::ReadWrite grants resolved from agent.workspace.access at policy construction time.

§allowed_roots_read_only: Vec<PathBuf>

Directories the agent can read but NOT write under. Populated from cross-agent AccessMode::Read grants at policy construction time. Empty when no read-only cross-agent access is configured.

§allowed_roots_write_only: Vec<PathBuf>

Directories the agent can write but NOT read under. Populated from cross-agent AccessMode::Write grants; read-side tools ignore this list.

§max_actions_per_hour: u32§max_cost_per_day_cents: u32§require_approval_for_medium_risk: bool§block_high_risk_commands: bool§shell_env_passthrough: Vec<String>§shell_timeout_secs: u64§allowed_tools: Option<Vec<String>>

Tool name allowlist. None is unrestricted (default for agents without an explicit risk_profile.allowed_tools setting). Some(vec![]) denies every tool. Some(list) admits only the listed names. Enforced at the agent loop’s tool-dispatch site.

§excluded_tools: Option<Vec<String>>

Tool name denylist. Subtracts from the allowed set (whether the allowed set comes from allowed_tools or from the unrestricted default). None and Some(vec![]) both mean “exclude nothing”.

§auto_approve: Vec<String>

Tools that never require approval in this profile. Mirrors RiskProfileConfig.auto_approve.

§always_ask: Vec<String>

Tools that always require approval in this profile. Mirrors RiskProfileConfig.always_ask.

§sandbox_enabled: Option<bool>

Whether the sandbox is enabled for this profile. None inherits the global default at the call site.

§sandbox_backend: Option<String>

Sandbox backend identifier (e.g. "firejail", "landlock"). None inherits the global default.

§firejail_args: Vec<String>

Extra arguments forwarded to firejail when sandbox_backend resolves to "firejail".

§tracker: PerSenderTracker

Implementations§

Source§

impl SecurityPolicy

Source

pub fn is_tool_allowed(&self, name: &str) -> bool

True when name is admissible under the current policy. allowed_tools = None is unrestricted; Some(list) is the allowlist. excluded_tools always subtracts.

Source

pub fn is_tool_excluded(&self, name: &str) -> bool

Source§

impl SecurityPolicy

Source

pub fn command_risk_level(&self, command: &str) -> CommandRiskLevel

Classify command risk. Any high-risk segment marks the whole command high.

Source

pub fn command_risk_level_for_shell( &self, command: &str, dialect: ShellDialect, ) -> CommandRiskLevel

Classify command risk using the language the runtime will execute.

Source

pub fn validate_command_execution( &self, command: &str, approved: bool, ) -> Result<CommandRiskLevel, String>

Validate full command execution policy (allowlist + risk gate).

Uses the conservative POSIX shell dialect. Shell tools that know the runtime’s effective shell should call validate_command_execution_for_shell so the Windows nul null device is only accepted under cmd.exe.

Source

pub fn validate_command_execution_for_shell( &self, command: &str, approved: bool, dialect: ShellDialect, ) -> Result<CommandRiskLevel, String>

Validate a command against the policy and the runtime’s shell language.

The dialect decides platform-specific redirect safety (e.g. the Windows nul null device is discard-only under cmd.exe but an ordinary file under a POSIX shell).

Source

pub fn is_command_allowed(&self, command: &str) -> bool

Source

pub fn is_command_allowed_for_shell( &self, command: &str, dialect: ShellDialect, ) -> bool

Check the command allowlist using the runtime’s actual shell language.

Allowlist + shell-safety check against a specific shell dialect. The dialect selects the command grammar (PowerShell vs POSIX-like) and gates platform-specific redirect safety (the Windows nul null device is only discard-safe under cmd.exe).

Source

pub fn forbidden_path_argument_for_shell( &self, command: &str, dialect: ShellDialect, ) -> Option<String>

Scan command for forbidden path arguments against a specific shell dialect. The dialect gates which redirect targets count as safe devices (the Windows nul null device is only a safe device under cmd.exe) and which relative forms are recognized as paths — Windows-relative paths are understood for both cmd.exe and PowerShell, including cross-platform PowerShell runtimes.

Source

pub fn forbidden_workspace_path_argument_for_shell( &self, command: &str, dialect: ShellDialect, ) -> Option<String>

Like SecurityPolicy::forbidden_workspace_path_argument, but against a specific shell dialect: it uses the effective shell’s path syntax and classifies platform-specific safe redirect devices by the shell that will execute the command, resolving relative candidates through symlinks before the workspace-boundary check.

Source

pub fn forbidden_path_argument(&self, command: &str) -> Option<String>

Return the first path-like executable or argument blocked by path policy using the host platform’s default shell syntax.

String-level command path guard: flags a path argument that is absolute and outside the workspace, uses .. traversal, a ~user form, or a forbidden prefix. Best-effort token parsing, intended as a safety gate before command execution. Does NOT resolve symlinks, so it is safe for callers whose working directory is NOT the workspace (e.g. cron jobs run in data_dir). Shell/skill tools, which run IN the workspace, should use SecurityPolicy::forbidden_workspace_path_argument, which additionally follows in-workspace symlinks to block escapes.

Source

pub fn forbidden_workspace_path_argument(&self, command: &str) -> Option<String>

Like SecurityPolicy::forbidden_path_argument but for a command that runs IN the workspace: each workspace-relative path argument is also resolved (following symlinks, including dangling ones) and re-checked against the workspace boundary with the host platform’s default shell syntax, catching an in-workspace symlink that points outside for the argument forms this static scan can see.

This is best-effort, defense-in-depth hardening over a token-scanned command line - NOT a complete workspace boundary, and NOT equivalent to the file tools, which resolve an operation-aware target at the call site. It flags a path-shaped argument (one with a separator, e.g. link/x, a redirect target, or an absolute / .. form) that escapes via an in-workspace symlink. It does NOT, and cannot from a static parse, cover: a bare argument with no separator (cat somelink) that is a symlink; a path computed at run time via variable expansion or command substitution ($VAR, $(...)), eval, or a write done inside an executed script (sh ./x.sh, where only the script path is scanned); a quoted path holding whitespace ("link dir/out"), which the whitespace tokenizer fragments; read-vs-write direction (an argument may be read or written, so a resolved target allowed for EITHER passes, unlike the operation-aware file tools); or non-Unix relative forms (a link\file path on Windows). A shell command is Turing-complete; complete containment is the execution boundary (the OS sandbox and the broader granular sandbox-policy work), not this preflight.

Source

pub fn is_path_allowed(&self, path: &str) -> bool

Check if a file path is allowed (no path traversal, within workspace)

Source

pub fn is_resolved_path_readable(&self, resolved: &Path) -> bool

Source

pub fn approved_read_root(&self, resolved: &Path) -> Option<PathBuf>

Return the canonical allowlisted root directory that authorizes reading resolved: the workspace first, then read-write roots, then read-only roots. Callers bind a directory-handle-scoped open (cap-std beneath/ no-follow) to this boundary instead of re-walking a pathname that could be swapped between the readability check and the open. Returns None when no bounded allowlist root contains the path (e.g. a fully permissive, non-workspace_only policy, or a device path) — there is then no confinement boundary to bind to. Assumes resolved is already canonical and has passed Self::is_resolved_path_readable.

Source

pub fn is_resolved_path_allowed(&self, resolved: &Path) -> bool

Source

pub fn is_runtime_config_path(&self, resolved: &Path) -> bool

Source

pub fn runtime_config_violation_message(&self, resolved: &Path) -> String

Source

pub fn resolved_path_violation_message(&self, resolved: &Path) -> String

Source

pub fn can_act(&self) -> bool

Check if autonomy level permits any action at all

Source

pub fn authorize_tool_operation( &self, operation: ToolOperation, operation_name: &str, ) -> Result<(), String>

Check whether autonomy permits a tool operation without recording it.

Source

pub fn enforce_tool_operation( &self, operation: ToolOperation, operation_name: &str, ) -> Result<(), String>

Enforce policy and record an action for callers without a rate-limit wrapper.

Source

pub fn reserve_action(&self) -> Option<ActionReservation>

Atomically reserve one action slot for a production-wrapped invocation.

Source

pub fn record_action(&self) -> bool

Record an action for the current sender and check if rate-limited. Returns true if allowed, false if budget exhausted.

Source

pub fn is_rate_limited(&self) -> bool

Check if the current sender would be rate-limited without recording.

Source

pub fn resolve_tool_path(&self, path: &str) -> PathBuf

Source

pub fn is_under_allowed_root(&self, path: &str) -> bool

Source

pub fn is_under_read_only_allowed_root(&self, path: &str) -> bool

Source

pub fn is_under_any_allowed_root(&self, path: &str) -> bool

Union of all three root tiers; directionality is enforced later by the resolved-path checks.

Source

pub fn ensure_no_escalation_beyond( &self, parent: &SecurityPolicy, ) -> Result<(), EscalationViolation>

Source

pub fn from_risk_profile( risk_profile: &RiskProfileConfig, workspace_dir: &Path, ) -> SecurityPolicy

Source

pub fn from_profiles( risk_profile: &RiskProfileConfig, runtime_profile: Option<&RuntimeProfileConfig>, workspace_dir: &Path, ) -> SecurityPolicy

Source

pub fn for_agent( config: &Config, agent_alias: &str, ) -> Result<SecurityPolicy, Error>

Source

pub fn prompt_summary(&self) -> String

Trait Implementations§

Source§

impl Clone for SecurityPolicy

Source§

fn clone(&self) -> SecurityPolicy

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · §

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SecurityPolicy

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for SecurityPolicy

Source§

fn default() -> SecurityPolicy

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more