11. 工具、权限与安全边界
Agent 系统的安全边界不在“模型有没有被提醒小心”,而在工具执行前的确定性检查。Craft 将 Claude hook 与 Pi JSONL request 都收敛到 runPreToolUseChecks(),再把需要人决策的部分返回成结构化 prompt。
11.1 工具的四个来源
Section titled “11.1 工具的四个来源”| 来源 | 例子 | 执行位置 |
|---|---|---|
| provider built-in | Read/Write/Edit/Bash/Glob/Grep | Claude SDK 或 Pi subprocess |
| session-scoped | submit plan、browser、spawn、call_llm、set status | in-process callback / MCP bridge |
| source proxy | mcp__linear__create_issue |
父进程 McpClientPool |
| mini/background | title、summary、task helpers | backend mini completion/host |
无论来源,涉及文件、shell、网络 mutation 或系统权限时,都应在同一产品 policy 下运行。
11.2 固定权限模式
Section titled “11.2 固定权限模式”持久枚举是:
type PermissionMode = 'safe' | 'ask' | 'allow-all'UI 可能显示 Explore / Ask to Edit / Auto;代码注释偶尔保留旧称 explore/execute,但序列化值不可变化。
- 只读 Bash pattern;
- Read/Glob/Grep 等读取;
- 禁止普通 Write/Edit/mutation;
- 特例允许写当前 session 的精确
plansFolderPath和dataFolderPath,用于提交计划与安全数据转换; - 不用弹窗,因为 safe 语义是“阻止”,不是“问”。
- 读操作直接通过;
- Bash、文件写、MCP/API mutation、admin 变成 permission prompt;
- 可有 session-scoped always allow command/domain;
- 高风险命令不会因宽松自定义规则静默放行。
allow-all
Section titled “allow-all”- 权限层自动通过写/命令;
- 仍经过输入规范化、配置 schema、source activation、prerequisite 和某些结构安全 guard;
- “allow all”不等于关闭整个 pipeline。
11.3 模式事实源
Section titled “11.3 模式事实源”Pre-tool input 带一个 permissionMode,但中央管道会再次从 session mode manager 读取 canonical effective mode。若二者不同,只用后者决策并记录:
- incoming/effective;
modeVersion;lastChangedBy/At。
源码:pre-tool-use.ts。
这防止 provider hook 捕获旧闭包:用户刚 Shift+Tab 改模式,旧 query 的 callback 参数仍可能是上一版。
11.4 中央管道的结果类型
Section titled “11.4 中央管道的结果类型”type Result = | { type: 'allow' } | { type: 'modify'; input } | { type: 'block'; reason; source? } | { type: 'prompt'; promptType; description; ... } | { type: 'source_activation_needed'; sourceSlug; sourceExists } | { type: 'call_llm_intercept'; input } | { type: 'spawn_session_intercept'; input }为什么需要 modify?路径展开、skill qualification、metadata stripping、RTK command rewrite 都会改变真正执行的 input,但模型仍应看到与自己意图一致的 tool result。
为什么 intercept call_llm/spawn_session?它们需要 host 级 auth、session 创建与预算控制,不能当普通 MCP call 直接进 provider。
11.5 六阶段 PreToolUse
Section titled “11.5 六阶段 PreToolUse”代码注释列出主顺序:runPreToolUseChecks。
flowchart TD I["normalized tool + input"] --> M["1. permission mode"] M -->|block| B["block with diagnostics"] M --> S["2. inactive source check"] S -->|inactive| A["source activation needed"] S --> P["3. prerequisite"] P -->|missing guide/skill| B P --> X["4. call_llm/spawn intercept"] X --> T["5. input transforms + config guards"] T --> Q["6. ask-mode prompt decision"] Q -->|read/safe| OK["allow/modify"] Q -->|mutation| U["permission prompt"]顺序不是随意的。例如 inactive source 要在 tool execute 前变成 activation flow;prerequisite 要在 source mutation prompt 之前阻止,确保模型先读 guide;ask prompt 应基于原始 command 做安全判断,再把 RTK rewrite 作为执行 input。
11.6 Mode check
Section titled “11.6 Mode check”shouldAllowToolInMode() 解析 tool 类别、Bash command、文件目标、API method/path 和 permissions.json 合并规则。
Safe 模式的 plans/data 例外必须比较规范化绝对路径;仅检查字符串前缀会被 ../ 或相似目录名绕过。路径处理章节与 sandbox 再做二次保护。
若阻止,reason 附 effective mode 与最后变更信息,帮助调试“明明切了 Auto 为什么还拦”。
11.7 Source activation
Section titled “11.7 Source activation”对于 mcp__<slug>__<tool>:
session与craft-agents-docs是 built-in,不按用户 source 拦;- 若
<slug>不在 activeSourceSlugs:返回 activation needed; - 同时标记 source 是否存在,区分“已配置但未启用”和“根本没有配置”。
Agent adapter 调用 SessionManager 的 activation callback;成功后工具集热更新,并可触发原用户消息一次自动重试。
11.8 Prerequisite
Section titled “11.8 Prerequisite”PrerequisiteManager 确保:
- skill mention 后先读 SKILL.md;
- source tool 前先读 guide.md;
- compaction 后重新读;
- Bash 中用于读取 pending skill 的命令可被识别并解除前置条件。
若没满足,返回 block 且 source:'prerequisite'。这不是安全拒绝,而是可恢复的教学反馈;Agent 读文件后再次调用即可。
11.9 Input transforms
Section titled “11.9 Input transforms”把 ~、相对路径和特定 tool 字段规范成执行环境可理解的绝对路径。远程模式必须以 server working directory 为准。
写 workspace config/source/status/permission/automation 等文件前,解析候选内容并跑 schema;无效写在落盘前被阻止。
Config CLI guard
Section titled “Config CLI guard”开启 feature flag 时,直接用 Bash/Write 操作 labels/automations 等受管目录会被阻止,并提示使用 craft-agent CLI/专用 tool。这样验证、migration 和事件不会被绕开。
Skill qualification
Section titled “Skill qualification”把简短 skill name 补为 workspace/global 作用域下的明确身份,避免同名歧义。
Metadata stripping
Section titled “Metadata stripping”Pi 可能在 input 里附 metadata.intent/displayName。这些用于产品 UI,不应传给真实 MCP/API schema,因此在执行前剥离,同时父进程另存显示元数据。
RTK rewrite
Section titled “RTK rewrite”若启用,原 Bash 可重写成 RTK 包装命令以改善输出/工具体验。权限决策仍针对原命令,只有 SDK 执行拿 rewrite 后输入,避免包装器名字掩盖危险原命令。
11.10 Ask 模式分类
Section titled “11.10 Ask 模式分类”Prompt 类型:
bash;file_write;mcp_mutation;api_mutation;admin_approval。
结构化请求包含 description、command、appName、reason、impact、是否预期 OS prompt、remember window、command hash、approval TTL。UI/消息渠道不必解析字符串来决定按钮和风险说明。
11.11 Bash 安全
Section titled “11.11 Bash 安全”- read-only pattern 判断;
- base command extraction;
- dangerous command 集;
- network domain extraction/whitelist;
- session-scoped alwaysAllowedCommands/domains。
危险集合包含删除/权限/磁盘/进程/关机、curl/wget/ssh/scp/rsync,以及 git push/reset/rebase/checkout 等。仅看第一个 token 不够:管道、&&、重定向、shell wrapper 都可能隐藏后续 mutation,所以 mode-manager 还有更完整的 shell 分析与 config rules。
安全结论:正则/allowlist 是降低风险,不是 shell 语义证明。高保证场景仍需 OS sandbox 或容器。
11.12 文件写安全
Section titled “11.12 文件写安全”文件工具要同时考虑:
- permission mode;
- canonical path/符号链接;
- workspace/session allowed roots;
- safe plans/data 例外;
- config domain schema;
- session script sandbox 的 input/output root;
- 跨机器/远程路径不存在。
session-tools-core/runtime/path-security.ts 与 filesystem isolation tests 覆盖 traversal/symlink 等,防止仅靠 prompt/PreToolUse 字段检查。
11.13 API/MCP mutation
Section titled “11.13 API/MCP mutation”API wrapper 知道 HTTP method/path,GET 等读取可自动通过;POST/PATCH/DELETE 等在 ask 模式形成 api_mutation。MCP 没有统一 read/write 标志,只能结合 tool annotations、命名/配置与 source guide 分类。
风险:第三方 MCP 可能把删除动作命名成 get_status。权限系统不能完全信任名字,应优先使用 MCP readOnlyHint/destructiveHint 等标准 annotations,未知工具在 ask/safe 下保守处理。
11.14 Admin approval 与命令完整性
Section titled “11.14 Admin approval 与命令完整性”少数操作(如 Homebrew 受保护目录步骤)需要原生管理员权限。分类器返回:
- plain-language reason/impact;
requiresSystemPrompt;rememberForMinutes;commandHash;- TTL。
PrivilegedExecutionBroker 在执行前比较 expected hash 与待执行 command hash,并检查过期/一次性状态。这样审批 UI显示的命令不能在批准后被替换。
仅传 boolean “approved”是不够的;批准必须绑定具体 command、session、时间窗。
11.15 Remembered approval
Section titled “11.15 Remembered approval”Session-scoped whitelist 允许减少重复弹窗:
- command 按规范化/base command 记录;
- network command 可按 domain;
- 有时间或 session 生命周期边界;
- 不跨 workspace/global 默默永久化;
- dangerous/admin 类可有更严格限制。
如果 command input 在审批后被 transform,完整性校验要明确 hash 针对原命令还是最终执行命令。Craft 的 RTK 策略是决策针对原命令,admin broker则绑定最终 privileged command。
11.16 Session tools 单一来源
Section titled “11.16 Session tools 单一来源”session-tools-core/tool-defs.ts 用 Zod 定义 canonical schema/description/handler registry,再派生:
- Claude SDK Zod shape;
- Pi/MCP JSON Schema(移除
$schema兼容 AJV); - 验证后的 typed handler input。
新增工具不应分别复制 schema。否则两 backend 可能接受不同字段、安全描述不同。
11.17 Script sandbox
Section titled “11.17 Script sandbox”script_sandbox 与 transform_data 执行 Python/Node/Bun,但有:
- runtime resolution;
- input file allowlist;
- output 必须在 session data;
- traversal/symlink 校验;
- 环境变量最小化;
- network isolation(平台能力允许时);
- timeout,
script_sandbox最大 15 秒; - stdout/result 限制。
这比给模型普通 Bash 更适合处理大 source response:数据落文件,脚本在受限目录转换,只把小结果回上下文。
11.18 Headless 与消息审批
Section titled “11.18 Headless 与消息审批”Ask 模式需要人,但 headless server 可能只有 WebUI/Telegram。Permission request 是 SessionEvent,所以可以由不同渠道承接;消息 binding 的 approvalChannel 决定在 chat 还是 app 审批,但“是否要审批”仍由 session mode 决定。
若没有任何可达审批 surface,ask 会卡住。自动 TaskRunner 因此不会默认 ask;部署时健康检查应暴露 pending request,而不是让 session静默等待。
11.19 安全边界图
Section titled “11.19 安全边界图”flowchart LR MODEL["Untrusted model output"] --> SCHEMA["Tool schema parse"] SCHEMA --> PRE["Central PreToolUse"] PRE --> HUMAN["Optional human approval"] HUMAN --> HOST["Host handler / SDK tool"] HOST --> OS["Filesystem / process / network"] HOST --> OUT["Result guard + binary/large externalization"] OUT --> MODEL每层负责不同问题:schema 防形状错误,PreToolUse 防策略越权,人审批给意图授权,host/sandbox 防 OS 越界,result guard 防返回内容撑爆上下文。
11.20 已知边界
Section titled “11.20 已知边界”allow-all允许高影响行为,仍需用户明确选择;- shell 静态分析无法覆盖所有语言/编码/间接执行;
- MCP mutation 分类依赖第三方 annotations/配置;
- 机器绑定凭据加密保护静态文件,但同用户下恶意进程仍可能调用系统/读取内存;
- prompt injection 可能诱导合法工具组合造成危害,需 source trust 与人审批共同缓解;
- remote capability 还需客户端侧校验,服务端允许不代表本机应无条件执行。
11.21 本章小结
Section titled “11.21 本章小结”Craft 安全设计的核心不是三档按钮,而是让所有 backend 在执行前进入同一个判定管道,并把“阻止、修改、激活、前置读取、拦截、人工审批”建模成不同结果。安全语义因此不随 provider 切换。
下一章沿 source proxy tool 继续往下:一个 source 如何从文件配置、凭据/OAuth、连接池变成模型可调用的动态工具。