docs(sandbox): 补齐「lark-cli 按 bot 拆配置」这条沙盒前置条件 - #701
Conversation
沙盒/读隔离的白名单本来就是按「每个 bot 用自己的 lark-cli 配置目录」 设计的:deny 共享的 `~/.lark-cli` 与 macOS keystore 整目录,只放行 `~/.lark-cli-bots/<自己appId>`(rw)+ 本 bot 的 `master.key.file` / `appsecret_<自己appId>.enc`(ro)。但这个前提从没写进文档,机器没配过时 沙盒内所有 lark-cli 命令会以 `not configured` / `config_file: operation not permitted` 失败,而报错完全不指向根因—— 还会把人误导到「给 node/codex 开完全磁盘访问权限」上去(TCC 与 Seatbelt 是两套独立的强制访问控制,对 seatbelt 的 deny 毫无作用)。 新增 docs/lark-cli-per-bot.md:白名单切法与理由、 BOTMUX_LARK_APP_ID → LARKSUITE_CLI_CONFIG_DIR 的映射链路、配置步骤、 验证(含用线上 profile 做内核级读探测)、边界与排错。 边界部分记下几条实测/读码结论:沙盒下只有 bot 身份可用(用户 token `<appId>_<openId>.enc` 不在 carve-out 内);不要用 sandboxPaths.readOnly 整目录开洞(user rank 3 > baseline 0 能覆盖 deny,但会把所有 bot 的 appsecret 密文 + master key 暴露给当前 agent);no-transport turn 会冻结 整个飞书授权面、per-bot 目录与 keystore carve-out 都不发放;lark-cli 1.0.56 没有 whoami 子命令,自查用 auth status / config show。 同时在 docs/file-sandbox.md「启用」与 docs/isolated-bot-deploy.md 部署步骤 + 排错表交叉链接。纯文档,无代码改动。 Refs deepcoldy#683 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
deepcoldy
left a comment
There was a problem hiding this comment.
复审结论:需要修改。macOS 的 deny/carve-out 因果没有讲反,但 Linux 安全语义与 lark-cli 1.0.56 的实际落盘行为相反,当前文字会给出错误的跨 bot 隔离保证。
[P1] Linux 密钥并不在 per-bot 配置目录,当前策略会把所有 bot 的密文和 master key 暴露为 readOnly
docs/lark-cli-per-bot.md:22 写道「Linux(bwrap)把密钥直接放在 per-bot 目录里」,但我用 PR 明确声称实测的 lark-cli 1.0.56 在隔离 HOME 下复现:
.lark-cli-bots/cli_review_56/config.json
.local/share/lark-cli/appsecret_cli_review_56.enc
.local/share/lark-cli/master.key
即 LARKSUITE_CLI_CONFIG_DIR 只重定向 config.json,Linux fallback keystore 仍落在 ~/.local/share/lark-cli。当前 commonHomeBaseline() 又把整个 ~/.local/share 设为 readOnly,且 Linux 没有对 ~/.local/share/lark-cli 的 deeper deny/carve-out。直接调用策略真源得到:
~/.local/share/lark-cli/master.key readOnly
~/.local/share/lark-cli/appsecret_cli_other.enc readOnly
~/.lark-cli-bots/cli_self/config.json readWrite
~/.lark-cli-bots/cli_other/config.json none
因此 Linux 沙盒内的 bot 能读到兄弟 bot 的 appsecret 密文和共享 master key;还可以改写自己可写的 config 指向兄弟 appId/key id,从而以兄弟 app 身份调用 lark-cli。这个问题也存在于当前安装的 1.0.76,不是只影响旧版本。
在合并这份“安全前置条件”文档前,至少需要二选一:
- 修正 Linux policy:deny
~/.local/share/lark-cli,仅 carve-out 本 bot 所需的 master key +appsecret_<self>.enc(并补策略/编译器测试);或 - 明确把该隔离保证限定为 macOS,并警告 Linux 文件沙盒下 lark-cli 的跨 bot secret 隔离尚未成立。
否则 file-sandbox.md 新增的跨平台前置条件会把一个实际未闭合的 secret 边界描述成已闭合。
[P2] 不要建议在隔离 bot 会话内首次 config init
docs/lark-cli-per-bot.md:72 暗示在 bot 会话内加 --force-init 即可。但首次配置时 per-bot 目录尚不存在,worker 的 existence filter 不会发放这条 allow;即便预建了目录,Linux 的 ~/.local/share/lark-cli、macOS 的 keystore carve-out 在沙盒内也只能读,config init 无法写入新 appsecret/master key。--force-init 只绕过 lark-cli 的 Agent-context 检查,不绕过 bwrap/Seatbelt。
建议把步骤 2 明确限定为沙盒外的宿主终端;若要保留 --force-init 说明,需限定为非隔离的 OPENCLAW/HERMES 类 Agent 会话。
其余我复核的 macOS 路径、source-rank/deepest-prefix、no-transport gate、用户 token 不 carve-out、Seatbelt profile 路径均与源码/测试一致。纯文档 diff 的 git diff --check 也通过。按群内要求,未执行合并。
|
我让agent直接改下 |
感觉linux下基线需要增强下 |
Refs #683。纯文档,零代码改动。
问题
沙盒 / 读隔离的白名单本来就是按「每个 bot 用自己的 lark-cli 配置目录」设计的:
~/.lark-cli~/Library/Application Support/lark-cli(整目录)…/master.key.file、…/appsecret_<自己appId>.enc~/.lark-cli-bots/<自己appId>但这个前提从没写进任何文档。机器没做过「按 bot 拆 lark-cli 配置」时,沙盒内所有
lark-cli命令都以not configured/config_file: operation not permitted失败,而报错完全不指向根因——#683 里就一路被误导到「给 node / codex 开完全磁盘访问权限」上去(TCC 与 Seatbelt 是两套互相独立的强制访问控制,TCC 授权对 Seatbelt 的 deny 规则毫无作用)。fs-policy.ts里其实已经有一行注释提到「botmux's lark-cli identity mapping lives there(~/.zshenv)」——契约存在于代码注释里,用户侧无从得知。改动
新增
docs/lark-cli-per-bot.md:BOTMUX_LARK_APP_ID→LARKSUITE_CLI_CONFIG_DIR→~/.lark-cli-bots/<appId>~/.zshenv映射(为什么必须是.zshenv不是.zshrc)、per-botconfig init+default-as bot、开放平台开 scopeconfig show/auth status,以及用会话线上的 Seatbelt profile 做内核级读探测交叉链接:
docs/file-sandbox.md「启用」段、docs/isolated-bot-deploy.md部署步骤 + 排错表。边界部分记下的几条实测 / 读码结论
<appId>_<openId>.enc不在 carve-out 内,--as user及一切依赖用户 token 的命令读不到。sandboxPaths.readOnly整目录开洞:user 源 rank=3 > baseline rank=0 确实能覆盖 deny 让命令跑起来,但等于把所有 bot 的 appsecret 密文 + master key 交给当前 bot 的 agent,是安全回退。apiOnlybot / HTTP 虚拟会话)下 lark-cli 一律不可用:整个飞书授权面被冻结,per-bot 目录与 keystore carve-out 都不发放。这是有意的。whoami子命令(fix(sandbox): macOS 沙盒 deny lark-cli 认证/配置路径,agent 在沙盒内无法读 auth/whoami/doctor(Full Disk Access 无法覆盖 Seatbelt) #683 里提到的那个)。自查身份用auth status/config show。没做的(可后续单独提)
这份 PR 只补文档。真正把隐式契约变成显式行为的两件事没做:
LARKSUITE_CLI_CONFIG_DIR(该目录存在时),让它不再依赖用户手改 shell rc——现在的.zshenv方案在不经过登录 shell 的 spawn 路径上、以及非 zsh 机器上会静默失效;~/.lark-cli-bots/<appId>/config.json缺失时 spawn 前 warn 一条,把静默失败变成指向文档的提示。验证
文档里的命令输出、路径、行为都在 macOS + lark-cli 1.0.56 上对着当前 master 的
fs-policy.ts逐条核过。🤖 Generated with Claude Code