Deploy Your OpenClaw Online Click to Deploy Now

Python ToolPermissionContext

Python 端的权限系统以 ToolPermissionContext 数据类为核心,它携带两个用于阻止工具的字段:

class ToolPermissionContext: deny_names: frozenset[str] # exact tool names to block deny_prefixes: tuple[str, ...] # prefix patterns to block

deny_names 是一个 frozenset,包含应被阻止的确切工具名称。deny_prefixes 是一个字符串前缀的 tuple——名称以列出的前缀开头的任何工具都会被阻止。两个字段都通过 from_iterables 类方法构建,该方法将所有条目转换为小写以确保不区分大小写的匹配。

阻止检查在 blocks() 方法中实现:

def blocks(self, tool_name: str) -> bool: name_lower = tool_name.lower() if name_lower in self.deny_names: return True return any( name_lower.startswith(prefix) for prefix in self.deny_prefixes )

该方法首先检查与 deny_names 的精确匹配,然后检查小写化的工具名称是否以 deny_prefixes 中的任何条目开头。这种两阶段检查非常高效:frozenset 查找是 O(1),前缀扫描是 O(n),且前缀列表通常很小。

Rust 权限模型

Rust 层实现了一个更丰富的权限模型,包含三种不同的模式:

enum PermissionMode { Allow, // tool is always permitted Deny, // tool is always blocked Prompt, // user is asked for each invocation }

Prompt 模式是与 Python 层的关键区别。Rust 权限系统不是做二元的允许/拒绝决策,而是可以暂停执行并询问用户是否允许特定的工具调用。这通过 PermissionPrompter trait 来协调:

struct PermissionRequest { tool_name: String, input: String, } enum PermissionPromptDecision { Allow, Deny { reason: String }, } trait PermissionPrompter { fn decide(&mut self, request: PermissionRequest) -> PermissionPromptDecision; }

PermissionRequest 包含工具名称和完整的输入字符串,因此用户可以做出关于是否允许特定操作的知情决策。PermissionPromptDecision 枚举在拒绝时包含一个可选的 reason,该原因会反馈给模型,使其理解为什么工具使用被拒绝。

PermissionPolicy

PermissionPolicy 结构体将所有内容串联在一起。它定义了 default_mode(应用于没有特定覆盖的任何工具)和 tool_modes 映射(BTreeMap<String, PermissionMode>)用于逐工具覆盖:

struct PermissionPolicy { default_mode: PermissionMode, tool_modes: BTreeMap<String, PermissionMode>, }

策略通过 new(default_mode) 构建,并通过 with_tool_mode(tool_name, mode) 为各个工具定制。mode_for(tool_name) 方法查找工具的特定模式,如果没有覆盖则回退到默认值。

authorize(tool_name, input, prompter) 方法执行完整的授权流程:

  1. 通过 mode_for 查找工具的模式
  2. 如果是 Allow,立即返回 PermissionOutcome::Allow
  3. 如果是 Deny,返回带有静态原因的 PermissionOutcome::Deny
  4. 如果是 Prompt,构建 PermissionRequest 并调用 prompter.decide()
  5. 将提示器的决策映射到 PermissionOutcome

PermissionOutcome 枚举镜像了决策类型:AllowDeny{reason}。策略(应用什么模式)和提示(如何询问用户)之间的分离使系统可测试——在测试中,提示器可以是一个始终允许或始终拒绝的 mock。

CLI 权限模式

CLI 通过 args.rs 提供三种预设权限模式,为常见用例提供便捷的默认值:

默认模式

WorkspaceWrite 作为默认值是有原因的——它提供足够的能力来完成实际开发工作,同时保持沙箱边界完好。ReadOnly 适用于代码审查和探索。DangerFullAccess 仅应在智能体受信任的受控环境中使用。

工具过滤

权限过滤在工具到达智能体的上下文窗口之前进行。get_tools 函数接受 permission_context 参数并调用 filter_tools_by_permission_context 从列表中移除任何被阻止的工具。这确保被拒绝的工具永远不会出现在系统提示中——智能体根本不知道它们的存在。

这种设计比事后强制执行更安全。如果被阻止的工具出现在提示中但在执行时被拒绝,智能体会浪费回合尝试使用它,并可能试图绕过限制。通过在提示级别过滤,智能体的决策被限制在它实际可以使用的工具范围内。

简单模式

简单模式是最严格的工具配置。启用后,工具池被缩减为恰好三个工具:

所有其他工具——Web 访问、子智能体、搜索、笔记本、任务管理——都被移除。这为完整的 19 个工具套件过于庞大的受限环境提供了最小的、可预测的攻击面。

运行时权限推断

运行时层通过 _infer_permission_denials 添加最终的权限检查。此函数根据活动的 CLI 权限模式来控制类似 bash 的工具(任何可以执行任意命令的工具)。即使工具通过了 ToolPermissionContext 过滤器,运行时推断层仍然可以基于更广泛的会话权限来阻止它。

这种分层方法——Python 拒绝列表过滤、Rust 策略引擎、CLI 模式预设和运行时推断——创建了纵深防御。每一层都能捕获其他层可能遗漏的情况,确保 Claw Code 权限系统对配置错误和边缘情况具有鲁棒性。

安全模型总结

Claw Code 权限系统通过四层提供逐工具粒度:Python 拒绝列表(快速过滤)、Rust 权限策略(带提示的细粒度控制)、CLI 模式预设(便捷默认值)和运行时推断(最终控制)。在任何层被阻止的工具永远不会到达智能体。