mod computer_use;
mod custom;
mod egress_allowlist;
mod forbidden_path;
mod input_injection_capability;
mod jailbreak;
mod mcp_tool;
mod patch_integrity;
mod path_allowlist;
mod path_normalization;
mod prompt_injection;
mod remote_desktop_side_channel;
mod secret_leak;
mod shell_command;
pub use computer_use::{ComputerUseConfig, ComputerUseGuard, ComputerUseMode};
pub use custom::{CustomGuardFactory, CustomGuardRegistry};
pub use egress_allowlist::{EgressAllowlistConfig, EgressAllowlistGuard};
pub use forbidden_path::{ForbiddenPathConfig, ForbiddenPathGuard};
pub use input_injection_capability::{
InputInjectionCapabilityConfig, InputInjectionCapabilityGuard,
};
pub use jailbreak::{JailbreakConfig, JailbreakGuard};
pub use mcp_tool::{McpDefaultAction, McpToolConfig, McpToolGuard};
pub use patch_integrity::{PatchIntegrityConfig, PatchIntegrityGuard};
pub use path_allowlist::{PathAllowlistConfig, PathAllowlistGuard};
pub use path_normalization::normalize_path_for_policy;
pub use prompt_injection::{PromptInjectionConfig, PromptInjectionGuard};
pub use remote_desktop_side_channel::{
RemoteDesktopSideChannelConfig, RemoteDesktopSideChannelGuard,
};
pub use secret_leak::{SecretLeakConfig, SecretLeakGuard, SecretPattern};
pub use shell_command::{ShellCommandConfig, ShellCommandGuard};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use crate::identity::{IdentityPrincipal, OrganizationContext, RequestContext, SessionContext};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Severity {
#[serde(alias = "low")]
Info,
#[serde(alias = "medium")]
Warning,
#[serde(alias = "high")]
Error,
Critical,
}
#[must_use]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GuardResult {
pub allowed: bool,
pub guard: String,
pub severity: Severity,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub details: Option<serde_json::Value>,
}
impl GuardResult {
pub fn allow(guard: impl Into<String>) -> Self {
Self {
allowed: true,
guard: guard.into(),
severity: Severity::Info,
message: "Allowed".to_string(),
details: None,
}
}
pub fn block(guard: impl Into<String>, severity: Severity, message: impl Into<String>) -> Self {
Self {
allowed: false,
guard: guard.into(),
severity,
message: message.into(),
details: None,
}
}
pub fn warn(guard: impl Into<String>, message: impl Into<String>) -> Self {
Self {
allowed: true,
guard: guard.into(),
severity: Severity::Warning,
message: message.into(),
details: None,
}
}
pub fn sanitize(
guard: impl Into<String>,
message: impl Into<String>,
original: impl Into<String>,
sanitized: impl Into<String>,
) -> Self {
Self {
allowed: true,
guard: guard.into(),
severity: Severity::Warning,
message: message.into(),
details: Some(serde_json::json!({
"action": "sanitized",
"original": original.into(),
"sanitized": sanitized.into(),
})),
}
}
pub fn is_sanitized(&self) -> bool {
if !self.allowed {
return false;
}
self.details
.as_ref()
.and_then(|value| value.get("action"))
.and_then(|value| value.as_str())
.is_some_and(|action| action == "sanitized")
}
pub fn with_details(mut self, details: serde_json::Value) -> Self {
self.details = Some(details);
self
}
}
#[derive(Clone, Debug, Default)]
pub struct GuardContext {
pub cwd: Option<String>,
pub session_id: Option<String>,
pub agent_id: Option<String>,
pub metadata: Option<serde_json::Value>,
pub identity: Option<IdentityPrincipal>,
pub organization: Option<OrganizationContext>,
pub request: Option<RequestContext>,
pub roles: Option<Vec<String>>,
pub permissions: Option<Vec<String>>,
pub session: Option<SessionContext>,
}
impl GuardContext {
pub fn new() -> Self {
Self::default()
}
pub fn with_cwd(mut self, cwd: impl Into<String>) -> Self {
self.cwd = Some(cwd.into());
self
}
pub fn with_session_id(mut self, id: impl Into<String>) -> Self {
self.session_id = Some(id.into());
self
}
pub fn with_agent_id(mut self, id: impl Into<String>) -> Self {
self.agent_id = Some(id.into());
self
}
pub fn with_identity(mut self, identity: IdentityPrincipal) -> Self {
self.identity = Some(identity);
self
}
pub fn with_organization(mut self, organization: OrganizationContext) -> Self {
self.organization = Some(organization);
self
}
pub fn with_request(mut self, request: RequestContext) -> Self {
self.request = Some(request);
self
}
pub fn with_roles(mut self, roles: Vec<String>) -> Self {
self.roles = Some(roles);
self
}
pub fn with_permissions(mut self, permissions: Vec<String>) -> Self {
self.permissions = Some(permissions);
self
}
pub fn with_session(mut self, session: SessionContext) -> Self {
self.session = Some(session);
self
}
}
#[derive(Clone, Debug)]
pub enum GuardAction<'a> {
FileAccess(&'a str),
FileWrite(&'a str, &'a [u8]),
NetworkEgress(&'a str, u16),
ShellCommand(&'a str),
McpTool(&'a str, &'a serde_json::Value),
Patch(&'a str, &'a str),
Custom(&'a str, &'a serde_json::Value),
}
#[async_trait]
pub trait Guard: Send + Sync {
fn name(&self) -> &str;
fn handles(&self, action: &GuardAction<'_>) -> bool;
async fn check(&self, action: &GuardAction<'_>, context: &GuardContext) -> GuardResult;
}