主题
命令执行引擎
本文引用的源码文件
本文引用的文件
目录
引言
本文件面向“命令执行引擎”的完整技术文档,聚焦以下目标:
- 命令安全分级系统:白名单机制、危险命令检测、参数注入防护、执行权限控制。
- 进程管理:进程创建、监控、终止、资源清理。
- 输出流处理:标准输出捕获、错误流分离、实时流式传输、缓冲区管理。
- 超时控制与资源限制:执行时间限制、内存使用监控、CPU 占用控制、并发执行限制。
- 进程树管理:父子进程关系跟踪、僵尸进程清理、进程组操作。
- 安全配置:命令白名单维护、沙箱环境配置、安全策略调优。
该引擎运行在独立本地代理端(Agent),由 Chrome 扩展通过 HTTP/WebSocket 调用;命令执行与安全校验是 Agent 的核心子系统之一。
项目结构
命令执行相关代码集中在 agent 子项目中,关键文件如下:
- security.js:路径沙箱、命令黑白灰名单、命令替换与内联载荷解析、环境变量剥离与包装器剥壳。
- executor.js:基于 child_process.spawn 的命令执行、WebSocket 流式输出、超时策略、进程生命周期管理。
- process-tree.js:跨平台整棵进程树终止工具。
- server.js:HTTP/WebSocket 路由入口,统一设置语言、鉴权、调用 security 与 executor,并暴露运行中进程列表等状态。
graph TB Client["客户端<br/>Chrome 扩展"] --> Server["服务器路由<br/>server.js"] Server --> Security["安全管控<br/>security.js"] Server --> Executor["命令执行器<br/>executor.js"] Executor --> PT["进程树工具<br/>process-tree.js"] Executor --> OS["操作系统 shell<br/>cmd/powershell/bash/zsh/fish"]
图表来源
- agent/src/server.js#L1-L56
- agent/src/security.js#L1-L10
- agent/src/executor.js#L1-L10
- agent/src/process-tree.js#L1-L10
章节来源
- agent/src/server.js#L1-L56
- agent/src/security.js#L1-L10
- agent/src/executor.js#L1-L10
- agent/src/process-tree.js#L1-L10
核心组件
- 安全管控模块(security.js)
- 路径沙箱:硬阻止目录、工作目录放行、allowedPaths 白名单、realpath 防符号链接绕过。
- 命令分级:黑名单(deny)、灰名单(confirm)、允许(allow)。
- 命令解析:链式拆分、解释器内联载荷提取、$( ) 与反引号替换扫描、包装器/提权前缀剥壳、路径归一化。
- 命令执行器(executor.js)
- Shell 选择:按平台与环境变量探测可用 shell,避免 Git Bash MSYS 路径不可执行等问题。
- 进程生命周期:spawn 启动、stdout/stderr 流式广播、close/error 收尾、execId 映射、已完成缓存回放。
- 超时策略:受管模式(extend/kill 决策函数)、旧模式直接 kill、断开连接时受管模式不解除超时。
- 进程终止:Windows taskkill /T /PID,POSIX 负 PID 进程组信号,5 秒后 SIGKILL 兜底。
- 进程树工具(process-tree.js)
- killProcessTree:跨平台整树终止(POSIX 进程组 + Windows taskkill /T)。
- stopProcessTree:SIGTERM → graceMs → SIGKILL,保证调用方不会永久挂起。
- 服务器路由(server.js)
- 统一 i18n 语言注入到各子模块。
- 认证与 CORS:仅放行 chrome-extension:// 来源。
- 暴露运行中进程列表、资源使用统计(内存/CPU/uptime)。
- 文件上传/下载/读写/删除等接口均经 checkPath 校验。
章节来源
- agent/src/security.js#L62-L229
- agent/src/security.js#L285-L384
- agent/src/security.js#L393-L683
- agent/src/security.js#L691-L758
- agent/src/executor.js#L32-L91
- agent/src/executor.js#L118-L156
- agent/src/executor.js#L165-L186
- agent/src/executor.js#L198-L386
- agent/src/executor.js#L429-L549
- agent/src/process-tree.js#L18-L73
- agent/src/server.js#L427-L443
- agent/src/server.js#L722-L748
架构总览
命令执行请求从服务器路由进入,先进行鉴权与语言设置,再调用安全模块检查命令与路径,最后由执行器 spawn 子进程并通过 WebSocket 推送 stdout/stderr。
sequenceDiagram
participant C as "客户端"
participant S as "服务器(server.js)"
participant SEC as "安全(security.js)"
participant EXE as "执行器(executor.js)"
participant OS as "Shell/OS"
C->>S : "POST /api/exec(或 WS 连接)"
S->>S : "鉴权/i18n/加载配置"
S->>SEC : "checkCommand(command, force)"
SEC-->>S : "{safe, level, reason}"
alt "deny"
S-->>C : "拒绝响应"
else "confirm/allow"
S->>EXE : "executeCommand(command, cwd, wsClient)"
EXE->>OS : "spawn(shell, args)"
OS-->>EXE : "stdout/stderr/close/error"
EXE-->>C : "WS 推送 stdout/stderr/exit"
end
图表来源
详细组件分析
安全管控模块(security.js)
- 路径沙箱
- 硬阻止目录:Agent 自身敏感配置文件、日志、回收站、技能状态等绝对禁止访问。
- 工作目录永远放行:用户当前 workdir 必须可访问,即使不在 allowedPaths 中。
- allowedPaths 白名单:支持多目录,使用前缀匹配 + realpath 二次校验,防止符号链接绕过。
- 路径格式规整:MSYS/Git Bash 风格、盘符大写、正斜杠统一,避免大小写/分隔符差异导致绕过。
- 命令分级
- 黑名单(deny):高危写入系统目录、格式化磁盘、覆盖关键系统文件、fork bomb、shebang 直接执行、管道直连 sh、修改根目录权限/属主、Windows 破坏性命令等。
- 灰名单(confirm):sudo/doas/runas、全局 npm install、pip 安装卸载、递归强制删除、git push --force、shutdown/reboot/halt/poweroff、eval、dd/shred/truncate、chmod/chown 危险组合、网络外联、进程操作、系统服务/计划任务、脚本解释器执行外部文件、PowerShell 破坏性 cmdlet 与 base64 内联载荷等。
- 允许(allow):未命中任何规则。
- 命令解析与注入防护
- 链式命令拆分:&&、||、;、|、&、换行,保留引号/反引号/$( ) 内部语义。
- 包装器剥壳:nohup/time/timeout/nice/stdbuf/env/exec/command/xargs/sudo/doas 等逐层剥壳,使真实命令暴露到段首正则。
- 解释器内联载荷:POSIX -c/-e、cmd /c /k、PowerShell -Command/-EncodedCommand,base64 解码失败不视为放行依据。
- 命令替换扫描:$( ) 与反引号内部子命令单独送检,避免只读头命令豁免被滥用。
- 路径归一化://usr、/.//usr、/tmp/../usr 等等价系统目录不能因写法不同降级。
- 环境变量剥离:KEY=VAL 前缀剥离,避免误判普通命令参数为命令。
flowchart TD
Start(["输入命令"]) --> Split["链式拆分"]
Split --> Peel["剥包装器/提权前缀"]
Peel --> Inline["提取解释器内联载荷"]
Inline --> Subst["提取 $( )/反引号替换"]
Subst --> Normalize["路径归一化"]
Normalize --> Blacklist{"命中黑名单?"}
Blacklist --> |是| Deny["deny"]
Blacklist --> |否| Graylist{"命中灰名单?"}
Graylist --> |是| Confirm["confirm"]
Graylist --> |否| Allow["allow"]
图表来源
章节来源
- agent/src/security.js#L62-L229
- agent/src/security.js#L285-L384
- agent/src/security.js#L393-L683
- agent/src/security.js#L691-L758
命令执行器(executor.js)
- Shell 选择
- Windows:优先 SHELL/COMSPEC 指向的 bash/powershell/cmd;若无效则探测 Git Bash 常见路径;回退 COMSPEC 或 cmd.exe。
- macOS:优先 zsh/bash;回退 /bin/zsh。
- Linux:优先 bash/zsh/fish;回退 /bin/bash 或 /bin/sh。
- 进程创建与流式输出
- spawn(shell, args, {cwd, env, stdio:['ignore','pipe','pipe'], detached/windowsHide})。
- stdout/stderr 分别监听 data 事件,实时 JSON 广播给所有 WS 客户端。
- 输出缓冲区上限 5MB,超过截断并广播 truncated 提示。
- close/error 事件统一收尾,记录 exitCode/killed/timedOut,移入 completedProcesses 缓存供延迟连接回放。
- 超时策略
- 受管模式:传入 timeoutMs 即接管超时权威;期内有输出才延长,静默即杀;最大延长次数与总预算封顶。
- 旧模式:commandTimeout 到期直接 kill。
- decideTimeoutAction:纯函数,便于单测;返回 extend/kill 及下次超时毫秒数。
- 进程终止与资源清理
- Windows:taskkill /T /PID 递归终止,失败则 /F /T /PID 强制。
- POSIX:优先 process.kill(-pid) 进程组信号,失败回退单进程;5 秒后 SIGKILL 兜底。
- disconnectWsClient:受管模式下不断开就取消超时;仅显式 detach 才豁免。
- detachProcess:标记 detached,清除超时定时器,让进程继续运行。
- getRunningProcesses:返回 execId/pid/command/startTime/duration。
classDiagram
class Executor {
+executeCommand(command, cwd, wsClient, onComplete, collectOutput, execOpts) string
+executeCommandSync(command, cwd, timeoutMs) Promise
+addWsClient(execId, wsClient) boolean
+disconnectWsClient(execId, wsClient) boolean
+detachProcess(execId) boolean
+killProcess(execId) boolean
+getRunningProcesses() array
+pickShell(platform, env, exists) object
}
class ProcessTree {
+killProcessTree(child, signal) boolean
+stopProcessTree(child, options) Promise
}
Executor --> ProcessTree : "间接使用(终止整树)"
图表来源
- agent/src/executor.js#L32-L91
- agent/src/executor.js#L198-L386
- agent/src/executor.js#L429-L549
- agent/src/process-tree.js#L18-L73
章节来源
- agent/src/executor.js#L32-L91
- agent/src/executor.js#L118-L156
- agent/src/executor.js#L165-L186
- agent/src/executor.js#L198-L386
- agent/src/executor.js#L429-L549
- agent/src/process-tree.js#L18-L73
服务器路由(server.js)中的命令执行集成
- 语言注入:每个请求将 Accept-Language 解析结果同步到 security/executor/trash/search/rag/skill/mcp 等子模块。
- 运行中进程与资源统计:/api/status/detail 返回 runningProcesses、memoryUsedMB/memoryTotalMB/memoryRssMB、uptimeSeconds、cpuUser/cpuSystem。
- 文件接口统一走 checkPath:read/write/list/stat/delete/download/upload-stream 等均需路径白名单校验。
- 更新与重启:npm install -g 使用 stopProcessTree 整树终止,避免孤儿进程。
章节来源
- agent/src/server.js#L427-L443
- agent/src/server.js#L722-L748
- agent/src/server.js#L751-L862
- agent/src/server.js#L1036-L1160
依赖关系分析
- server.js 依赖 security.js 与 executor.js,并在请求入口处注入语言。
- executor.js 依赖 process-tree.js 用于整树终止(例如 npm 更新流程)。
- security.js 提供 checkPath/checkCommand,供文件接口与命令执行前置校验。
- 外部依赖:child_process、os、crypto、ws、archiver、fs/fs/promises 等。
graph LR Server["server.js"] --> Security["security.js"] Server --> Executor["executor.js"] Executor --> ProcessTree["process-tree.js"] Security --> Config["config.js(路径/工作目录)"] Executor --> Config
图表来源
- agent/src/server.js#L1-L56
- agent/src/security.js#L1-L10
- agent/src/executor.js#L1-L10
- agent/src/process-tree.js#L1-L10
章节来源
- agent/src/server.js#L1-L56
- agent/src/security.js#L1-L10
- agent/src/executor.js#L1-L10
- agent/src/process-tree.js#L1-L10
性能与资源限制
- 输出缓冲区限制:stdout/stderr 各自最多 5MB,超过截断并广播 truncated 消息,防止长时间命令无限增长内存。
- 超时控制:
- 受管模式:根据 decideTimeoutAction 动态延长,最多 MAX_TIMEOUT_EXTENSIONS 次,且不超过 TOTAL_BUDGET_CAP_MS。
- 旧模式:commandTimeout 到期直接 kill。
- 资源监控:/api/status/detail 暴露 heapUsed/heapTotal/rss、uptime、cpuUser/cpuSystem,便于上层做 CPU/内存告警。
- 并发执行:runningProcesses Map 以 execId 为键,无显式并发上限;可通过上层调度限制并发度。
- 环境变量白名单:SAFE_ENV_KEYS 过滤宿主敏感信息,强制 TERM=dumb、FORCE_COLOR=0,减少终端干扰。
章节来源
- agent/src/executor.js#L93-L116
- agent/src/executor.js#L118-L156
- agent/src/executor.js#L165-L186
- agent/src/executor.js#L297-L323
- agent/src/server.js#L722-L748
故障排查指南
- 命令被 deny
- 检查是否命中黑名单(如 rm -rf /dev/、mkfs.、dd of=/dev/、fork bomb、shebang、管道直连 sh、修改根目录权限/属主、Windows format/diskpart/System32/config/SAM 等)。
- 检查是否包含 Agent 敏感路径(.ai-helper-agent 下 config.json/logs/.trash/builtin_skills_state.json/disabled_skills.json)。
- 命令频繁 confirm
- 灰名单命中项包括 sudo/doas/runas、npm install -g、pip install/uninstall、rm -r -f、git push --force、shutdown/reboot/halt/poweroff、eval、dd/shred/truncate、chmod/chown 危险组合、curl/wget/nc/telnet/ssh/scp、kill/pkill/killall、systemctl/launchctl/crontab/sysctl、脚本解释器执行外部文件、PowerShell remove-item -recurse/-force 与 -EncodedCommand。
- 可通过“本次任务放行”降低确认频次,但黑名单不可绕过。
- 输出被截断
- stdout/stderr 超过 5MB 会触发 truncated 提示;建议缩短命令输出或分批查看。
- 进程无法终止
- Windows:taskkill /T /PID 失败后会尝试 /F /T /PID;POSIX:先 SIGTERM 进程组,5 秒后 SIGKILL。
- 若仍残留,可使用 process-tree.js 的 stopProcessTree 等待退出或强制结束。
- 超时异常
- 受管模式:期内无输出会被视为挂起/静默失败,不再延长;检查命令是否真的产生 stdout/stderr。
- 旧模式:commandTimeout 到期直接 kill;调整 commandTimeout 或改用受管模式。
章节来源
- agent/src/security.js#L285-L384
- agent/src/security.js#L691-L758
- agent/src/executor.js#L297-L323
- agent/src/executor.js#L500-L549
- agent/src/process-tree.js#L18-L73
安全配置指南
- 命令白名单维护
- 黑名单与灰名单位于 security.js,新增高危命令应加入 BLACKLIST_PATTERNS 或 GRAYLIST_PATTERNS,并明确 reasonKey。
- 对于“读取即外泄”类命令(如 cat /etc/passwd),注意命令通道不受 allowedPaths 约束,需在更高层面(如业务策略)限制。
- 沙箱环境配置
- workdir:通过 /api/config/workdir 切换,自动追加到 allowedPaths;禁止设为 .ai-helper-agent 目录本身。
- allowedPaths:通过 /api/config/allowed-paths/remove 移除非工作目录;保持最小权限原则。
- 文件上传:upload-stream 与 upload 均经 checkPath 校验,脚本文件写入后剥离执行权限(chmod 0o644)。
- 安全策略调优
- 超时策略:优先使用受管模式(传入 timeoutMs),结合 decideTimeoutAction 的 extend/kill 逻辑,避免静默长任务耗尽资源。
- 环境变量:SAFE_ENV_KEYS 已过滤敏感信息;如需新增必要变量,请谨慎评估泄露风险。
- 进程终止:对 npm 等可能派生孙进程的任务,使用 stopProcessTree 确保整树清理。
章节来源
- agent/src/security.js#L62-L229
- agent/src/security.js#L285-L384
- agent/src/server.js#L872-L930
- agent/src/server.js#L932-L983
- agent/src/server.js#L751-L862
- agent/src/executor.js#L118-L156
- agent/src/executor.js#L165-L186
- agent/src/process-tree.js#L18-L73
结论
命令执行引擎通过“路径沙箱 + 命令分级 + 流式输出 + 超时策略 + 进程树终止”形成闭环:
- 安全层面:黑名单绝对禁止、灰名单用户确认、路径白名单与 realpath 防绕过、敏感路径硬阻止。
- 执行层面:跨平台 shell 选择、stdout/stderr 分离与实时广播、5MB 缓冲上限、受管超时策略。
- 运维层面:运行中进程列表与资源统计、整树终止、脚本权限剥离、工作目录与 allowedPaths 管理。 建议在部署时严格限定 workdir 与 allowedPaths,启用受管超时模式,并结合 /api/status/detail 监控内存与 CPU,必要时在上层实现并发限制与告警。