Skip to main content

PolicyEngine

Struct PolicyEngine 

Source
pub struct PolicyEngine { /* private fields */ }
Expand description

The core policy evaluation engine.

Evaluates Actions against a set of Policy rules to produce a Verdict.

§Security Model

  • Fail-closed: An empty policy set produces Verdict::Deny.
  • Priority ordering: Higher-priority policies are evaluated first.
  • Pattern matching: Policy IDs use "tool:function" convention with wildcard support.

Implementations§

Source§

impl PolicyEngine

Source

pub fn compile_policies( policies: &[Policy], strict_mode: bool, ) -> Result<Vec<CompiledPolicy>, Vec<PolicyValidationError>>

Compile a set of policies, validating all patterns at load time.

Returns pre-sorted Vec<CompiledPolicy> on success, or a list of all validation errors found across all policies on failure.

Source§

impl PolicyEngine

Source

pub fn evaluate_action_traced( &self, action: &Action, ) -> Result<(Verdict, EvaluationTrace), EngineError>

Evaluate an action with full decision trace.

Opt-in alternative to Self::evaluate_action that records per-policy match details for OPA-style decision explanations. Has ~20% allocation overhead compared to the non-traced hot path, so use only when ?trace=true.

Source§

impl PolicyEngine

Source

pub fn new(strict_mode: bool) -> Self

Create a new policy engine.

When strict_mode is true, the engine applies stricter validation on conditions and parameters.

Source

pub fn strict_mode(&self) -> bool

Returns the engine’s strict_mode setting.

Source

pub fn validate_domain_pattern(pattern: &str) -> Result<(), String>

Validate a domain pattern used in network_rules.

Rules per RFC 1035:

  • Labels (parts between dots) must be 1-63 characters each
  • Each label must be alphanumeric + hyphen only (no leading/trailing hyphen)
  • Total domain length max 253 characters
  • Wildcard *. prefix is allowed (only at the beginning)
  • Empty string is rejected

See the internal domain::validate_domain_pattern function for details.

Source

pub fn with_policies( strict_mode: bool, policies: &[Policy], ) -> Result<Self, Vec<PolicyValidationError>>

Create a new policy engine with pre-compiled policies.

All regex and glob patterns are compiled at construction time. Invalid patterns cause immediate rejection with descriptive errors. The compiled policies are sorted by priority (highest first, deny-overrides).

Source

pub fn set_max_path_decode_iterations(&mut self, max: u32)

Set the maximum percent-decoding iterations for path normalization.

Paths requiring more iterations fail-closed to "/". The default is DEFAULT_MAX_PATH_DECODE_ITERATIONS (20). A value of 0 disables iterative decoding entirely (single pass only).

Source

pub fn sort_policies(policies: &mut [Policy])

Sort policies by priority (highest first), with deny-overrides at equal priority, and a stable tertiary tiebreaker by policy ID for deterministic ordering.

Call this once when loading or modifying policies, then pass the sorted slice to Self::evaluate_action to avoid re-sorting on every evaluation.

Source

pub fn evaluate_action( &self, action: &Action, policies: &[Policy], ) -> Result<Verdict, EngineError>

Evaluate an action against a set of policies.

For best performance, pass policies that have been pre-sorted with Self::sort_policies. If not pre-sorted, this method will sort a temporary copy (which adds O(n log n) overhead per call).

The first matching policy determines the verdict. If no policy matches, the default is Deny (fail-closed).

Source

pub fn evaluate_action_with_context( &self, action: &Action, policies: &[Policy], context: Option<&EvaluationContext>, ) -> Result<Verdict, EngineError>

👎Deprecated since 4.0.1:

policies parameter is silently ignored when compiled policies exist. Use evaluate_action() for compiled engines or build a new engine with with_policies() for dynamic policy sets.

Evaluate an action with optional session context.

This is the context-aware counterpart to Self::evaluate_action. When context is Some, context conditions (time windows, call limits, agent identity, action history) are evaluated. When None, behaves identically to evaluate_action.

§WARNING: policies parameter ignored when compiled policies exist

When the engine was constructed with Self::with_policies (or any builder that populates compiled_policies), the policies parameter is completely ignored. The engine uses its pre-compiled policy set instead.

Source

pub fn evaluate_with_context( &self, action: &Action, context: Option<&EvaluationContext>, ) -> Result<Verdict, EngineError>

Evaluate an action with optional session context, returning only the verdict.

This is the context-aware counterpart to Self::evaluate_action. When context is Some, context conditions (time windows, call limits, agent identity, action history) are evaluated. When None, behaves identically to evaluate_action.

For the full decision trace, use Self::evaluate_action_traced_with_context.

Source

pub fn evaluate_action_traced_with_context( &self, action: &Action, context: Option<&EvaluationContext>, ) -> Result<(Verdict, EvaluationTrace), EngineError>

Evaluate an action with full decision trace and optional session context.

Source

pub fn normalize_path(raw: &str) -> Result<String, EngineError>

Normalize a file path: resolve .., ., reject null bytes, ensure deterministic form.

Handles percent-encoding, null bytes, and path traversal attempts.

Source

pub fn normalize_path_bounded( raw: &str, max_iterations: u32, ) -> Result<String, EngineError>

Normalize a file path with a configurable percent-decoding iteration limit.

Use this variant when you need to control the maximum decode iterations to prevent DoS from deeply nested percent-encoding.

Source

pub fn extract_domain(url: &str) -> String

Extract the domain from a URL string.

Returns the host portion of the URL, or the original string if parsing fails.

Source

pub fn match_domain_pattern(domain_str: &str, pattern: &str) -> bool

Match a domain against a pattern like *.example.com or example.com.

Supports wildcard patterns with *. prefix for subdomain matching.

Source

pub fn get_param_by_path<'a>(params: &'a Value, path: &str) -> Option<&'a Value>

Retrieve a parameter value by dot-separated path.

Supports both simple keys ("path") and nested paths ("config.output.path").

Resolution order (Exploit #5 fix): When the path contains dots, the function checks both an exact key match (e.g., params["config.path"]) and dot-split traversal (e.g., params["config"]["path"]).

Ambiguity handling (fail-closed): If both interpretations resolve to different values, the function returns None. This prevents an attacker from shadowing a nested value with a literal dotted key (or vice versa). The None triggers deny behavior through the constraint’s on_missing handling.

When only one interpretation resolves, that value is returned. When both resolve to the same value, that value is returned.

IMPROVEMENT_PLAN 4.1: Also supports bracket notation for array access:

  • items[0] — access first element of array “items”
  • config.items[0].path — traverse nested path with array access
  • matrix[0][1] — multi-dimensional array access
Source

pub fn has_ip_rules(&self) -> bool

Returns true if any compiled policy has IP rules configured.

Used by proxy layers to skip DNS resolution when no policies require it.

Trait Implementations§

Source§

impl Debug for PolicyEngine

Source§

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

Formats the value using the given formatter. 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
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
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

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

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

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> Same for T

Source§

type Output = T

Should always be Self
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.
Source§

impl<T> WithSubscriber for T

Source§

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
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

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