Codex 配置与权限系统:TOML 层级与三种审批策略

在自主 Coding Agent 的运行过程中,权限裁决是一个避不开的核心命题:当模型意图修改文件、执行系统命令或发起网络请求时,由谁来做出“允许”还是“拒绝”的决策?

不同框架给出的技术路线截然不同:

  • Claude Code 采用动态应用层检查:规则以内置交互为主,运行时通过终端 Prompt 向用户索权;
  • DeepSeek Harness 采用策略平面(Policy Plane):审批逻辑被抽象为插件,开发者可编写代码实现复杂的上下文动态规则;
  • OpenAI Codex CLI 选择了第三条路:配置即代码(Configuration as Code),将权限边界全部收敛至分层的 TOML 配置文件中。

在 Codex 中,没有图灵完备的动态审批脚本,也没有不可预测的黑盒策略。所有规则在启动前由 Rust 的 serde 解析完毕,运行时仅执行极速查表。这种设计牺牲了部分动态上下文灵活性,却换来了绝对的可预测性与可审计性。


TOML 三层配置体系与优先级继承

Codex 的配置由三层 TOML 文件级联构成,其生效优先级从低到高如下:

1. 用户级配置(User Level)

通常位于 ~/.codex/config.toml,用于声明个人全局偏好:

1
2
3
4
5
6
7
8
[model]
default = "o3"

[sandbox]
mode = "workspace-write"

[approval]
policy = "on-request"

该配置表明:默认选用 o3 模型,沙箱默认限制在当前工作区可写,工具调用采用“按需提示”。

2. Profile 级配置(Profile Level)

当工程师需要在不同工作场景之间快速切换时,可以在 $CODEX_HOME/ 下维护不同的命名配置集。例如一个用于严格审计环境的 strict.config.toml:

1
2
3
4
5
6
# $CODEX_HOME/strict.config.toml
[sandbox]
mode = "read-only"

[approval]
policy = "untrusted"

在终端执行 codex --profile strict 即可加载。Profile 配置会覆盖全局配置中的对应项,未声明的字段则继续继承全局设定。

3. 项目级配置(Project Level)

位于项目根目录的 .codex/config.toml,通常由团队统一维护并提交进代码仓库:

1
2
3
4
5
6
7
8
# .codex/config.toml
[sandbox]
writable_roots = ["src/", "tests/", "docs/"]

[mcp.servers.github]
transport = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]

硬规则:安全约束只能收紧,不能放宽

在配置合并逻辑中,Codex 贯彻了一条铁律:更具体的子路径约束优先,且 deny 永远优于 write。

例如,当你在配置中指定:

1
2
3
[sandbox.filesystem]
"src/" = "write"
"src/generated/" = "deny"

即便模型在对 src/ 下的其他源码文件进行正常重构,一旦其生成的工具调用试图触碰 src/generated/ 目录,内核沙箱检查器会无条件判定为 deny。这种分级路径约束杜绝了误伤关键静态产物或配置模板的可能。


三种预设沙箱模式

Codex 没有暴露成百上千个杂乱的开关,而是将运行环境归纳为三种明确的预设沙箱模式:

模式名称 文件系统写权限 网络出站权限 衍生子进程权限 推荐使用场景
read-only 完全禁止(只读) 受限(仅允许模型 API 等) 受限 代码审查、依赖分析、架构探查
workspace-write 仅当前工作区(默认模式) 受限 受限 日常主力编码、常规功能开发与测试
danger-full-access 系统全盘可写 完全放开 完全放开 宿主系统运维、全局环境初始化(极高风险)

1. read-only

在此模式下,文件系统对模型完全呈只读状态。模型可以遍历代码树、提取 AST、回答复杂调用链问题,但没有任何工具能落盘修改。适用于只要求生成建议或执行安全审计的只读会话。

2. workspace-write(默认基准)

绝大多数研发日常使用的安全底线。模型被严格囚禁在当前工作目录及其子路径内。它无法触碰用户的 ~/.ssh/、~/.aws/,更无法修改系统的 /etc/ 目录。
如果希望进一步限制写操作的范围,可通过 writable_roots 白名单进一步收拢:

1
2
3
[sandbox]
mode = "workspace-write"
writable_roots = ["src/", "tests/"]

此时,即使是当前项目根目录下的 package.json 或 Cargo.toml,模型也无法擅自改动。

3. danger-full-access

命名中显式的 danger- 前缀是刻意设计的防御性命名,强制开发者意识到这属于完全脱离防护的高危操作。此模式下沙箱全面放开,仅适合全自动服务器部署或本地全局运维脚本执行,在常规业务开发中应当避免。


三种审批策略(Approval Policies)

配置中的 [approval].policy 决定了当模型发起可能改变系统状态的工具调用时,交互层如何处理:

  1. untrusted(完全不信任):
    无论只读还是写入,每一次外部命令派发或工具调用都必须等待开发者手动回车确认。执行速度最慢,但在审计外来开源代码或高危脚本时最为稳妥。
  2. on-request(按需审批,默认):
    读取文件、目录遍历、合法状态查询等无副作用操作自动放行;凡涉及文件覆写、删除或执行外部 Shell 脚本等产生持久化副作用的行为,均暂停并向开发者申请批准。
  3. never(免审批):
    不进行任何终端拦截。通常仅在配合 read-only 模式(因为本来就无法写),或在经过充分隔离的无人工干预自动化容器中使用。

细粒度审批重载(按类别覆盖)

为了避免“一刀切”造成的配置困扰,Codex 支持对特定类别的能力进行审批策略重载:

1
2
3
4
5
6
7
8
[approval]
policy = "on-request"

# 针对外部 MCP 工具调用强制进行全量审批
mcp_elicitations = "untrusted"

# 针对预装本地 Skill 加载完全放行
skill_approval = "never"

注:部分极细维度的重载字段在官方说明文档中有涉及,但在开源代码主干中仍在逐步演进合并。


仓库信任机制(Trust-on-First-Use)

项目级配置 .codex/config.toml 带来了极大的团队一致性便利,但同时也引入了潜在的恶意代码投毒风险:如果一个恶意的公共仓库在 .codex/config.toml 中配置了 mode = "danger-full-access" 并附带恶意构建指令,开发者一旦克隆并运行,就可能面临越权攻击。

为了化解该问题,Codex 引入了与 Git safe.directory 类似的 首次使用信任原则(Trust-on-First-Use):

  1. 当首次在一个未标记信任的目录中启动 Codex 时,CLI 会显式忽略该目录下的 .codex/config.toml,仅降级采用用户的全局安全配置;
  2. 只有当开发者在终端显式执行:
    1
    codex trust
    该项目路径才会被记录在用户的安全白名单中,后续会话方可合法加载项目专属的沙箱与 MCP 规则。

权限方案横向对比:静态配置 vs 动态审批

下表对比了 Codex 与 Claude Code 在权限体系上的根本差异:

评估维度 Codex CLI(模式 + 静态 TOML) Claude Code(应用层逐操作审批)
规则可预测性 极高(只要审阅 TOML 文件即完全确定) 中等(取决于运行时模型的操作上下文)
规则版本化与审计 极佳(可纳入 Git 进行 Code Review) 较难(配置规则分布在设置项与对话提示中)
动态上下文灵活性 较低(无法编写“仅工作时间允许”等动态规则) 较高(可通过动态 Prompt 与用户实时交互)
用户认知负担 集中在配置初始化阶段,后续按模式稳定运行 分散在每次操作弹窗中,容易引起点击疲劳
底层绕过难度 极高(最终由操作系统内核强制执行) 中等(依赖框架内部正则与拦截逻辑的严密性)

下一步

明确了 TOML 配置的优先级与模式后,接下来的核心问题是:这些路径和模式究竟是如何传递到操作系统层面的?macOS 与 Linux 分别是如何在底层限制进程行为的?下一篇将深入沙箱底层:Codex-03-沙箱安全Seatbelt与Bubblewrap隔离。