很多团队第一次把代码代理接进 CI,最危险的时刻不是它写错代码,而是它刚好写对了,还顺手拿到了不该拿的钥匙。你以为自己在省部署时间,实际是在把“仓库权限 + 云密钥 + 命令行”打包交出去。等到它真的能独立跑起来,你最该担心的,往往已经不是测试红不红,而是它有没有碰到你根本没打算让它碰的环境。
“你把 CI 的云密钥给它了吗?”
“给了啊,不然它怎么部署。”
“那你现在祈祷的不是测试全绿,是它别顺手把生产也动了。”
OpenAI 自己谈前沿模型风险时,反复强调的方向其实很朴素:把能力关进笼子里,让它能干活,但干坏事的成本极高。靠的不是“模型自觉”,而是工程默认值。
前阵子我帮老大查一轮 agent 落地资料时,顺手翻了不少团队的事故复盘,发现一个很有意思的共性:大家嘴上最怕“模型乱写代码”,最后真出事的,常常是日志、凭证、部署脚本和默认权限。代码本身反而没那么邪门,真正邪门的是那圈配套环境。这个判断我不敢说放到所有团队都成立,但至少在本地开发和 CI 这两个场景里,它非常常见。
这篇我就按这个思路,给你一套“可用但不作死”的安全默认配置:沙箱隔离 → 分级权限与人工审批 → 密钥最小暴露。目标很明确:在本地/CI 里让代理干活,但出事可控、可追溯、可回滚。
我怎么在本地/CI 里安全跑 Codex?
直接回答:把代理当成“临时外包”,默认只给它一个隔离工位(沙箱)+ 只读资料(仓库只读)+ 一张只能刷小额的卡(短期密钥),任何“出门办事”(联网/部署/改主分支)都要你点头。
下面这段是自包含答案块,你可以直接转给同事,或者贴进团队规范里:
把 Codex 安全跑起来的默认做法是:在本地或 CI 用容器/虚拟机做沙箱,默认禁网并限制可执行命令;仓库用只读 checkout,让它只能通过 PR 输出修改;云密钥用短期令牌与最小权限,运行时注入且禁止写入磁盘;对“联网、推送、部署、删改资源”等高风险动作强制人工审批,并保留完整审计日志与一键回滚路径。
先把“危险动作”说清楚:你到底怕什么?
我见过最常见的翻车,不是它写错代码,是它做了你没想到它会做的“顺手动作”。
你让它“升级依赖”,它可能顺便:
- 改了 lockfile 的生成方式,导致构建缓存失效(账单飙)
- 把
.env、CI 变量、调试输出打进日志(密钥泄露) - 看到脚本里有
deploy,就尝试跑一遍(生产被碰瓷) - 为了“修复测试”,改了测试本身(你还以为稳定了)
所以安全策略别写成“谨慎使用”。要把风险拆成能落地的开关:文件、网络、进程、权限、密钥、审计。
有次在 Discord 里,读者问过我一句特别实在的话:“它都已经能跑测试、改代码了,为什么不能顺便部署?”我当时第一反应是,理论上可以。可把这事往下拆,你就会发现“顺便部署”这四个字里,藏着网络出口、环境变量、制品来源、回滚路径和审批责任,根本不是一个动作,而是一串动作。
也正因为这样,我现在越来越倾向于把代理看成流水线里的一个工位,而不是一个可以无限外扩的执行者。它做得越多,你越要把边界切得更细。这里面有没有更优雅的自动化方案?应该有,但我自己目前更信工程上的笨办法。
三道闸:照着 OpenAI 的思路抄一套默认值
这一段是整篇的核心观点:别纠结“给不给代理权限”,要纠结“权限怎么分三次给”。
第一道闸:沙箱隔离(文件 / 网络 / 进程)
把代理想成在厨房里学做菜的新厨子:刀给它、锅给它,但先别给燃气总阀,也别让它随便出门买东西。
你要的隔离,至少覆盖三件事:
- 文件隔离
- 只挂载工作目录(项目代码),别把整块 Home 目录塞进去
- 禁止访问 SSH 目录、浏览器配置、云 CLI 默认凭证目录(这些地方全是“现成钥匙”)
- 网络隔离
- 默认禁网,尤其是本地跑的时候
- 要放网也要“只放允许域名”,比如只允许访问你公司的包仓库、镜像源
- 进程隔离
- 限制它能起的进程类型(只允许
git、node、pytest这类) - 禁止它直接调用系统层面的破坏性命令(后面白名单会讲)
第二道闸:分级权限 + 人工审批(把高风险动作变成“需要签字”)
“让它自己跑完”听起来很爽,但真正稳的是:低风险动作自动化,高风险动作走审批。
我建议你用这张表定团队默认值。你一个人做项目,其实也一样适用:
| 动作类型 | 默认策略 | 你要的反馈(做对了长啥样) |
|---|---|---|
| 读代码、跑测试、静态分析 | 自动允许 | 产出可复现的命令与日志,CI 能重跑 |
| 修改代码(工作分支) | 允许,但只能 PR | PR 里有 diff,能逐行 review |
推送到 main / 改 tag / 发 release | 必须人工确认 | 触发前弹出确认点,且记录操作者 |
| 联网下载依赖 | 默认允许“固定来源”,否则确认 | 日志里能看见访问域名与版本号 |
执行 rm / 清库 / 改权限 / 写系统目录 | 一律阻断 | 明确报错:需要人工接管 |
| 部署到云、迁移数据库 | 必须人工确认 + 双人复核(可选) | 有审批记录 + 可回滚脚本 |
这里的关键不是“你不信任它”,而是你把责任边界画出来了:代理负责产出,主人负责批准。
第三道闸:密钥最小暴露(短期、最小权限、只在运行时出现)
真正让人睡不着的,是密钥。
你想要的不是“把密钥藏好”,而是做到三件事:
- 短期:用临时令牌,能 30 分钟到几小时过期的那种,别用长期 Access Key
- 最小权限:只给它完成任务需要的那一小撮权限,比如只能写某个 bucket、只能部署到 staging
- 不落盘:密钥只在运行时通过环境变量注入,禁止写入 repo、禁止写入日志、禁止写入产物
方法论:一套能照抄的“默认禁用 → 逐步放行”流程
下面是落地部分。按这个顺序做,最不容易漏。
Step 0:先定“运行形态”(本地 vs CI)
- 本地:优先强隔离(容器/虚拟机),默认禁网
- CI:把代理当作一个 job,权限跟 job 走,所有动作必须有日志、可重跑
你做完这一步,应该能回答一句话:代理跑在哪台机器上?那台机器上有哪些它不该看到的东西?
Step 1:仓库默认只读,改动只能走 PR
目标:让“可追溯”成为默认值。
操作要点(平台无关):
- CI checkout 用只读 token,或者直接匿名拉取公开仓库
- 禁止代理持有能直接 push
main的凭证 - 改动必须以 PR 形式输出,哪怕是你一个人,也当成流程
你做对了的标志是:代理即使想“悄悄改点东西”,也只能留下一个你看得见的 diff。
Step 2:命令白名单(让它只能用“厨房刀具”,别摸电锯)
这里给你一个可复制的白名单模板:把允许的命令分三层——允许、需要确认、禁止。
你可以先从这套起步,再按你项目语言改:
- 允许(自动执行):
git status、git diff、npm test、pytest、ruff、go test、mvn test - 需要确认(弹窗/审批):
git push、docker build、terraform plan、kubectl diff - 禁止(直接拒绝):
rm -rf、chmod -R、chown、terraform apply、kubectl apply、任何直接连生产的命令
为了让你今天就能用,我给一个最小的审批提示词(prompt),你可以塞到任何代理的系统提示或团队规范里:
text你是代码代理。默认只能:读仓库、在隔离环境运行测试/静态检查、在工作分支修改代码并通过 PR 提交建议。
当你准备执行以下动作时,必须先停止并请求人工确认:联网访问非白名单域名、git push、发布/部署、写入仓库以外路径、删除文件、修改权限、运行基础设施变更命令。
如果发现可能包含密钥/凭证的内容(如 .env、API key、token、私钥),必须在输出中打码并提示风险,不得写入文件或日志。
Step 3:密钥注入策略(Mac/Linux 和 Windows 两套)
原则:密钥只给“需要它的那一步”,不给整条流程。
Mac/Linux(运行时注入到单个命令):
bashAWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... npm run deploy:staging
Windows PowerShell(同样只对当前会话/命令生效):
powershell$env:AWS_ACCESS_KEY_ID="..."; $env:AWS_SECRET_ACCESS_KEY="..."; npm run deploy:staging
你做对了的标志是:
- repo 里搜不到密钥
- 构建产物里搜不到密钥
- 日志里也搜不到密钥,至少不会明文出现
Step 4:审计与回滚(让“出事”变成一次演练,而不是一次事故)
你不可能保证永远不出事,但你可以保证“出事时别瞎”。
最低配你也要有:
- 审计:保存代理执行过的命令清单、拉取/安装了哪些依赖、生成了哪些文件
- 回滚:所有改动都在分支/PR;部署要有对应的回滚命令,或上一版本可一键恢复
- 复现:CI 里能重跑同一套命令,结果一致,至少失败方式一致
我自己的习惯是:只要代理碰过“部署 / 依赖升级 / 配置变更”,我就会要求它在 PR 描述里附一段“回滚说明”。写不出来的回滚,基本都不该自动执行。
说白了,安全配置的价值不只是在“拦住一次坏动作”,还在于它能让你复盘。很多人把事故当成模型问题,我越来越觉得,更多时候是流程没有留下抓手。等你想回看那一步到底是谁批的、用了什么密钥、访问了哪些域名,结果什么都没记,那就不是模型太聪明,是系统太糊涂。
如果你现在手上已经有一条能跑的 agent 流程,不妨先别急着加能力。先做一件小事:挑出其中最危险的那个动作,把它改成“默认不执行,必须确认”。通常改完这一处,你对整套系统的控制感就会完全不一样。
你可以直接照抄的“高风险操作确认清单”
把下面这份当成你每次点“允许”之前的过脑子 checklist:
- 这一步会不会写生产?会 → 必须审批
- 这一步会不会联网?连哪?不确定 → 必须审批
- 这一步会不会读到密钥?会 → 改成短期令牌 + 运行时注入
- 这一步失败了能不能回滚?不能 → 先补回滚再执行
- 这一步执行完,我能不能解释“它做了什么”?不能 → 先补审计
到这里你会发现:你要的不是“更聪明的代理”,而是一套让你敢用它的安全地板。
FAQ
Q: 我就一个人做项目,也要搞审批吗?
A: 要,但可以简化成“高风险动作必须手动确认”。你一个人更容易手滑,流程不是官僚,是防呆。
Q: 默认禁网会不会太麻烦?
A: 本地默认禁网更稳;真需要联网就改成“域名白名单 + 人工确认”。麻烦一点,换来的是不会把凭证和环境一起暴露。
Q: PR 流程会不会拖慢效率?
A: 早期反而更快:你能一眼看 diff、能回滚、能复盘。真正拖慢的是线上出一次事故后全盘排查。
如果你打算今天就把 Codex 接进项目,我建议别先研究 prompt,先把三件事补上:沙箱、审批点、短期密钥。做完以后,再回头看你的流程里还有哪一步其实默认信得太多了。那一步,往往才是下一次事故真正会长出来的地方。