OpenAI Codex · 沙箱

沙箱管理器:把权限档案编译成一行命令

工作区可写,网络收紧。同一条 git status,Mac 套上 sandbox-exec,Linux 套上 helper,Windows 可能原样出门。差别出在编译器。

课程目标读完能说清:一份权限档案怎样被选成一种沙箱类型,再被编译成一行命令。要不要上沙箱、这台机器有没有后端,是两道题。同一份档案还会渲染进模型看见的 environment_context
先玩一遍 · 同一条命令,三层壳
同一份档案:看三台机器各自套上什么壳
Windows 档位
关着给不出实现。打开之后,Windows 才进入第二拍。
工具偏好
Forbid 钉死不需要。Require 钉死需要,钉不死机器上有没有后端。
托管网络
打开之后 Auto 必须上沙箱。Windows 若仍关着,类型还是 None。
模型看见的档案

还没渲染。

等待开始。点播放,看同一条命令在三台机器上各自套上什么壳。
逻辑轨迹 · 动画每一步对应源码里的哪一段
  1. 读入 PermissionProfile 三态models.rs L411
  2. 叠上 additional permissionspolicy_transforms.rs L525
  3. Auto 则跑 should_require_platform_sandboxpolicy_transforms.rs L541
  4. select_initial 再问 get_platform_sandboxmanager.rs L62
  5. None 则原样传出 argvmanager.rs L366
  6. macOS 前置 /usr/bin/sandbox-execmanager.rs L401
  7. Linux 序列化档案给 helperlandlock.rs L23
  8. Windows 第一拍不改 argvmanager.rs L447
  9. 同一份档案渲染进 environment_contextenvironment_context.rs L96
点播放,看同一条 git status 在三台机器上各自被套上什么壳。
三行命令
需要和能提供
模型那一侧
教学示意:命令固定为 git status,不调用真实 shell。外层包装按平台合同简化。逻辑轨迹右侧行号对应 openai/codex 仓库 commit 4f39251a01。
思路一 · 要不要,和有没有,是两道题
它解决什么问题

同一份仓库,三台机器,模型发出同一条 git status。配置里写的是同一份权限档案:工作区可写,网络收紧。

排障的人会以为沙箱没生效。日志里档案还在,模型上下文里那份 environment_context 也还在。只是平台这一层没有把档案编译成包装命令。Windows 上开关关着,编译器交出原 argv,策略层还在。

思路是什么

SandboxManager 先问要不要,再问有没有。should_sandbox 只返回一个布尔。Forbid 恒假,Require 恒真,Auto 看档案形状。有托管网络要求,必须上。网络收紧时,除了调用方自己管文件系统,都要上。网络放开且文件系统不受限,才跳过。

出处:codex-rs/sandboxing/src/manager.rs 第 310 至 329 行 · codex-rs/sandboxing/src/policy_transforms.rs 第 541 至 561 行

然后 get_platform_sandbox 按操作系统给类型。macOS 给 Seatbelt,Linux 给 seccomp helper。Windows 多一个开关,关着就是空。空的意思是这台主机没有可派发的实现。

出处:codex-rs/sandboxing/src/manager.rs 第 62 至 76 行

select_initial 先问前者,再把后者的空收成 SandboxType::None。档案说需要,主机给不出,类型仍是 None

出处:codex-rs/sandboxing/src/manager.rs 第 293 至 306 行

权限档案 谁建沙箱,条目有多宽 要不要 should_sandbox → 布尔 有没有 get_platform_sandbox → 可选 三台机器的壳 macOS · sandbox-exec Linux · helper 加档案 JSON Windows · 第一拍不改 argv 给不出实现就保持原命令
教学化结构图:两道题分开问,编译产物才按平台分叉。
为什么长期成立

配置里的意图和主机上的后端,本来就会分手。产品文案、状态栏、模型说明如果都去读配置里希望启用的那一侧,排障会从这里开始歪。两个函数,一个返回布尔,一个返回可选的后端名。换语言重写也用得上。

思路二 · 一份档案,两个出口
它解决什么问题

权限如果写成两份,改了一边忘了另一边,模型就会按旧边界规划下一步。模型看见没有外层沙箱,和 Windows 关沙箱时落到 None,应该是同一份意图的两个出口。

思路是什么

PermissionProfile 三个变体写的是谁负责建外层沙箱。Managed 由 Codex 自己拼包装命令。Disabled 不要外层。External 文件系统由调用方负责,网络仍可能归 Codex 管。

出处:codex-rs/protocol/src/models.rs 第 411 至 425 行

transform 按类型分派。None 原样传出用户 argv,连本机 cwd 都不准备,因为未沙箱的请求可能带着外机路径。macOS 只信任 /usr/bin/sandbox-exec,策略走 -p,路径走 -D,用户命令放在 -- 后面。Linux 把整份档案序列化进 --permission-profile,helper 缺失直接报错,不会按无沙箱降级。Windows 第一拍只校验,argv 不动;包装器就是当前 exe,套壳推迟到 transform_for_direct_spawn

出处:codex-rs/sandboxing/src/manager.rs 第 365 至 459 行 · codex-rs/sandboxing/src/seatbelt.rs 第 52 至 56 行 · codex-rs/sandboxing/src/landlock.rs 第 15 至 23 行 · codex-rs/sandboxing/src/manager.rs 第 484 至 518 行

同一份档案由 FileSystemContext 收成内部枚举,渲染进 environment_contextDisabled 写成 type="disabled" 加 unrestricted 文件系统。模型可见文本挡不住越权,只减少无效尝试。

出处:codex-rs/core/src/context/environment_context.rs 第 96 至 116 行

有效档案 基座叠上 extra transform → argv 隔离发生在子进程入口 render → environment_context 模型看见同一份运行时事实
教学化结构图:一份运行时值,两个出口。
平台给不出实现时,XML 不会改口。
为什么长期成立

运行时事实只应有一份。隔离发生在子进程入口,编排层继续拿路径和档案,到执行边界才落地。平台方言会变,这份同时喂给包装命令和模型的档案形状用得上。

思路三 · 开口用并集,批准用求交
它解决什么问题

单条命令还可以再带一份 overlay。如果人批的时候用并集,一次误批就能把请求里没有的路径写进会话授权。

思路是什么

合并走并集:任一侧打开网络,结果就是开网;文件系统条目首尾相接去重。求交走另一套:网络必须两侧都开才留下;文件系统只保留落在请求范围内的已批条目。求交结果为空,会话不记账,基座档案继续生效。空集的含义是这次额外开口没留下任何加宽。命令还能不能跑,要看后面的策略和沙箱。

出处:codex-rs/sandboxing/src/policy_transforms.rs 第 90 至 142 行 · codex-rs/sandboxing/src/policy_transforms.rs 第 144 至 214 行 · codex-rs/core/src/session/mod.rs 第 2833 至 2846 行

为什么长期成立

加宽和批准是两件事。并集让这条命令多开一条路径这件事说得清。求交保证人批下来的不宽过请求。空集表示开口失败,不要解释成改成最严,也不要解释成整条命令禁止。

横向对比 · 切在哪一层,失败倒向哪一边

DeepSeek Harness:缺后端就拒绝执行

DSH 也切在子进程入口。confine 按当前主机选 runner,再把政策编成 runner 参数,用户命令放在 -- 后面。档案词汇只有三个文件模式,danger-full-access 不进包装。

缺后端时 fail closed,不退回原 argv。文案写明 refusing to run the command unconfined。Codex 在 Unix helper 缺失时同样不跑;Windows 关沙箱时把给不出实现收成 None,交给后面的策略层。

两侧均已核对源码 · 2026-08-22 · DSH · 沙箱

Grok:一次 apply,锁住当前进程

Grok 也有一个叫 SandboxManager 的类型,职责是 apply()install()。注释写明:作用对象是当前进程,不可逆。编译产物是 CapabilitySet,不包每条命令的 argv。

平台不支持,或 apply 失败,都打警告、记 apply_failed,然后继续跑。后面的工具调用共享同一份 capability。Grok 不用为每条命令再编 argv,也没法在同一进程里给两条命令两套边界。

两侧均已核对源码 · 2026-08-22 · Grok · 五种沙箱 Profile

出处:packages/sandbox/sandbox-local/src/index.ts 第 316 至 333 行 · crates/codegen/xai-grok-sandbox/src/lib.rs 第 117 至 136 行

课堂练习
01

四条返回,三组输入

打开 should_require_platform_sandbox,用纸画出四条返回。然后对下面三组给出预测:Disabled 档案加托管网络;根可写加一条 deny、网络 Enabled;External 档案、网络 Restricted。

进阶一问:同一份 Disabled 档案,工具声明 Require,Windows 档位仍关着。类型会是什么,模型看见的 XML 会不会改口。

Takeaway:先把需要隔离、这台机器能提供什么,写成两个函数。一份权限档案同时喂给包装命令和模型。Windows 分两拍,关着时交出原 argv,策略层还在。