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,策略層還在。