Exec host 重構計畫
目標
- 新增
exec.host+exec.security以在 sandbox、gateway 和 node 之間路由執行。 - 預設值維持安全:除非明確啟用,否則不進行跨主機執行。
- 將執行分割為 headless runner 服務,搭配選用的 UI(macOS 應用)透過本地 IPC。
- 提供逐代理策略、白名單、詢問模式和節點綁定。
- 支援可搭配或不搭配白名單運作的詢問模式。
- 跨平台:Unix socket + token 驗證(macOS/Linux/Windows 一致)。
非目標
- 不做舊有白名單遷移或舊有 schema 支援。
- 節點 exec 不做 PTY/串流(僅彙總輸出)。
- 不在既有的 Bridge + Gateway 之外建立新的網路層。
決策(已鎖定)
- 設定鍵:
exec.host+exec.security(允許逐代理覆寫)。 - 提升: 保留
/elevated作為 gateway 完全存取的別名。 - 詢問預設值:
on-miss。 - 核准儲存:
~/.openclaw/exec-approvals.json(JSON,不做舊有遷移)。 - Runner: headless 系統服務;UI 應用透過 Unix socket 提供核准。
- 節點身分: 使用既有的
nodeId。 - Socket 驗證: Unix socket + token(跨平台);需要時之後分割。
- 節點主機狀態:
~/.openclaw/node.json(節點 id + 配對 token)。 - macOS exec host: 在 macOS 應用內執行
system.run;節點主機服務透過本地 IPC 轉發請求。 - 不使用 XPC helper: 維持 Unix socket + token + peer 檢查。
關鍵概念
Host
sandbox:Docker exec(現行行為)。gateway:在 gateway 主機上 exec。node:透過 Bridge(system.run)在節點 runner 上 exec。
安全模式
deny:一律阻擋。allowlist:僅允許匹配者。full:允許一切(等同 elevated)。
詢問模式
off:從不詢問。on-miss:僅在白名單未匹配時詢問。always:每次都詢問。
詢問與白名單獨立;白名單可搭配 always 或 on-miss 使用。
策略解析(逐 exec)
- 解析
exec.host(工具參數 -> 代理覆寫 -> 全域預設)。 - 解析
exec.security和exec.ask(相同優先順序)。 - 若 host 為
sandbox,以本地沙箱 exec 進行。 - 若 host 為
gateway或node,在該主機上套用 security + ask 策略。
預設安全
- 預設
exec.host = sandbox。 gateway和node預設exec.security = deny。- 預設
exec.ask = on-miss(僅在 security 允許時生效)。 - 若未設定節點綁定,代理可定位任何節點,但僅在策略允許時。
設定介面
工具參數
exec.host(選用):sandbox | gateway | node。exec.security(選用):deny | allowlist | full。exec.ask(選用):off | on-miss | always。exec.node(選用):host=node時使用的節點 id/名稱。
設定鍵(全域)
tools.exec.hosttools.exec.securitytools.exec.asktools.exec.node(預設節點綁定)
設定鍵(逐代理)
agents.list[].tools.exec.hostagents.list[].tools.exec.securityagents.list[].tools.exec.askagents.list[].tools.exec.node
別名
/elevated on= 為代理 session 設定tools.exec.host=gateway、tools.exec.security=full。/elevated off= 為代理 session 恢復先前的 exec 設定。
核准儲存(JSON)
路徑:~/.openclaw/exec-approvals.json
用途:
- 執行主機(gateway 或節點 runner)的本地策略 + 白名單。
- 無 UI 可用時的詢問回退。
- UI 用戶端的 IPC 憑證。
提議的 schema(v1):
{
"version": 1,
"socket": {
"path": "~/.openclaw/exec-approvals.sock",
"token": "base64-opaque-token"
},
"defaults": {
"security": "deny",
"ask": "on-miss",
"askFallback": "deny"
},
"agents": {
"agent-id-1": {
"security": "allowlist",
"ask": "on-miss",
"allowlist": [
{
"pattern": "~/Projects/**/bin/rg",
"lastUsedAt": 0,
"lastUsedCommand": "rg -n TODO",
"lastResolvedPath": "/Users/user/Projects/.../bin/rg"
}
]
}
}
}
說明:
- 不支援舊有白名單格式。
askFallback僅在需要ask且無可達 UI 時套用。- 檔案權限:
0600。
Runner 服務(headless)
角色
- 在本地強制
exec.security+exec.ask。 - 執行系統指令並回傳輸出。
- 發出 Bridge 事件用於 exec 生命週期(選用但建議)。
服務生命週期
- macOS 上為 Launchd/daemon;Linux/Windows 上為系統服務。
- 核准 JSON 為執行主機本地。
- UI 提供本地 Unix socket;runner 依需求連接。
UI 整合(macOS 應用)
IPC
- Unix socket 在
~/.openclaw/exec-approvals.sock(0600)。 - Token 儲存在
exec-approvals.json(0600)。 - Peer 檢查:僅限相同 UID。
- 挑戰/回應:nonce + HMAC(token, request-hash) 防止重播。
- 短 TTL(如 10s)+ 最大 payload + 速率限制。
詢問流程(macOS 應用 exec host)
- 節點服務從 gateway 接收
system.run。 - 節點服務連接至本地 socket 並傳送提示/exec 請求。
- 應用驗證 peer + token + HMAC + TTL,然後依需要顯示對話框。
- 應用在 UI 上下文中執行指令並回傳輸出。
- 節點服務將輸出回傳給 gateway。
UI 不存在時:
- 套用
askFallback(deny|allowlist|full)。
流程圖(SCI)
Agent -> Gateway -> Bridge -> Node Service (TS)
| IPC (UDS + token + HMAC + TTL)
v
Mac App (UI + TCC + system.run)
節點身分 + 綁定
- 使用 Bridge 配對中既有的
nodeId。 - 綁定模型:
tools.exec.node將代理限制在特定節點。- 若未設定,代理可選擇任何節點(策略仍強制預設值)。
- 節點選擇解析:
nodeId精確匹配displayName(正規化)remoteIpnodeId前綴(>= 6 字元)
事件
誰看到事件
- 系統事件為逐 session,在下一次 prompt 時呈現給代理。
- 儲存在 gateway 的記憶體內佇列(
enqueueSystemEvent)。
事件文字
Exec started (node=<id>, id=<runId>)Exec finished (node=<id>, id=<runId>, code=<code>)+ 選用的輸出尾部Exec denied (node=<id>, id=<runId>, <reason>)
傳輸
方案 A(建議):
- Runner 傳送 Bridge
eventframeexec.started/exec.finished。 - Gateway 的
handleBridgeEvent將這些對應至enqueueSystemEvent。
方案 B:
- Gateway 的
exec工具直接處理生命週期(僅同步)。
Exec 流程
Sandbox host
- 既有的
exec行為(Docker 或未沙箱化時為主機)。 - PTY 僅在非沙箱模式下支援。
Gateway host
- Gateway 行程在自己的機器上執行。
- 強制本地
exec-approvals.json(security/ask/allowlist)。
Node host
- Gateway 以
system.run呼叫node.invoke。 - Runner 強制本地核准。
- Runner 回傳彙總的 stdout/stderr。
- 選用的 Bridge 事件用於開始/完成/拒絕。
輸出上限
- 合併的 stdout+stderr 上限為 200k;事件保留尾部 20k。
- 截斷時附加清楚的後綴(如
"… (truncated)")。
斜線指令
/exec host=<sandbox|gateway|node> security=<deny|allowlist|full> ask=<off|on-miss|always> node=<id>- 逐代理、逐 session 覆寫;除非透過設定儲存否則不持久。
/elevated on|off|ask|full仍為host=gateway security=full的捷徑(full跳過核准)。
跨平台方案
- Runner 服務是可攜的執行目標。
- UI 為選用;不存在時套用
askFallback。 - Windows/Linux 支援相同的核准 JSON + socket 協定。
實作階段
第 1 階段:設定 + exec 路由
- 新增
exec.host、exec.security、exec.ask、exec.node的設定 schema。 - 更新工具串接以遵循
exec.host。 - 新增
/exec斜線指令並保留/elevated別名。
第 2 階段:核准儲存 + gateway 強制
- 實作
exec-approvals.json讀寫器。 - 為
gatewayhost 強制白名單 + 詢問模式。 - 新增輸出上限。
第 3 階段:節點 runner 強制
- 更新節點 runner 以強制白名單 + 詢問。
- 新增至 macOS 應用 UI 的 Unix socket 提示橋接。
- 串接
askFallback。
第 4 階段:事件
- 新增節點 -> gateway Bridge 事件用於 exec 生命週期。
- 對應至
enqueueSystemEvent供代理 prompt。
第 5 階段:UI 完善
- Mac 應用:白名單編輯器、逐代理切換器、詢問策略 UI。
- 節點綁定控制(選用)。
測試計畫
- 單元測試:白名單比對(glob + 不區分大小寫)。
- 單元測試:策略解析優先順序(工具參數 -> 代理覆寫 -> 全域)。
- 整合測試:節點 runner 拒絕/允許/詢問流程。
- Bridge 事件測試:節點事件 -> 系統事件路由。
開放風險
- UI 不可用:確保
askFallback被遵循。 - 長時間執行的指令:依賴逾時 + 輸出上限。
- 多節點歧義:除非有節點綁定或明確的節點參數否則報錯。