use super::capability::CapabilitySet;
use super::syscall::SyscallAllowlist;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NetworkPolicy {
pub allowlist: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ToolRule {
pub name: String,
pub allow: bool,
pub requires_approval_if: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PolicyDocument {
pub name: Option<String>,
pub network: Option<NetworkPolicy>,
pub capabilities: Option<CapabilitySet>,
pub tools: Vec<ToolRule>,
pub syscall_allowlist: Option<SyscallAllowlist>,
}
impl PolicyDocument {
pub fn denied_capabilities(&self) -> Vec<&super::capability::Capability> {
self.capabilities
.as_ref()
.map(|c| c.deny.iter().collect())
.unwrap_or_default()
}
pub fn egress_allowlist(&self) -> &[String] {
self.network.as_ref().map(|n| n.allowlist.as_slice()).unwrap_or(&[])
}
pub fn allowed_syscalls(&self) -> Vec<super::syscall::Syscall> {
self.syscall_allowlist
.as_ref()
.map(|a| a.iter().collect())
.unwrap_or_default()
}
}
#[cfg(test)]
mod tests {
use super::super::capability::Capability;
use super::*;
#[test]
fn default_document_is_empty() {
let doc = PolicyDocument::default();
assert!(doc.name.is_none());
assert!(doc.network.is_none());
assert!(doc.capabilities.is_none());
assert!(doc.tools.is_empty());
assert!(doc.denied_capabilities().is_empty());
assert!(doc.egress_allowlist().is_empty());
assert!(doc.syscall_allowlist.is_none());
assert!(doc.allowed_syscalls().is_empty());
}
#[test]
fn accessors_read_through() {
use super::super::syscall::{Syscall, SyscallAllowlist};
let mut caps = CapabilitySet::default();
caps.deny.insert(Capability::FileWrite);
let doc = PolicyDocument {
name: Some("strict".to_string()),
network: Some(NetworkPolicy {
allowlist: vec!["api.openai.com".to_string()],
}),
capabilities: Some(caps),
tools: vec![ToolRule {
name: "write_file".to_string(),
allow: false,
requires_approval_if: None,
}],
syscall_allowlist: Some(SyscallAllowlist::from_names(["read", "write"]).unwrap()),
};
assert_eq!(doc.denied_capabilities(), vec![&Capability::FileWrite]);
assert_eq!(doc.egress_allowlist(), ["api.openai.com"]);
assert_eq!(doc.tools.len(), 1);
assert_eq!(doc.allowed_syscalls(), vec![Syscall::Read, Syscall::Write]);
}
}