专题篇章 · 拆开 OpenAI Codex

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

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

本页解决的问题

先给结论

「沙箱管理器:把权限档案编译成一行命令」要解决的关键问题是什么?

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

判断标准

跟着交接处走,不要只看 Demo。 系统是否可靠,往往取决于模型、工具、状态、权限和人的交接处。把每次交接都当成可以观察、测试和恢复的地方。

下一步

为一个自动化步骤写清输入、负责人、审批和恢复动作。

常见误区

一次运行成功了,却说不清发生了什么,也无法安全重放。

课程目标读完能说清:一份权限档案怎样被选成一种沙箱类型,再被编译成一行命令。要不要上沙箱、这台机器有没有后端,是两道题。同一份档案还会渲染进模型看见的 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,策略层还在。

「先玩一遍 · 同一条命令,三层壳」的能力藏在每次交接里

「同一份仓库,三台机器,模型发出同一条 git status 。配置里写的是同一份权限档案:工作区可写,网络收紧」说明,Agent 的表现不只由模型决定。模型、上下文、工具、状态、权限和人之间的每次交接,都会改变任务能否继续以及出了问题能否恢复。

先写清状态,再增加能力

从「排障的人会以为沙箱没生效。日志里档案还在,模型上下文里那份 environment_context 也还在。只是平台这一层没有把档案编译成包装命令。Windows 上开关关着,编译器交出原 argv,策略层还在」出发,可以把流程拆成起始状态、下一步动作、工具返回、状态更新和停止条件。这样调试时找的是第一处丢失信息或权限的位置,而不是笼统地说“模型变笨了”。

  • 读入 PermissionProfile 三态 models.rs L411
  • 叠上 additional permissions policy_transforms.rs L525
  • Auto 则跑 should_require_platform_sandbox policy_transforms.rs L541

成功路径不能代表系统可靠

用「进阶一问:同一份 Disabled 档案,工具声明 Require ,Windows 档位仍关着。类型会是什么,模型看见的 XML 会不会改口」重放一次成功和一次失败,记录每一轮真正传入的上下文、工具结果和负责人;只要第二个人能复述这条链,系统才有可维护性。

从「先玩一遍 · 同一条命令,三层壳」走到「思路一 · 要不要,和有没有,是两道题」

「先玩一遍 · 同一条命令,三层壳」先把问题落在「同一份档案:看三台机器各自套上什么壳 播放 单步 重置 Windows 档位 关着 RestrictedToken 关着给不出实现。打开之后,Windows 才进入第二拍。 工具偏好 Auto Forbid Require Forbid 钉死不需要。Require 钉死需要,钉不死机器上有没有后端。 托管网络 关 开 打开之后 Auto 必须上沙箱。Windows 若仍关着,类型还是 None。 macOS 待选 g…」上;到了「思路一 · 要不要,和有没有,是两道题」,讨论继续推进到「同一份仓库,三台机器,模型发出同一条 git status 。配置里写的是同一份权限档案:工作区可写,网络收紧」。两段连起来,重点就不只是记住一个结论,而是看清它成立所依赖的条件。

把这条判断带到下一个场景

分析 Agent 时,沿着状态、动作、工具结果和下一步的顺序走一遍;每次交接都要能说明信息从哪里来、由谁确认、失败时停在哪里。

  • 「先玩一遍 · 同一条命令,三层壳」:同一份档案:看三台机器各自套上什么壳 播放 单步 重置 Windows 档位 关着 RestrictedToken 关着给不出实现。打开之后,Windows 才进入第二拍。 工具偏好 Auto Forbid Require Forbid 钉死不需要。Require 钉死需要,钉不死机器上有没有后端。 托管网络 关 开 打开之后 Auto 必须上沙箱。Windows 若仍关着,类型还是 None。 macOS 待选 g…
  • 「思路一 · 要不要,和有没有,是两道题」:同一份仓库,三台机器,模型发出同一条 git status 。配置里写的是同一份权限档案:工作区可写,网络收紧
  • 「最后的要点」:None 则原样传出 argv manager.rs L366

最后的「最后的要点」把讨论落到「None 则原样传出 argv manager.rs L366」。回看这条线索时,最值得保留的是:当输入、规模或风险改变,哪些判断需要重新做一遍。

标记为已学完 阅读进度会自动记录
← 上一篇下一篇 →

继续阅读

同一条线上的下一篇。

文章讨论

读到这里,留下一个判断。

把刚想明白的地方、还没想通的问题,留给下一位一起学习的人。

正在讨论 沙箱管理器:把权限档案编译成一行命令 拆开 OpenAI Codex
3条讨论文章讨论 · 与共学社区同步
在共学社区查看
AM
Asha Morgan内容编辑
观点实践记录

我把这篇文章里的一个判断改写成了今天可以验证的小实验。比记住结论更有用的是,知道下一步要观察什么。

文章讨论7 有帮助
LH
Lin Harper独立开发者
观点观点

读完以后我先回头找它成立的条件,而不是直接把方法搬进项目。这个顺序让后面的取舍清楚很多。

文章讨论5 有帮助
KM
Kiki Moore产品运营
问题问题

如果把这个判断放到真实工作里,最先需要补的约束是什么?我想知道从阅读到第一次实践之间,哪一步最值得先做。

文章讨论4 有帮助