Skip to main content

Crate ferrin_policy

Crate ferrin_policy 

Source
Expand description

Policy-based tool approval for Ferrin.

A PolicyClient evaluates a policy path with a JSON input and returns the raw decision document. policy_approval turns a client into an ApprovalPolicy: the tool name, its input, the messages and the runtime context become the policy input, and the normalized PolicyDecision becomes the approval status. capability_middleware filters the tools offered to the model through the same client. shadow observes decisions without enforcing them and with_default gives every call a decision.

Clients: HttpPolicyClient speaks the OPA REST Data API (POST /v1/data/<path>); RegoPolicyClient (feature rego) evaluates Rego policies in-process with regorus. policy_client adapts a closure, for tests and static rules.

Design: docs/01-architecture/18-policy-approval.md, ADR 0020.

§Attribution

The decision document format, its normalization rules and the shadow and capability patterns are derived from the Vercel AI SDK (Apache-2.0, Copyright 2023 Vercel, Inc.) and reimplemented in Rust. See the NOTICE file in the crate root.

§Examples

use ferrin_core::generate_text::ApprovalStatus;
use ferrin_policy::PolicyDecision;
use ferrin_policy::policy_approval;
use ferrin_policy::policy_client;
use serde_json::json;

// A decision document as returned by a policy server or a Rego rule.
let decision = PolicyDecision::normalize(&json!({
    "decision": "requires-approval",
    "reason": "writes outside the workspace"
}));
assert_eq!(
    decision.into_approval(),
    Some(ApprovalStatus::user_approval().with_reason("writes outside the workspace"))
);

// A static in-process client; pass the policy to
// `generate_text(..).tool_approval(policy)`.
let client = policy_client(|_path, input| {
    Ok(json!({ "decision": if input["tool"]["name"] == "delete_file" { "deny" } else { "allow" } }))
});
let _policy = policy_approval(client, "ferrin/tools/decision");

Structs§

CapabilityMiddleware
Middleware created by capability_middleware.
HttpPolicyClient
Evaluates policies through a policy server implementing the OPA REST Data API: POST <base>/v1/data/<path> with {"input": ..}, answering {"result": ..}.
HttpPolicyClientBuilder
Builder of an HttpPolicyClient.
PolicyApproval
Approval policy created by policy_approval.
PolicyClientFn
Adapter turning a synchronous closure into a PolicyClient.
PolicyDecisionEvent
The observed and effective approval decisions for one tool call.
PolicyDecisionToolCall
Identifying information for the tool call a policy evaluated.
RegoPolicyClient
Evaluates Rego policies in-process.
RegoPolicyClientBuilder
Builder of a RegoPolicyClient.
Shadow
Approval policy created by shadow.
WithDefault
Approval policy created by with_default.

Enums§

Enforcement
Whether a Shadow policy acts on the decisions it observes.
FailureMode
What an approval policy or capability middleware does when the policy cannot be evaluated (transport failure, engine error, invalid response).
PolicyDecision
A normalized policy decision.
PolicyError
Why a policy could not be evaluated.

Constants§

DEFAULT_MAX_RESPONSE_BYTES
Default limit on the size of a decision response body.
UNRECOGNIZED_DECISION
Reason attached to denials of documents that are not recognized.

Traits§

PolicyClient
Evaluates policies: a path and a JSON input in, a raw decision document out.

Functions§

capability_middleware
Restricts CallOptions::tools to the allowlist returned by the policy at path.
default_capability_input
The default capability input:
default_input
The default policy input matches the reference SDK’s OPA rule input.
parse_allowlist
Parses the allowlist of a capability decision: an array of tool names or an object with a tools array. Returns None for anything else.
policy_approval
Resolves tool approvals by evaluating the policy at path with client.
policy_client
Wraps a synchronous closure (path, input) -> decision as a policy client, for tests and static rules.
shadow
Evaluates policy for every call and reports its decision through Shadow::on_decision, but only acts on it under Enforcement::Enforce. Roll a policy out by observing first and flipping the enforcement later without changing the wiring.
with_default
Gives calls with None or NotApplicable from the inner policy the status default, so that every call has a decision.

Type Aliases§

CapabilityInputFn
Builds the policy input for a model call.
OnDecisionFn
Asynchronous observer receiving each evaluated and effective decision.
OnDecisionSyncFn
Synchronous low-level observer of the original policy return value.
SharedPolicyClient
Shared reference to a policy client.
ToInputFn
Builds the policy input for a tool call.