运行时

文件系统沙箱

使用 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 true

Ubuntu 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,可以选择以下两种宿主机方案:

  1. 临时全局关闭限制,用于确认问题来源。

    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,因此只适合能够接受更大安全影响面的机器。

  2. 保持全局限制开启,只为 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_ENABLEDtrue为 Agent 子进程启用 bwrap 挂载命名空间。未设置或为空时启用,仅 false 或 off 会关闭。
MOPHEUS_SANDBOX_DENY—额外隐藏的绝对路径,逗号分隔。