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