文件系统沙箱
使用 Linux bubblewrap 挂载命名空间限制 Agent 任务的文件系统可见性,并按工作区隔离任务数据。
文件系统沙箱将每个 Agent 子进程及其工具放入 Linux bubblewrap(bwrap)挂载命名空间。它控制文件系统的可见性与可写性,不控制网络访问、环境变量内容或可执行文件的运行权限。
MOPHEUS_SANDBOX_ENABLED=true沙箱默认开启,包括该变量未设置或为空的情况。只有将其设置为 false 或 off 才会关闭;其他值仍保持开启。
该能力仅在 Linux 且宿主机上的 bwrap 可用时生效。Daemon 会在包裹任务前执行一次最小能力探测(bwrap --ro-bind / / true),因为已安装的二进制仍可能被 AppArmor、SELinux、seccomp、内核配置或容器运行时禁止创建 user namespace。探测失败时,Daemon 记录原始错误并以非沙箱方式运行任务;只有探测和实际命令包裹都成功时,任务才会标记为已启用沙箱。
Linux 宿主机可使用以下命令排查:
bwrap --ro-bind / / true
sysctl kernel.apparmor_restrict_unprivileged_userns 2>/dev/null || true
sysctl kernel.unprivileged_userns_clone 2>/dev/null || true
sysctl user.max_user_namespaces 2>/dev/null || true
unshare -Ur trueUbuntu 23.10 及更高版本常见原因是 AppArmor 限制。Docker、LXC 和 CI 环境也可能在宿主机或容器安全策略层面施加相同限制。这是 Linux 能力问题,并非 Ubuntu 独有;其他发行版应检查实际生效的内核和安全策略。
Ubuntu 排查与解决
Ubuntu 的 APT 包名是 bubblewrap,安装后的命令名是 bwrap。请先安装,并使用运行 Mopheus daemon 的普通用户验证:
sudo apt update
sudo apt install bubblewrap
bwrap --version
bwrap --ro-bind / / true不要只在 root 用户下测试:root 可能测试成功,但 daemon 用户仍没有创建 user namespace 的权限。如果 APT 提示找不到 bubblewrap,请确认当前 Ubuntu 版本对应的软件源已启用,再运行 sudo apt update。
Ubuntu 23.10 及更高版本上若探测失败,再检查 AppArmor 限制和内核额度:
sysctl kernel.apparmor_restrict_unprivileged_userns 2>/dev/null || true
sysctl kernel.unprivileged_userns_clone 2>/dev/null || true
sysctl user.max_user_namespaces 2>/dev/null || true
sudo aa-status | grep -i bwrap || true
sudo journalctl -k | grep -i apparmor | tail -50如果内核日志显示 AppArmor 拒绝了 user namespace,可以选择以下两种宿主机方案:
-
临时全局关闭限制,用于确认问题来源。
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 bwrap --ro-bind / / true如需永久生效,可在
/etc/sysctl.d/下的配置文件中加入kernel.apparmor_restrict_unprivileged_userns=0,然后执行sudo sysctl --system。这会允许未受 profile 约束的应用创建 user namespace,因此只适合能够接受更大安全影响面的机器。 -
保持全局限制开启,只为 bwrap 放行 user namespace。
先检查是否已有附着到 bwrap 的 profile。不要为同一个可执行文件再添加第二个 profile;应检查并修改现有 profile。软件包也可能在
/usr/share/apparmor/extra-profiles/提供经过测试的 profile:command -v bwrap sudo aa-status | grep -i bwrap || true find /etc/apparmor.d /usr/share/apparmor/extra-profiles -iname '*bwrap*' -o -iname '*bubblewrap*' 2>/dev/null grep -R "userns" /etc/apparmor.d 2>/dev/null如果没有现有 profile,且
command -v bwrap输出/usr/bin/bwrap,创建/etc/apparmor.d/usr.bin.bwrap,内容如下:sudo vi /etc/apparmor.d/usr.bin.bwrap abi <abi/4.0>, include <tunables/global> /usr/bin/bwrap flags=(unconfined) { userns, } sudo apparmor_parser -r /etc/apparmor.d/usr.bin.bwrap sudo aa-status | grep -i bwrap bwrap --ro-bind / / true如果
command -v bwrap返回其他路径,请相应修改 profile 中的可执行路径和 profile 文件名。userns,规则允许匹配该 profile 的进程创建 namespace;flags=(unconfined)表示 AppArmor 不会对该可执行文件施加其他限制。请评估这项对宿主机所有 bwrap 调用生效的例外,并用实际 Mopheus Provider 验证。回滚手动创建的 profile:sudo apparmor_parser -R /etc/apparmor.d/usr.bin.bwrap sudo rm /etc/apparmor.d/usr.bin.bwrap
对于多人共用的宿主机,第二种方案更推荐,因为它会继续限制其他无关可执行文件。如果 AppArmor 已允许 userns 但探测仍失败,请确认 kernel.unprivileged_userns_clone 已开启,且 user.max_user_namespaces 大于零。能力仍不可用时,Mopheus 会记录探测输出并以非沙箱方式执行任务。
工作区隔离边界
沙箱按工作区隔离,而不是按单个任务隔离。同一工作区中的任务可以协作并共享运行所需的数据;其他工作区的数据不可见。
| 路径或范围 | 沙箱内权限 | 说明 |
|---|---|---|
/ | 只读 | 系统命令、动态库与系统配置可读取和执行,不能修改。 |
| 当前任务工作目录 | 可读写 | 可编辑代码、生成文件和写入任务日志。 |
| 当前工作区的其他任务目录 | 可读写 | 同工作区任务可见,这是协作范围。 |
当前工作区 .repos/<workspaceId> bare cache | 可读写 | worktree 的 .git 指针依赖该缓存,因此 git 操作可正常执行。 |
/tmp | 可读写 | 映射为宿主 /tmp/mopheus-<workspaceId>,同工作区任务共享。 |
| 其他工作区任务目录与 bare cache | 不可见 | WorkDir 上的 tmpfs 覆盖阻止读取和写入。 |
宿主其余 /tmp | 不可见 | /tmp 先被遮蔽,仅重新挂载当前工作区临时目录。 |
$HOME | 可读写 | Provider 配置、session 和 symlink 继续可用。 |
MOPHEUS_SANDBOX_DENY 指定路径 | 不可见 | 使用空 tmpfs 覆盖,不能读取或写入。 |
因此,沙箱提供跨工作区的任务数据隔离,但不将同一工作区的任务彼此隔离,也不默认隔离整个 $HOME。
敏感路径
~/.ssh 默认不隐藏,以保留通过 SSH 执行 git pull 和 git push 的能力。对于不受信任的 Agent,可通过逗号分隔的绝对路径隐藏额外凭据:
MOPHEUS_SANDBOX_DENY=~/.ssh,~/.aws,~/.gnupg隐藏凭据后,依赖这些凭据的操作会失败。应将最小权限与任务需要的 Git、云服务访问方式一起评估。
个人配置文件
启用沙箱后,Daemon 将已启用的个人配置文件暂存于 <WorkDir>/.config/<workspaceId>/<taskId>/,保留其相对 $HOME 的目录结构,并逐个覆盖到沙箱中的目标位置。暂存目录本身不会挂载。
- 每个文件按保存的文件模式以只读或读写方式挂载。
- 任务成功、失败、取消、超时或启动失败后都会清理暂存目录。
- 沙箱禁用或不可用时,任务继续执行,但不会下发这些配置文件。
- Daemon 启动时只清理
.config下 UUID 形式的 Mopheus 任务暂存目录,不影响无关内容。
托管 SSH 密钥与 SSH 配置片段通过这一机制下发。私钥在服务端加密存储,浏览器只能查看安全元数据和公钥;现有主机 SSH 配置不会被修改。
Provider 与降级
所有支持的 CLI Provider 在 Linux 上使用这一外层沙箱。启用时,Codex 会关闭自身内层沙箱,避免嵌套;不支持该能力的 Provider 会告警并以非沙箱方式执行。支持矩阵见 Provider CLI。
这是进程级挂载沙箱,可与容器运行时组合使用;它不是网络沙箱,也不替代访问控制、密钥管理或容器隔离。
| 环境变量 | 默认值 | 说明 |
|---|---|---|
MOPHEUS_SANDBOX_ENABLED | true | 为 Agent 子进程启用 bwrap 挂载命名空间。未设置或为空时启用,仅 false 或 off 会关闭。 |
MOPHEUS_SANDBOX_DENY | — | 额外隐藏的绝对路径,逗号分隔。 |