exec.ts 下篇 —— OpenClaw用户审批、后台任务与权限提升控制
关键词:用户审批|后台任务|权限提升|交互式终端|租户隔离|超时熔断
在上一篇中,我们介绍了 OpenClaw exec.ts 的三层隔离模型(Sandbox / Gateway / Remote),为 Shell 命令执行建立了基础安全边界。然而,真正的挑战在于运行时控制:当 AI 提出一个高风险操作时,系统如何确保人类始终保有最终决策权?当命令耗时较长时,又如何避免阻塞主对话流?
OpenClaw 的答案是三大核心机制:
- 用户审批(User Approval)—— 人类确认高危操作
- 后台任务(Background Task)—— 非阻塞长时执行
- 权限提升控制(Elevated Privilege Gate)—— 白名单 + 上下文感知
本文将逐一拆解这些机制的设计细节与工程实现。
一、用户审批:让人类成为“最后守门人”
触发条件
当满足以下任一条件时,命令执行将暂停并等待用户确认:
host: "gateway"或host: "remote"- 命令包含在
elevatedWhitelist中(即使白名单内也需确认) - 命令涉及写操作(如
git commit,npm install)
原则:任何可能改变系统状态的操作,必须经用户显式授权。
审批流程(以 WhatsApp 为例)

审批卡片设计要点
- 明确命令:显示完整、未截断的命令字符串
- 上下文信息:工作目录、目标远程节点
- 一键操作:确认/拒绝按钮(非文本回复,防误触)
- 超时失效:5 分钟未响应自动拒绝
移动端优先:审批体验针对手机通知优化。
二、后台任务:长时命令不阻塞对话
某些命令(如 yarn build、docker pull)可能耗时数十秒甚至数分钟。若同步等待,会导致:
- WebSocket 连接超时
- 用户以为系统卡死
- 无法中断或查询进度
OpenClaw 引入 后台任务机制(Background Task)解决此问题。
核心逻辑:yieldMs 超时检测
// exec.ts
const YIELD_THRESHOLD_MS = 10_000; // 10 秒
const startTime = Date.now();
let lastOutputTime = startTime;
// 监听命令 stdout/stderr 流
child.stdout.on('data', (chunk) => {
lastOutputTime = Date.now();
sendProgressToClient(chunk); // 实时推送输出
});
// 定时检查是否“长时间无输出”
setInterval(() => {
if (Date.now() - lastOutputTime > YIELD_THRESHOLD_MS) {
promoteToBackground(taskId);
}
}, 5000);
后台任务行为
- 立即返回占位响应:
“命令已转入后台运行(任务 ID: task_xyz)。您可随时发送
/task status task_xyz查询进度。” - 持续推送日志:通过 ACP 事件
tool.call.log流式输出 - 支持中止:用户可发送
/task kill task_xyz - 完成通知:任务结束时主动推送结果
用户体验:从“等待”变为“异步协作”。
三、权限提升控制:不只是白名单
仅靠命令白名单(如 ["git status", "npm run build"])仍存在风险:
npm run build可能执行任意脚本(若package.json被篡改)- 路径遍历:
git status --work-tree=/etc
因此,OpenClaw 实施多维权限提升控制:
1. 路径沙箱(Path Sandbox)
- 所有
gateway命令的工作目录被限制在allowedPaths内 - 自动拒绝包含
..、绝对路径(除非在白名单路径内)
function resolveSafeCwd(baseDir: string, userPath: string): string {
const resolved = path.resolve(baseDir, userPath);
if (!resolved.startsWith(baseDir)) {
throw new Error("Path traversal detected");
}
return resolved;
}
2. 环境变量净化
执行前清除敏感环境变量:
const SAFE_ENV = {
PATH: "/usr/bin:/bin",
LANG: "en_US.UTF-8",
HOME: allowedPaths[0],
// 移除:SSH_AUTH_SOCK, AWS_SECRET_ACCESS_KEY, DOCKER_HOST...
};
3. 上下文感知白名单
白名单可基于智能体上下文动态生效:
# agents/dev-assistant/config.yaml
bashTools:
elevatedWhitelist:
- command: "kubectl get pods"
onlyIf: { project: "k8s-cluster-alpha" } # 仅当会话上下文含此标签
权限 = 命令 + 路径 + 环境 + 上下文
四、交互式终端支持:PTY 与实时输入
某些命令需要交互(如 sudo 输入密码、vim 编辑文件)。OpenClaw 通过 PTY(伪终端)支持有限交互。
实现方式
import { spawn } from 'node-pty';
const ptyProcess = spawn('bash', [], {
name: 'xterm-color',
cols: 80,
rows: 24,
cwd: safeCwd,
env: SAFE_ENV
});
// 将用户输入转发给 PTY
gateway.on('tool.input', (input) => {
if (task.isInteractive && task.owner === userId) {
ptyProcess.write(input);
}
});
安全限制
- 仅允许当前会话用户发送输入
sudo默认禁用(因无法安全传递密码)- 会话超时 2 分钟自动 kill PTY
目标不是完全终端替代,而是安全的有限交互。
五、租户隔离:防止越权操作
在多用户/多智能体环境中,必须确保:
- 用户 A 不能查看或中止用户 B 的任务
- 智能体 X 不能访问智能体 Y 的工作目录
OpenClaw 通过 isInScope() 函数实现租户隔离:
function isInScope(task: BackgroundTask, requester: UserContext): boolean {
return (
task.sessionKey === requester.sessionKey ||
(task.agentId && requester.hasAccessToAgent(task.agentId))
);
}
所有 task.kill、task.log 操作均经过此检查。
多租户安全是企业部署的前提。
六、审计与可观测性
所有高权限操作均记录结构化日志:
{
"event": "exec.elevated",
"timestamp": 1710234567,
"userId": "user_abc",
"sessionId": "wa:+1234567890",
"command": "npm run deploy",
"cwd": "/home/user/app",
"approved": true,
"taskId": "task_xyz",
"exitCode": 0
}
- 日志自动脱敏(移除 API Key、密码)
- 支持对接 SIEM 系统(如 ELK、Splunk)
可审计,才可信。
结语:安全是动态平衡,不是静态开关
exec.ts 的设计哲学是:不阻止 AI 行动,但确保每一步都在可控、可观察、可撤销的框架内进行。通过用户审批、后台任务与多维权限控制,OpenClaw 在“能力”与“责任”之间找到了工业级系统的黄金平衡点。
这不仅是技术实现,更是对人机协作关系的深刻理解——AI 是助手,人类是主人。
在下一篇中,我们将转向进程管理,解析
process.ts如何让 AI 像开发者一样监控和操作后台服务。
下一篇预告:
第 12 篇:process.ts —— AI 如何像开发者一样管理后台进程
您的 AI 助手,从此由您定义。若感兴趣可以浏览本书其他章节内容:
浙公网安备 33010602011771号