//! Capability manager use dashmap::DashMap; use zclaw_types::{AgentId, Capability, CapabilitySet, Result, ZclawError}; /// Manages capabilities for all agents pub struct CapabilityManager { capabilities: DashMap, } impl CapabilityManager { pub fn new() -> Self { Self { capabilities: DashMap::new(), } } /// Grant capabilities to an agent pub fn grant(&self, agent_id: AgentId, capabilities: Vec) { let set = CapabilitySet { capabilities, }; self.capabilities.insert(agent_id, set); } /// Revoke all capabilities from an agent pub fn revoke(&self, agent_id: &AgentId) { self.capabilities.remove(agent_id); } /// Check if an agent can invoke a tool pub fn can_invoke_tool(&self, agent_id: &AgentId, tool_name: &str) -> bool { self.capabilities .get(agent_id) .map(|set| set.can_invoke_tool(tool_name)) .unwrap_or(false) } /// Check if an agent can read memory pub fn can_read_memory(&self, agent_id: &AgentId, scope: &str) -> bool { self.capabilities .get(agent_id) .map(|set| set.can_read_memory(scope)) .unwrap_or(false) } /// Check if an agent can write memory pub fn can_write_memory(&self, agent_id: &AgentId, scope: &str) -> bool { self.capabilities .get(agent_id) .map(|set| set.can_write_memory(scope)) .unwrap_or(false) } /// Validate capabilities for dangerous combinations /// /// Checks that overly broad capabilities are not combined with /// dangerous operations. Returns an error if an unsafe combination /// is detected. pub fn validate(&self, capabilities: &[Capability]) -> Result<()> { let has_tool_all = capabilities.iter().any(|c| matches!(c, Capability::ToolAll)); let has_agent_kill = capabilities.iter().any(|c| matches!(c, Capability::AgentKill { .. })); let has_shell_wildcard = capabilities.iter().any(|c| { matches!(c, Capability::ShellExec { pattern } if pattern == "*") }); // ToolAll + destructive operations is dangerous if has_tool_all && has_agent_kill { return Err(ZclawError::SecurityError( "ToolAll 与 AgentKill 不能同时授予".to_string(), )); } if has_tool_all && has_shell_wildcard { return Err(ZclawError::SecurityError( "ToolAll 与 ShellExec(\"*\") 不能同时授予".to_string(), )); } Ok(()) } /// Get capabilities for an agent pub fn get(&self, agent_id: &AgentId) -> Option { self.capabilities.get(agent_id).map(|c| c.clone()) } } impl Default for CapabilityManager { fn default() -> Self { Self::new() } }