context_harness/agent_runtime/
policy.rs1use crate::agent_resource::{Capability, Permissions};
4use async_trait::async_trait;
5use serde_json::Value;
6
7#[derive(Debug, Clone)]
8pub struct RuntimePolicy {
9 pub allow: Vec<Capability>,
10 pub require_approval: Vec<Capability>,
11}
12impl Default for RuntimePolicy {
13 fn default() -> Self {
14 Self {
15 allow: vec![Capability::ReadOnly, Capability::AgentDelegate],
16 require_approval: vec![
17 Capability::WorkspaceWrite,
18 Capability::ProcessExecute,
19 Capability::ExternalSideEffect,
20 ],
21 }
22 }
23}
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub enum Authorization {
26 Denied,
27 Allowed,
28 Approval(Vec<Capability>),
29}
30impl RuntimePolicy {
31 pub fn authorize(&self, agent: &Permissions, capabilities: &[Capability]) -> Authorization {
32 if capabilities.is_empty() {
33 return Authorization::Denied;
34 }
35 let allowed = agent.allowed();
36 let mut approval = Vec::new();
37 for capability in capabilities {
38 if (!self.allow.contains(capability) && !self.require_approval.contains(capability))
39 || (!allowed.contains(capability) && !agent.require_approval.contains(capability))
40 {
41 return Authorization::Denied;
42 }
43 if (self.require_approval.contains(capability)
44 || agent.require_approval.contains(capability))
45 && !approval.contains(capability)
46 {
47 approval.push(*capability);
48 }
49 }
50 if approval.is_empty() {
51 Authorization::Allowed
52 } else {
53 Authorization::Approval(approval)
54 }
55 }
56}
57
58pub struct ApprovalRequest {
61 pub run_id: String,
62 pub call_id: String,
63 pub tool: String,
64 pub capabilities: Vec<Capability>,
65 pub arguments: Value,
66}
67#[async_trait]
68pub trait ApprovalHandler: Send + Sync {
69 async fn approve(&self, request: &ApprovalRequest) -> bool;
70}
71pub struct DenyApprovals;
72#[async_trait]
73impl ApprovalHandler for DenyApprovals {
74 async fn approve(&self, _: &ApprovalRequest) -> bool {
75 false
76 }
77}