第 2 篇 核心 · 第 6 章
整合 Git 與安全地讓它動手
Codex CLI 的安全機制,就是給你一個「能放手讓 AI 動手、又隨時能踩煞車、還能一鍵反悔」的雙保險。
想像你請了一位很能幹的助手到家裡幫忙。你會做兩件事:第一,先跟他講好「你只能進廚房,不准進臥室、不准出門」——這是活動範圍的圍欄;第二,跟他約定「動手丟東西之前,先問我一聲」——這是越界前要不要先報備。Codex 就是用這兩道各自獨立的關卡,決定它能多自由地幫你寫程式。
而 Git(版本控制,程式碼的「存檔系統」)則是你的第三道保險:就算 AI 真的改壞了什麼,你也能像遊戲讀檔一樣,一鍵回到改之前的樣子。
這一章你會學到:
- 怎麼用「能做什麼」和「要不要問我」兩個角度,看懂 Codex 的權限設計。
- 三個官方預設模式(唯讀 / 自動 / 完全放行),以及一鍵切換的旗標。
- 用
/diff、/review和 Git 存檔點,安全地收尾每一次改動。 - 什麼時候該放寬權限、哪一條紅線千萬別碰。
小提醒
這一章談的全部是終端機裡的 codex 指令。Codex 還有雲端版、IDE 外掛版,它們的權限機制長得不一樣,別把那邊的設定當成 CLI 指令來打。
6.1 為什麼要先懂「能做什麼」和「要不要問」兩軸
Codex 的安全設計,是由兩個各自獨立、但會搭配運作的控制軸組成的。官方原話是這樣說的(來自 Sandbox 概念頁):
"The sandbox defines technical boundaries. The approval policy decides when Codex must stop and ask before crossing them."
(沙箱定義技術邊界。核可政策決定 Codex 在跨越這些邊界之前,何時必須停下來問你。)
我們把這兩軸翻成白話:
| 控制軸 | 英文 | 一句話 | 比喻 |
|---|---|---|---|
| 沙箱 | Sandbox | 決定 AI 能碰什麼(哪些檔案、能不能上網) | 給助手畫的活動圍欄 |
| 核可 | Approval | 決定 AI 在越界前要不要先問你 | 越界前要不要先報備 |
Auto preset 不等於 Auto-review,也不等於 Goal mode
這裡的官方 Auto 只是在說 workspace-write + on-request 這組基礎權限,越界預設仍可能交給你核准。要讓獨立 reviewer 處理符合資格的越界,還得加 approvals_reviewer = "auto_review";要讓長任務知道「什麼證據出現才收工」,則另用 /goal。完整兩層工作流見第 7 章 7.6。
為什麼要分成兩軸?
因為「能做什麼」和「要不要問」是兩件不同的事,拆開來你才能精細調整。舉幾個組合你就懂了:
- 圍欄很小 + 越界一定問:最保守。AI 只能在工作資料夾裡動手,想多做一步都要先問你。
- 圍欄適中 + 該問才問:最常用。AI 能在你的專案裡讀檔、改檔、跑指令,但要改到專案外面、或想上網時,會停下來問你。
- 沒有圍欄 + 從不問:最危險。AI 想幹嘛就幹嘛,完全不問。只在隔離環境用(下一節會講)。
記住這句就夠
沙箱決定「能做什麼」,核可決定「做之前要不要問」。兩者組合起來,就是你給 Codex 的自由度。
一個關鍵觀念:兩軸是獨立的
很多新手會搞混:「我設成『從不問我』,是不是就等於沒有保護了?」
不是。 「從不問」(approval = never)只是 Codex 不暫停跟你確認,但沙箱的圍欄還在。除非你同時把沙箱也拆掉(改成完全放行),否則 AI 還是只能在圍欄內活動。
重要提醒
--ask-for-approval never 不等於「沒有沙箱」。沙箱邊界依然存在,除非你另外用了 danger-full-access 或 --yolo 把圍欄也一起拆掉。
一個具體例子:.git 資料夾摸不到
抽象的「圍欄還在」講起來有點空,換一個具體例子就懂了。在基礎 workspace-write(也就是 Auto preset)底下,工作目錄裡的 .git 資料夾是受保護的唯讀路徑——就連 .git 其實是指向別處的一個指標檔(常見於 worktree 或 submodule,內容通常只有一行 gitdir: ...)這種情況,Codex 解析出實際 Git 目錄後也會保護它。一般沙箱內指令不能直接寫入;像 git commit 這類動作若要跨過邊界,必須提出明確 escalation,再依 approval policy、reviewer 與組織 managed requirements 決定是否放行。技術核准也不等於使用者已授權 commit、強制推送或改寫歷史。
官方參考:Sandbox 概念頁、Agent 核可與安全
6.2 三大預設模式與一鍵旗標
懂了兩軸之後,好消息來了:你不必每次都自己拼湊兩軸的組合。 官方把最常用的組合打包成三個「預設模式」(preset),這是新手最該先記住的三檔。
來源:Agent 核可與安全頁。
| 預設模式 | 它能做什麼(官方說法) | 適合場景 | 新手建議 |
|---|---|---|---|
| Read Only(唯讀) | 可以讀檔、回答問題。要改檔、跑指令、上網都得先問你。 | 還沒搞清楚的陌生目錄、別人的程式碼 | 探索時用 ✅ |
| Auto(自動,預設) | 可以讀檔、改檔、在工作區內跑指令。要改到工作區外面或上網才會問你。 | 有版本控管(Git)的自己的專案 | 日常用這個 ✅ |
| Full Access(完全放行) | 沒有沙箱、不問核可(官方註明「不建議」)。 | 已經外部隔離的環境(專用 VM / 容器 / CI) | 新手別碰 ❌ |
怎麼一鍵切換?
每個預設模式背後,其實就是「沙箱旗標 + 核可旗標」的固定組合。你可以直接打對應的旗標:
Auto(預設,什麼旗標都不加就是這個):
codex
小技巧
想接受預設,直接跑 codex 就好,一個旗標都不用加。官方原話:「To accept the defaults, run codex.」
如果你想寫清楚一點(等同 Auto):
codex --sandbox workspace-write --ask-for-approval on-request "<你的需求>"
Read Only(唯讀,適合看陌生程式碼):
codex --sandbox read-only "<你的問題>"
Full Access(完全放行,危險):
codex --dangerously-bypass-approvals-and-sandbox "<你的需求>"
重要提醒
上面那條 --dangerously-bypass-approvals-and-sandbox(別名就是惡名昭彰的 --yolo)會同時拆掉檔案圍欄和上網限制。官方原話:「Only use inside an externally hardened environment.」(只在外部已加固的環境內使用。)新手請當作不存在。
認識兩個核心旗標
預設模式是包好的,但你遲早要直接認識那兩個旗標本人。
--sandbox(別名 -s):決定圍欄大小。 三個合法值:
| 值 | 白話 | 網路 |
|---|---|---|
read-only | 只能讀,要改要跑指令都得核可 | 不能上網 |
workspace-write | 工作區內可讀、可改、可跑指令 | 預設不能上網 |
danger-full-access | 完全不限制檔案和網路 | 開放 |
--ask-for-approval(別名 -a):決定什麼時候停下來問你。 合法值:
| 值 | 白話 | 適合 |
|---|---|---|
untrusted | 安全的唯讀動作自動做,會「改變狀態」的指令才問你 | 自動化與防呆之間平衡 |
on-request | 在沙箱內自動做,要越界才問你 | 互動使用的推薦值 |
never | 完全不暫停問你;仍需核准的越界直接失敗,也不會啟動 Auto-review | 封閉、fail-closed 的非互動 / CI |
舊教學陷阱
網路上很多舊文章會教你用 --ask-for-approval on-failure。這個值已經被官方棄用(deprecated)了。官方建議:互動使用改用 on-request、非互動使用改用 never。看到 on-failure 就知道那是過時資訊。
另一個棄用旗標
--full-auto 也已經被棄用了,用了會跳警告。官方建議改用明示的 --sandbox workspace-write。一樣,舊教學常見,別跟。你可能還會在更舊的部落格文章看到 suggest / auto-edit / full-auto 這種三段式模式的講法,那套命名已經整個被拆解掉,換成本章教的「沙箱+核可」兩個獨立旋鈕——看到這三個舊名字,直接在腦中翻譯成本章的兩軸即可。
session 進行中也能改
不必一開始就把權限定死。Codex 跑到一半,你可以在對話裡輸入斜線指令臨時調整:
/permissions
這會叫出互動選單,讓你當場切換沙箱 / 核可模式,即時生效。官方原話:「you can adjust permissions mid-session using the /permissions slash command.」
跟 /permissions 常搭配出現的,還有另一個斜線指令。如果剛剛有個動作被你(或啟用了 auto_review 的自動審查)擋下來,你看清楚後發現其實沒問題,不必重新描述一次需求,直接打:
/approve
/approve 會核准最近一次被拒的操作並重試,適合「手滑按錯」或「看仔細後發現其實沒問題」這種情境,不用整段對話重講一遍。
新手就用 Auto
真的不用想太多。直接跑 codex(就是 Auto 模式),遇到它要越界時它自己會問你,你看一眼覺得 OK 就放行。等熟了再研究怎麼放寬或收緊。
官方參考:Agent 核可與安全、CLI 指令參考
6.3 用 /diff、/review、Git 存檔點安全收尾
權限設好了,讓 AI 動手了——但你怎麼知道它到底改了什麼?改得對不對?萬一改壞了怎麼反悔?
這一節給你三件收尾的工具:看改動、找問題、能回滾。
第一步:開工前先存檔(Git checkpoint)
這是最重要、也最常被新手忽略的一步。Codex 會直接改你的檔案。 所以動手之前,先用 Git 存一個「乾淨的存檔點」,就像玩遊戲打王前先存檔。
為什麼一定要先存檔?
因為有了乾淨的存檔點,你之後看 AI 改了什麼會非常清楚(改動對照一目了然),而且只要一個指令就能整個還原。這是你最大的安全網。
開工前,在你的專案目錄裡跑(三平台指令相同):
# 看看現在有沒有還沒存的改動
git status
# 把目前狀態存成一個乾淨的存檔點
git add -A
git commit -m "存檔點:讓 Codex 動手之前"
還沒用過 Git?
別怕,先記住兩個動作就好:git add -A 是「把所有改動先放進待存清單」,git commit 是「真的存進去」。詳細的 Git 入門不在本書範圍,但光是「動手前 commit 一次」這個習慣,就能救你無數次。
第二步:讓它動手,過程中用 /diff 隨時看改了什麼
Codex 改檔的過程中(或改完後),你可以在對話裡輸入:
/diff
/diff 會把這次的改動列出來,新增的行、刪掉的行一清二楚——而且連 Git 還沒開始追蹤的新檔案也一併顯示(官方說法:「Show the Git diff, including files Git isn't tracking yet」)。你不用自己去翻每個檔案,一個指令就看完它做了什麼。
第三步:用 /review 請它自我審查
光看改動還不夠,你可能看不出藏在裡面的 bug。這時可以叫 Codex 自己審查自己剛寫的程式碼:
/review
/review 會請 Codex 檢視你目前工作目錄裡的改動(官方說法:「Ask Codex to review your working tree」),幫你找邏輯錯誤、沒處理到的邊界情況、可能的風險,並給修正建議。
這就像找第二個人複查
一個人寫、同一個人馬上檢查,難免有盲點。/review 等於讓 AI 換個角度,專門挑自己剛才寫的東西的毛病。
/review 除了審查目前工作目錄的改動,也能挑一個 base branch 來比對——原理是先找出你的分支跟那個 base branch 的共同祖先(merge base),再拿這個共同祖先去對 diff,這樣才只看到你自己這條分支上的改動,不會把上游其他人這段時間的變更也混進來一起被檢討。/review 完整的互動選項、以及跟雲端 @codex review 的對照,第 11 章會整套講。
看到重複或對不上號的發現,先懷疑 diff 範圍
社群回報過(issue #8404)比對 base branch 時,抓 diff 範圍的邏輯偶爾會出錯,把你還沒 commit 的工作樹改動、甚至一些舊的、不相干的發現也混進報告——看起來像同一個問題被講了好幾遍,或冒出跟這次改動對不上號的建議。遇到這種狀況,先別照單全收,改選審查未提交的改動、或審查特定 commit 這類範圍更明確的選項,縮小審查範圍通常就能讓報告乾淨很多。⚠️ 以你實機版本的行為為準,這類細節修得快。
第四步:不滿意?用 Git 一鍵反悔
假設你看完 /diff、跑完 /review,覺得這次 AI 改得不好,想整個丟掉重來。因為你開工前存過檔,現在就能輕鬆還原(三平台相同):
# 丟掉所有還沒 commit 的改動,回到上一個存檔點
git restore .
# 如果連已經暫存(git add)的也要丟掉
git restore --staged .
git restore .
重要提醒
git restore . 會永久丟掉你還沒 commit 的改動,沒得反悔。執行前確認你真的不要這些改動了。這也是為什麼「開工前先 commit」這麼重要——你才有一個明確的、安全的點可以退回去。
如果你滿意 AI 的改動,想把它變成正式的存檔:
git add -A
git commit -m "完成:<這次做了什麼>"
養成節奏
「存檔 → 讓它動手 → /diff 看 → /review 查 → 滿意就 commit、不滿意就 restore」。把這個循環變成肌肉記憶,你就能放心讓 AI 大膽幫你寫程式,因為你永遠有退路。
進階:git push 在沙箱裡容易踩到的坑
前面四步(存檔、/diff、/review、還原)都只碰本機檔案,沙箱不太會找麻煩。但只要牽扯到 git push——需要真的連出去網路——就會跟沙箱的網路限制正面相撞,冒出來的錯誤訊息常常讓人摸不著頭緒。這裡整理幾種實際會遇到的狀況,讓你少走冤枉路。
狀況一:明明開了網路,SSH 方式的 push 還是失敗。 沙箱擋的其實是更底層的「原始 socket 操作」,DNS 查詢、SSH agent 溝通都要用到這一層。所以用 SSH 協定 push 時,就算已經開了 network_access,還是常見這類錯誤:
ssh: Could not resolve hostname github.com: Temporary failure in name resolution
Error connecting to agent: Operation not permitted
這不是 bug,是設計上的落差:network_access 開的是 HTTP/HTTPS 這條路,不代表 SSH 那條路也一起通。
🍎 macOS 使用者另外注意
社群回報過(issue #13373)在 macOS 上,config.toml 裡寫 network_access = true 有機會被 Seatbelt 沙箱靜默忽略——設定明明寫對了,卻還是連不出去,這跟 Linux/Windows 的行為不一致,容易誤判成自己打錯字。
狀況二:push 好像成功了,又好像沒成功。 在 workspace-write 搭配 network_access = true 的組合下,git push 有機會把改動真的推上了遠端,卻在更新本機 .git/refs/remotes/origin/* 這個追蹤 ref 時失敗噴錯(issue #21869)。結果是遠端其實已經更新,本機看起來卻像沒推成功。遇到這種狀況先別急著重推——上 GitHub/GitLab 的網頁確認遠端是否已經收到,避免重複推送製造出不必要的衝突。
狀況三:🪟 Windows 原生沙箱下,同一句指令行為不一致。 一模一樣的 git 指令,在一般 PowerShell 視窗裡跑得好好的,放進 Codex 的 Windows 原生沙箱卻可能走 HTTPS 協定時失敗甚至直接崩潰,這是已知的平台限定議題。Windows 使用者不能完全照搬 macOS/Linux 的排錯邏輯,遇到怪異行為先假設是這一層的落差。
老手常見習慣:commit 交給沙箱,push 自己按
正因為上面這幾種狀況都跟版本、平台有關,不容易一次講死,很多熟手的作法是:讓 Codex 在沙箱裡把 add/commit 做完,/diff、/review 都看過確認沒問題,但最後 git push 這一下自己回到終端機手動按。理由很單純:push 是「東西真的送出去給別人看見」的動作,牽涉到網路沙箱一堆版本間會變的邊界案例,與其每次都賭這次行不行,不如把「送出去」的最後一步留給自己,確定性最高。
時效提醒
以上幾種狀況部分來自社群回報的 issue,不是官方文件白紙黑字保證的行為,會隨版本變動。遇到 push 異常,先用 /diff、git status 確認本機狀態,再上遠端網頁核對是否已經收到,比死記這幾條症狀更可靠。以實機行為與最新 issue 狀態為準。
進階:用 Git worktree 同時跑好幾條任務
如果你想同時讓 Codex 處理好幾件不相干的事,又不想讓它們互相干擾,官方建議用 Git worktree。
簡單說,worktree 讓同一個 repo 可以同時 checkout 出好幾個獨立的工作資料夾,各自一個分支、各自一個 Codex session,彼此不打架。
# 開一個叫 feature-x 的獨立工作資料夾 + 新分支
git worktree add ../feature-x -b feature-x
# 進去那個資料夾,單獨跑一個 Codex
codex --cd ../feature-x
重要提醒
worktree 並行有個前提——每個 session 的工作範圍要清楚分開。官方警告:如果範圍重疊,並行的 agent 會產生「互相打架的改動」而不是互補。所以一個 worktree 配一件明確的任務,別讓兩條任務碰同一批檔案。worktree 的深入用法會在後面的進階篇再談。
另一層地雷:session 之間可能互相汙染
跟上面「範圍重疊會打架」是不同層次的問題:社群回報過,多個 Codex CLI 實例共用同一個 ~/.codex/ 存對話紀錄的資料夾,如果同時開好幾個平行 session(即使各自站在不同的 worktree 資料夾裡),有機會讀到彼此的對話上下文,讓執行結果被搞混。這是 session 管理層的議題,跟 worktree 本身無關——就算把檔案系統隔離得再乾淨,也不保證平行開好幾個視窗時彼此互不影響。保守作法:同時開的 session 數別太多,執行結果看起來怪怪的,先懷疑是不是平行開太多,關掉重開看看。
實務上的分支規矩
要平行跑好幾條任務,訂一套簡單的命名慣例會省很多事:feat/<描述>、fix/<描述>、chore/<描述>,一眼就看得出這條分支在做什麼。也建議明訂規矩——Codex 產出的分支永遠不直接推 main,一律走 PR,讓每一次改動都有人(包括你自己)過一遍再合併。經驗法則是平行開到 3~4 個 session 為上限,再往上開,「審查跟合併」會變成新的瓶頸,多開也沒用。
官方參考:最佳實踐、Slash 指令清單
6.4 放寬權限的時機與紅線
你已經知道怎麼用預設模式,也知道怎麼收尾。最後這一節談「什麼時候該放寬、放寬到哪裡為止」,以及幾條新手最容易踩的雷。
官方的放寬原則:從緊開始,慢慢放
官方在最佳實踐頁給的建議很明確:
- 新手從預設權限開始(也就是 Auto 模式)。
- 預設收緊核可與沙箱。
- 只有在「清楚的工作流需求浮現」之後,才針對你信任的 repo 放寬。
- 不要過早給 full access。
換句話說:別一開始就把保護全拆了圖方便。先用 Auto,真的遇到「它一直卡在要核可某個安全動作、很煩」時,再針對那個情境放寬一點點。
紅線一:要寫更多目錄,優先用 --add-dir,別升級成完全放行
常見情境:Codex 預設只能寫工作區(你跑 codex 的那個資料夾),但你這次需要它也能改另一個資料夾。
❌ 錯誤做法: 嫌麻煩,直接改成 --sandbox danger-full-access(完全放行)。這等於為了多開一扇門,把整棟房子的牆全拆了。
✅ 正確做法: 用 --add-dir 精準地只多授權那一個目錄:
# 在原本的工作區之外,額外授權寫入 ../shared-lib 這個目錄
codex --add-dir ../shared-lib "<你的需求>"
官方原話:--add-dir 是「Grant additional directories write access alongside the main workspace」(在主工作區之外,額外授予指定目錄寫入權)。需要的話可以重複用 --add-dir 加好幾個。
記住這個取捨
要多一個可寫目錄,用 --add-dir 加那一個就好。不要為了這點需求,就把沙箱整個升級成 danger-full-access。多開一扇窗,不必拆掉整面牆。
紅線二:workspace-write 預設不能上網,別期待它直接裝套件
這是新手最常見的困惑:「我叫 Codex 幫我 npm install,它怎麼裝不起來?」
因為在 workspace-write(也就是 Auto 模式)底下,網路預設是關閉的。Codex 可以改你本機的檔案,但碰不到網路,所以任何要連外下載的動作(裝套件、抓資料、call API)都會失敗。
重要提醒
Auto 模式下 Codex 連不了網。別以為它能直接 pip install、npm install 或抓網路資源。這是刻意的安全設計,不是 bug。
如果你確實需要讓它上網,要在設定檔裡明確開啟。在 ~/.codex/config.toml 加上:
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = true # 預設是 false,改成 true 才放行網路
重要提醒
開放網路 = 讓 AI 能連外。確定你信任這個專案、也清楚它可能去連哪些地方,再開。開了之後它就能下載任何東西,風險自負。
紅線三:--yolo / 完全放行,只在隔離環境用
把前面的話再講白一點。--dangerously-bypass-approvals-and-sandbox(別名 --yolo)= 完全放行 = 同時拆掉檔案圍欄和網路圍欄,而且從不問你。
它的合法使用場景只有一種:你跑在一個「就算被搞爛也無所謂」的外部隔離環境裡——專用的測試 VM、Docker 容器、或 CI 的拋棄式 runner。
重要提醒
絕對不要在你自己的主力電腦、或放著重要資料的環境裡跑 --yolo。它把所有保護都拆了,AI 的任何指令都會直接執行,不問、不擋。官方原話就一句:「Only use inside an externally hardened environment.」(只在外部已加固的環境內使用。)
別以為開了 --yolo 就一定「什麼都不問」
社群回報過(issue #14345)某個版本起,--yolo 不再連第 1 章提過的那個「信任這個資料夾嗎?」提示都一起跳過——就算下了旁路旗標,第一次進新目錄照樣可能被攔下來問;在唯讀掛載設定檔的容器環境裡,這個信任選擇甚至存不下來,每次都要重答。這屬於版本間會變動的行為,開了旁路旗標不保證信任詢問一定消失。如果不想每次都被問,官方也提供 projects.<路徑>.trust_level 這個設定鍵,可以把特定專案標成 trusted。⚠️ 實機行為以你的版本為準。
紅線四:.gitignore 擋不住的東西,以及 pre-commit hook 可能被繞過
這條紅線比較隱性,容易被忽略——因為它牽涉到兩個你以為「本來就有在保護」、實際上保護力沒你想的那麼完整的機制。
.gitignore 只對「還沒被 git 追蹤過」的檔案有效。 如果 .env 這類敏感檔案曾經被 commit 過,事後才補進 .gitignore,並不會把它從 Git 歷史裡清掉——舊的 commit 裡還是躺著那份明文,要真正清除得重寫歷史。另外,agent 讀你電腦上的檔案系統時,本來就不一定尊重 .gitignore 規則——那是寫給 git 用的規則,不是寫給檔案總管用的——Codex 掃描專案時有機會直接讀到 .gitignore 裡列的檔案,甚至把內容送進推論流程。真的要保護敏感檔案,光靠 .gitignore 不夠,得搭配6.5會講的 filesystem deny 規則明確擋住讀取。
Codex 在 shell 層跑 git commit 時,理論上能自己加 --no-verify 繞過 pre-commit/commit-msg hook。 如果你的團隊靠這類 hook 把關程式碼品質(跑 lint、跑測試),要知道這層防護對「AI 自己在 shell 裡下的指令」不是絕對牢靠——這裡說的是你專案裡 .git/hooks/(或 husky 之類工具管理)的 Git hook,跟第 14 章會教的、Codex 自己那套用來管控 Codex 行為的 PreToolUse hook 是兩回事,別搞混。
實務上怎麼防
三個方向搭配比較踏實:敏感檔案從一開始就別讓它進 git(.gitignore 要加在第一次 commit 之前);已經進過歷史的金鑰視同外洩,直接輪替換一把新的,而不是只補 .gitignore 了事;真的在意品質關卡被繞過,把 lint/test 這類檢查也放進 CI(不倚賴本機 hook 一定會被觸發),CI 端不受 Codex 本機沙箱影響,是更可靠的最後一關。
把常用設定寫進 config.toml,不用每次打旗標
如果你每次都要同一組設定,與其每次打一長串旗標,不如寫進設定檔(~/.codex/config.toml)。例如一個安全的本機自動化設定:
# 等同每次都打 --sandbox workspace-write --ask-for-approval on-request
approval_policy = "on-request"
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = false # 預設就是 false,寫出來只是更清楚
小技巧
config.toml 的完整用法、不同情境的設定組合包(profile)、各層設定的優先順序,我們會在第 8 章好好講。這裡你先知道「常用權限可以寫進設定檔、不用每次打旗標」就夠了。
新版重要校正
上面這個 sandbox_mode + [sandbox_workspace_write] 寫法仍然可用,但官方已經推出更新、更強的 [permissions] 命名 profile 系統(用 default_permissions + [permissions.<名字>] 來定義權限)。兩套系統不能在同一個 session 裡混用——官方原話:「Use one system or the other for a session, not both.」(一個 session 只用其中一套,別兩套都設。)新手照本節的 sandbox_mode 寫法即可;想用更精細的 profile 模型(可以「能寫程式碼但連 .env 都不准讀」),看本章 6.5 高手進階,完整玩法在第 15 章。⚠️ 以實機 codex --help 與官方頁為準。
時效提醒
上面提到的旗標(--sandbox / --ask-for-approval / --add-dir / --yolo)和設定鍵,都依本書對照的 Codex CLI 版本(0.140.0,2026-06-15)。Codex 更新很快,旗標和值偶爾會變。任何時候以實機 codex --help 與官方頁面為準。
6.5 🎓 高手進階
到這裡你已經會用三大預設模式、/diff、/review 和 Git 安全網了——日常用這些完全夠。這一節是進階入口:給已經上手、想把安全機制玩到企業級的你,先看「紅線與校正」,深度主體(完整 config 配方、逐鍵解說、企業強制設定)會在第 15 章展開。沒興趣的可以直接跳到本章小結,不影響日常使用。
進階入口:[permissions] profile 模型(取代舊 sandbox_mode 的主軸)
前面 6.4 那個 sandbox_mode 的寫法,官方現在有了更強的替代品:[permissions] 命名 profile。它能做到舊寫法做不到的細活,例如「可以改原始碼,但連專案裡的 .env 金鑰檔都不准讀」。
來源:Permissions 官方頁。三個內建 profile:
| Profile | 官方語意 |
|---|---|
:read-only | 本機指令保持唯讀 |
:workspace | 允許寫入「目前 workspace 根目錄」與「系統暫存目錄」 |
:danger-full-access | 移除本機沙箱限制,只在「確實需要這種大範圍存取」時才用 |
自訂 profile 用 extends 繼承:
default_permissions = "project-edit" # 選定起始 profile
[permissions.project-edit]
description = "Project editing with OpenAI API access."
extends = ":workspace" # 可繼承 :read-only / :workspace / 另一個具名 profile
互斥鐵律(最重要)
一個 session 裡,[permissions] / default_permissions 與舊的 sandbox_mode / [sandbox_workspace_write] 只能擇一,不可混用。官方原話:「Use one system or the other for a session, not both.」另外,extends 不能繼承 :danger-full-access(官方會直接拒絕)。⚠️ 以實機 codex --help 與官方頁為準。
filesystem:deny > write > read,用 glob deny 鎖住 .env
profile 裡的檔案權限有三個等級,優先序是愈具體愈優先,且 deny 勝 write、write 勝 read(官方逐字):
| 值 | 行為 |
|---|---|
read | 可讀檔、可列目錄 |
write | 可讀、可改(含新建 / 改名 / 刪除) |
deny | 讀寫全擋 |
這帶出一個高手最愛的配方——可寫原始碼,但連 .env 都讀不到:
[permissions.project-edit.filesystem.":workspace_roots"]
"." = "write"
"**/*.env" = "deny" # deny 勝 write,即使整個 workspace 可寫,.env 仍被擋讀
Linux 校正
在 Linux / WSL / Windows 上,無界的 ** glob 需要「有界預展開」,否則可能不生效——要加 glob_scan_max_depth(官方:至少 1):
[permissions.project-edit.filesystem]
glob_scan_max_depth = 3
而且官方提醒:deny 的 glob 較可靠;read / write 的 glob「跨平台較不可靠(less portable)」。⚠️ 以實機行為為準。
預設已幫你擋一批金鑰
官方在 read-only / workspace-write 下,預設就加了一批「禁讀」規則保護常見金鑰檔(.env、SSH 私鑰、.aws/credentials 等)。但完整清單官方文件尚未逐字列全,所以最穩的做法是自己明設 **/*.env = "deny" 等規則,別假設預設一定涵蓋你的檔案。⚠️ 完整預設清單以實機 codex 行為為準。
網路:proxy 白名單 + DNS rebinding 防護
workspace-write(Auto 模式)預設不能上網(這你在 6.4 學過了)。進階玩法不是「整段打開」,而是只放行特定網域——用 Codex 自帶的「沙箱網路代理(network proxy)」設白名單:
[permissions.net-allowlist.network]
enabled = true
[permissions.net-allowlist.network.domains]
"registry.npmjs.org" = "allow"
"*.npmjs.org" = "allow" # 只放行 subdomain(不含 apex)
"github.com" = "allow"
"ads.example.com" = "deny" # deny 勝出
# 未列的網域一律不放行
網域萬用字元語意(官方逐字):example.com=只該主機;*.example.com=只 subdomain;**.example.com=apex 加所有 subdomain;*=全域萬用,只能用於 allow,不能用於 deny。
DNS rebinding 防護(冷門但重要)
Codex 預設套用「本機/私網守衛」防 DNS rebinding 攻擊——DNS 查不到 / 逾時的主機一律 block,解析到私有 IP 的主機也 block。所以要放行 localhost / 127.0.0.1 這類本機服務,必須顯式列出並開 allow_local_binding = true,否則會被擋。⚠️ 以官方頁為準。
已知 bug,自動化前必實測
社群回報(issue #16242,狀態查核日 2026-06-18 仍 open)proxy 白名單在 codex sandbox 會正確擋(回 403),但在 codex exec 與互動模式可能直接放行(白名單沒生效)。所以寫自動化前,務必在當前版本拿一個「非白名單網域」實際 curl 一次,確認真的有擋到。⚠️ 以實機驗證為準。
核可:granular 五子鍵 + auto_review
--ask-for-approval 除了 6.2 教的三個值(untrusted / on-request / never),進階還能給一個 granular 物件,逐項獨立決定「何時停下來問你」:
approval_policy = { granular = { sandbox_approval = true, rules = true, mcp_elicitations = true, request_permissions = false, skill_approval = false } }
五個布林子鍵:sandbox_approval / rules / mcp_elicitations / request_permissions / skill_approval。
另外有個搭配技巧——誰來審:
approvals_reviewer = "user" # 預設;或設 "auto_review"
半自動 pipeline 配方
approval_policy 決定「何時停」,approvals_reviewer = "auto_review" 決定「停下後交給一個獨立 reviewer 自動判斷」。兩者搭配可在半自動流程裡降低人工中斷,又保留審查紀錄;但核准一次技術越界不代表使用者已授權 push、部署或其他外部副作用。安全 launcher+/goal 的完整實戰見第 7 章 7.6。⚠️ 以官方頁為準。
Linux 沙箱校正:bubblewrap + seccomp(Landlock 已退為 legacy)
很多舊教學會說「Codex 在 Linux 用 Landlock 做沙箱」——這個說法已經過時了。
依官方 Linux sandbox README:
- Linux / WSL 現在預設 =
bubblewrap(bwrap)+seccomp(mount namespace +PR_SET_NO_NEW_PRIVS+ seccomp 網路過濾)。 - Landlock 已退居「顯式 legacy fallback」:要
features.use_legacy_landlock = true(或-c use_legacy_landlock=true)才會走它。 - macOS 則是用 Seatbelt(
sandbox-exec -p <profile>),不支援的政策會直接被拒,不會默默放行。
Linux 使用者注意
因為預設要靠 bubblewrap,機器上得先裝好 bwrap。若在容器內,且 namespace / setuid bwrap / seccomp 被環境封掉,沙箱可能失效。看到舊文寫「Linux 用 Landlock」就知道那是過時資訊。⚠️ 以實機與官方 README 為準。
實戰排錯:Ubuntu 23.10 以上,bubblewrap 常常建不了 namespace
這是實機最容易踩到的一個具體症狀。Ubuntu 23.10 起,系統預設把 kernel.apparmor_restrict_unprivileged_userns 打開,會擋掉 bubblewrap 建立 user namespace 這個動作。如果你懷疑是這個原因,可以直接手動測一次:
# 症狀重現
bwrap --dev-bind / / --unshare-net echo ok
# bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted
看到這行 Operation not permitted,不用整台機器關掉 AppArmor 限制,只要新增一個檔案 /etc/apparmor.d/bwrap,內容如下:
abi <abi/4.0>,
include <tunables/global>
profile bwrap /usr/bin/bwrap flags=(unconfined) {
userns,
include if exists <local/bwrap>
}
存檔後載入這個 profile,再重跑一次剛剛的測試指令確認修好了:
sudo apparmor_parser -r /etc/apparmor.d/bwrap
# 驗證:看到 ok 就是修好了
bwrap --dev-bind / / --unshare-net echo ok
如果修完這個還是不行,錯誤訊息變成 bwrap: Creating new namespace failed: Operation not permitted,通常代表你跑的環境(某些 NAS、容器化 CI runner)在核心層級就完全不給建立 user namespace——這是不同層的限制,AppArmor profile 對這種狀況沒用。這時候改用前面提過的 legacy Landlock 路徑繞過(features.use_legacy_landlock = true,或指令列 -c use_legacy_landlock=true),或乾脆放棄在容器內跑沙箱、改在外層限制存取範圍。
⚠️ 上面的指令與設定鍵,以你實機的 Codex 版本與 Ubuntu 版本行為為準,AppArmor profile 語法也可能隨 AppArmor 版本略有差異。
紅線複習:--add-dir 優先於 full-access
6.4 講過的紅線,進階版再強調一次決策順序——要寫更多目錄,層層加碼,別一步跳到全放行:
- 只多一個可寫目錄 →
--add-dir(或 config 的writable_roots)。 - 多個目錄、想各自定讀寫等級 → 自訂
[permissions.<名字>.filesystem]細粒度 map(同一目錄樹可混read/write/deny,比writable_roots更精細)。 - 需要連網 → 開
network_access或上面的網域白名單,不要為了連網而升danger-full-access。 - 真的要全放 → 只在外部已加固環境(VM / 容器 / CI),且優先用「
danger-full-access+ 集中 deny 名單」而非裸--yolo。
企業守閘預告
管理員可以用 requirements.toml 把這些安全設定鎖死(例如禁止使用者選 danger-full-access、強制網域白名單)。這屬企業部署主題,完整玩法第 15 章再談。注意 allowed_permission_profiles 這個強制鍵需要 Codex ≥ 0.138.0,舊版會靜默忽略。⚠️ 以官方 managed-configuration 頁為準。
本章小結
這一章你學會了安全地放手讓 Codex 動手:用沙箱(能做什麼) 和 核可(要不要問你) 兩軸理解權限;記住三個預設模式(唯讀 / 自動 / 完全放行),日常用 Auto 就好;開工前先用 Git 存檔點當安全網,過程中用 /diff 看改動、/review 找問題,不滿意就 git restore 一鍵反悔;放寬權限要從緊開始慢慢放,要多寫一個目錄用 --add-dir 而不是拆掉整個沙箱,也記住 Auto 模式預設不能上網、--yolo 只在隔離環境用。
動手試試
- 在一個你不熟悉的別人的專案裡,跑
codex --sandbox read-only "這個專案大概在做什麼?",體驗一下「只能讀、不能改」的唯讀模式。 - 在你自己的專案裡,先
git commit存一個乾淨點,再用 Auto 模式(直接codex)請它做一個小改動,改完輸入/diff看它改了什麼,再/review請它自我審查。 - (練反悔)接續上一題,如果你不滿意改動,跑
git restore .把它整個還原,確認檔案真的回到改之前的樣子——這就是你的安全網在運作。
本章官方文件參考
- Sandbox 概念:https://developers.openai.com/codex/concepts/sandboxing
- Agent 核可與安全:https://developers.openai.com/codex/agent-approvals-security
- CLI 指令參考(旗標):https://developers.openai.com/codex/cli/reference
- 設定參考(config 鍵):https://developers.openai.com/codex/config-reference
- 最佳實踐(放寬原則、worktree):https://developers.openai.com/codex/learn/best-practices
- Permissions(進階 profile / filesystem / network 模型):https://developers.openai.com/codex/permissions
- 企業 Managed configuration(requirements.toml):https://developers.openai.com/codex/enterprise/managed-configuration
- Linux sandbox README(bubblewrap+seccomp):https://github.com/openai/codex/blob/main/codex-rs/linux-sandbox/README.md