審批策略:同一條命令,問不問看哪兩顆旋鈕
預設問不問跟沙箱種類綁在一起。問過一次之後,記住的是完整命令,還是一段前綴。
- 讀當前 turn 的 AskForApprovalprotocol.rs L924
- 看 FileSystemSandboxKind 是不是 Restrictedpermissions.rs L227
- Never 給 Skip,UnlessTrusted 給 NeedsApprovalsandboxing.rs L198
- OnRequest 或 Granular 只在 Restricted 時要問sandboxing.rs L200
- Granular 要問且關掉沙箱審批則 Forbiddensandboxing.rs L209
- execpolicy 的 Prompt 再過第二道閘exec_policy.rs L214
- 會話快取只收 ApprovedForSession,認精確 keysandboxing.rs L108
- 策略改了,給模型的說明書一起改permissions_instructions.rs L271
你把審批留在 on-request,沙箱從 workspace-write 擰到 danger-full-access。十分鐘前那條出沙箱命令還會彈窗。現在不彈了。你沒改審批旋鈕。
審批策略 AskForApproval 是當前 turn 用哪套問人規則,型別裡有四個變體。檔案系統沙箱種類是三個,預設 Restricted,意思是只讀或只能寫工作區。這兩顆旋鈕在同一個判定函式裡。改其中一顆,另一顆的行為會跟著走。出處:codex-rs/protocol/src/protocol.rs 第 924 至 947 行,以及 codex-rs/protocol/src/permissions.rs 第 227 至 232 行
一條命令先讀審批策略,再看檔案系統是不是 Restricted,再讓 execpolicy 把 Allow、Prompt、Forbidden 疊上去。execpolicy 是按命令文字給出三態的規則檔案。
預設問不問寫在 default_exec_approval_requirement。Never 這一層給 Skip。UnlessTrusted 這一層給 NeedsApproval。OnRequest 和 Granular 只在 Restricted 時要問。read-only 和 workspace-write 都是 Restricted,所以這兩格的預設結局一樣。danger-full-access 把 kind 變成 Unrestricted,預設函式走 Skip。出處:codex-rs/core/src/tools/sandboxing.rs 第 198 至 230 行
Granular 還多一個閘。需要審批、且 sandbox_approval 關掉時,直接 Forbidden。檔案系統如果已經是 Unrestricted,needs_approval 先變成假,Forbidden 分支進不去。關掉沙箱審批,只擋住本來就要彈的窗。
Never 遇到 execpolicy 的 Prompt,提問會升級成拒絕。它並不表示什麼都準跑。出處:codex-rs/core/src/exec_policy.rs 第 214 至 236 行
untrusted 寫不進配置。型別還在,公開字串已經退休。使用者顯式寫出,整次載入失敗。沒寫才看專案信任:已信任走 OnRequest,明確未信任走 UnlessTrusted。出處:codex-rs/core/src/config/mod.rs 第 3607 至 3625 行
還有一個載入期硬拒絕。requirements 不允許 danger-full-access,配置卻寫了 approval_policy = "never",載入器會先把權限檔案回落到只讀。只讀加上從不提問,等於模型在窄沙箱裡還沒人可問。這種組合直接判非法。出處:codex-rs/core/src/config/mod.rs 第 3969 至 3979 行
全盤可寫時,再問一次出沙箱沒有意義。兩顆旋鈕綁在一起,少彈窗。代價是改沙箱會靜默帶走審批行為。換個語言重寫,仍要先回答:全權模式還要不要問人。
策略列舉靠窮盡分支表達規則。新加一個變體,編譯器會逼所有判定函式表態。這是型別在替執行時守門。
彈窗上兩條記住長得很像。一條是本會話記住這條命令。一條是把前綴寫進 execpolicy,跨會話生效。點錯了,後面的邊界題就會答反。
常規 exec 彈窗預設選單裡,甚至沒有 ApprovedForSession。有網路上下文時才帶上它。普通命令給一次批准,有前綴修正提案時再加按前綴記住,最後是取消。使用者最常碰到的記住,是前綴那一條。出處:codex-rs/protocol/src/approvals.rs 第 314 至 347 行
會話快取活在 ApprovalStore 裡,跟會話同壽命。key 是規範化後的完整命令,外加 cwd、環境和 execpolicy 指紋。所有 key 都已經是 ApprovedForSession 才命中。Approved 一次放行不會進 map。出處:codex-rs/core/src/tools/sandboxing.rs 第 64 至 116 行
npm run test 批准進會話,npm run lint 是另一把 key。/bin/bash -lc 和 bash -lc 在能拆出單一明文命令時,快取成同一組 token。會話快取認完整命令,不認 npm *。前綴擴張只走 execpolicy。
改審批策略不會清空這座 map。key 裡沒有 AskForApproval。中途從 OnRequest 改成 UnlessTrusted,已經快取的批准仍算數。改 execpolicy 會改指紋,快取才會失效。
兩套記住對應兩種威脅。精確 key 擋不住換參數。前綴擋得住換參數,也容易把包裝命令的範圍擴太大。兩層分開,才能各自配禁建議名單。一天彈窗不多的時候,先只做一次放行也成立。
策略改了,只改執行時分支不夠。模型看到的說明必須同步改,否則它會按舊規則去要 require_escalated。Never 下面如果說明書還在教它提權,執行時會把提問升級成拒絕,模型只會反覆撞牆。
權限說明是一段 developer 訊息。先選沙箱模板,再選審批模板。Never、UnlessTrusted、OnRequest 各有現成 markdown。Never 那份只有一句:不要再給 sandbox_permissions,命令會被拒。Granular 沒有第五份檔案,按五個開關現場拼允許列表和拒絕列表。兩套說明拼在同一段裡,模型一次看到當前組合。出處:codex-rs/prompts/src/permissions_instructions.rs 第 271 至 291 行
鉤子在人前面。鉤子給出 Allow 或 Deny,彈窗就不會出現。鉤子的 Allow 是一次 Approved,不寫會話快取。
執行時和模型說明書是同一份合同的兩面。判定函式改了,字典那一行必須一起改。把這兩份放在同一個模組,用同一組測試喂兩邊,換語言也用得上。
DSH:兩顆旋鈕,一次授權不擴大
DSH 的審批策略只有 ask 和 never。never 在分派給回答者之前就返回 rejected,後掛的監聽器改不了這個承諾。授權結果只有 allowed-once。沒有本會話快取,沒有前綴修正。問過一次,下一次還問。出處:packages/interaction/user-approval/src/index.ts 第 84 至 94 行,以及第 304 至 312 行
沙箱和審批是兩顆獨立旋鈕。使用者看見的下拉框是預設表:workspace-write 綁 ask,danger-full-access 綁 never。點下一檔時分別呼叫兩顆 setter。對不上表就顯示 custom。所以 DSH 可以單獨把審批留在 ask、把沙箱擰到全盤可寫。Codex 的 OnRequest 在 Unrestricted 上預設 Skip,這個組合在預設函式裡不可獨立存在。出處:packages/interaction/permission-presets/src/index.ts 第 167 至 176 行
Claude Code:記住寫進規則表
Claude Code 對外的權限模式是五檔,外加內部的 auto 和 bubble。規則來源包括 userSettings、projectSettings、session、cliArg。判定先查整工具級 deny,再往下走。出處:restored-src/src/types/permissions.ts 第 16 至 29 行,以及 restored-src/src/utils/permissions/permissions.ts 第 1169 至 1181 行
alwaysAllowRules 可以按來源記下允許項,session 是其中一檔。下次按規則匹配,不必完整 argv 相等。代價是匹配函式必須自己防包裝。Codex 把擴大範圍交給 execpolicy 前綴和禁建議名單。dontAsk 接近 Never。Codex 沒有公開的全放行審批策略,Never 仍會被 execpolicy 攔住。出處:restored-src/src/types/permissions.ts 第 54 至 62 行,以及第 433 行
擰沙箱,彈窗還在嗎
審批留在 on-request,沙箱從 workspace-write 擰到 danger-full-access。再跑一條會寫工作區外路徑的命令。彈窗還在不在?為什麼?
接著把同一條 npm run test 按會話批准,再提交 npm run lint。快取該不該命中?如果點的是按前綴記住,答案會不會變?