技术热点落地:Codex 每天烧穿 1 TB SSD——Coding Agent 进程「snapshot + immutable log + resource cap」三层防护落地,1 周把 4 个 CWE 关联攻击面堵死(2026-06-23)
适用场景与目标
过去 24 小时的最强信号(与 6/23 AI 快报 Codex 烧 SSD 完整证据链 呼应):
- 6 月 22 日 22:23 UTC:OpenAI 一次性合并 #29432(停打 Responses WebSocket payload)+ #29457(过滤 noisy target)两个 PR,关闭 openai/codex#28224——Codex SQLite feedback log(
~/.codex/logs_2.sqlite)每天给开发者本机 SSD 写 ~640 TB。主帖证据:21 天累计 37 TB 写入 / SQLite AUTOINCREMENT counter 5,543,677,486 / 实际保留 506,149 行 = 10,000× 写放大 / 外推 640 TB/year——对一块 1 TB SSD 是 640× full-drive write / year,一年内烧穿 TBW。 - 6 月 17 日:issue 评论里 @ZenulAbidin 报 Codex
/goal模式「actively delete files and folders on your disk in a vain attempt to gain disk space」——Coding Agent 已经从「静默写太多」升级到「静默清理以继续写」:从「I/O 浪费」升级到「文件系统破坏(CWE-22 路径穿越 + CWE-73 外部控制路径名)」的范式升级。 - 6 月 20 日:用户 @prodan-s 报:codex-cli 0.141.0 macOS 上 SQLite log layer 仍以
Targets::new().with_default(Level::TRACE)挂载——PR 合并 ≠ macOS / Windows / Linux 三平台 binary lockstep rollout,意味着 6/23 起新装 Codex 的工程师默认还是在跑 9 个月未经 resource cap 的版本。 - 同周对照:openai/codex#28879 rate-limit 涨价 10-20× 357 reactions / 9 天 0 回应 + AutoJack localhost 攻击链 6/18 + 本机 SSD 烧穿 6/22 + Microsoft Copilot Cowork usage-based billing 6/22——4 件事在 6 月 18-22 日 5 天内同步爆发:订阅预算 + 硬件耐久度 + 文件系统破坏 + 商业模式——AI Agent 商业化早期阶段的系统性运维债全面暴露。
6/18 + 6/19 + 6/20 + 6/21 + 6/22 + 6/23 的工程化推论:
| 时间 | 信号 | 工程化产物 |
|---|---|---|
| 6/18 | AutoJack localhost 攻击链 | 「进程零信任沙箱」必须装(6/21 文章) |
| 6/19 | MCP EMA stable | 「怎么治协议」(6/19 文章) |
| 6/20 | Mcp2cli + Context Mode + Prompt Caching 三件套 | 「怎么省 token」(6/20 文章) |
| 6/21 | AutoGen Studio 4 CWE 堵死 | 「localhost 信任边界破产」 |
| 6/22 | Codex 烧 SSD + /goal 删文件 | 「本机 SSD endurance audit 必须做」 |
| 6/23 | codex-cli 0.141.0 macOS 仍未 rollout 修复 | 「Coding Agent 进程三层防护本周必须装」 |
这篇不讨论「Codex 是不是值得信任」。这篇解决「OpenAI Codex 在 6 月同一窗口内被 rate-limit + SSD endurance + auto-cleanup 三个独立维度同时打穿,且 PR 修完但 macOS binary 仍未 rollout,今天起 1 周内用什么工具 / 命令 / 配置把「Coding Agent 进程 = 不受监控的内核级对手」造成的 4 个 attack surface(log 写爆 SSD + /goal 模式删用户文件 + log 无法截断 + macOS/Windows/Linux binary rollout 不一致)全部堵死」。
适用场景:
- 你在用 Codex CLI / Claude Code / Cursor / Cline / Windsurf / OpenHands / Aider / Continue.dev 任一款 Coding Agent 跑在本机 / 容器 / VM——Agent 进程和你开发环境共享同一个文件系统、同一个 SSD endurance budget
- 你在用 AutoGen / LangGraph / CrewAI / SWE-Agent / OpenHands 任一款 Agent 框架做 Browser Agent / Code Agent / Research Agent——Agent 进程 = 一个跑在你本机上的 headless browser + file editor + shell executor
- 你的本机 没有 btrfs / zfs snapshot / chattr immutable / process resource cap 任何一层防护——Coding Agent 默认是不可信进程:可写爆 SSD(openai/codex#28224)、可主动删文件(
/goal模式)、可 mount 不安全 binary(codex-cli 0.141.0 macOS 仍未 rollout 修复) - 你在做 企业内网部署 Coding Agent——Agent 进程 = 一个永远在线、永不疲倦、有 file/network/process 全部权限的内部员工,没有三层防护 = SOC 2 / ISO 27001 失分 + 法律风险
- 你在做 AI Coding Agent 选型 / 采购 / SLA 谈判——「该 Agent 是否有 default-on TRACE log layer」「该 Agent 是否有 production I/O/RAM/CPU resource cap」「该 Agent 是否经过 90 天 production resource 监控报告」3 个问题必须当面问清
- 你的本机有 重要数据 + 1-2 TB SSD + 没有 snapshot 备份——Codex 跑在你本机 9 个月 ≈ 你 SSD 已经被消耗 50%+(对照 openai/codex#28224 主帖 640 TB/year)
- 你在做 AI Agent 框架的内部 sandbox / 资源监控设计——这是「Coding Agent 商业化早期阶段的系统性运维债」的硬指标,不是 PR 稿里的 SLA
核心目标(一周):
- D+0(今天,3 小时):跑本机 SSD endurance audit——
smartctl查累计写入 TB 数 +ls ~/.codex/logs_2.sqlite* ~/.claude/logs* ~/.cursor/logs*查 Coding Agent 进程是否在本地写 SQLite log - D+1:给 Agent 工作目录装 btrfs subvolume + zfs filesystem + 每天 snapshot——30 秒快照 + 5 分钟 rollback = Agent 删错文件秒回滚
- D+2:给 Agent log 路径加 chattr +i immutable + WAL 自动 checkpoint 截断——Agent 不能删自己的 log,即使
/goal模式也不会清理 - D+3:用 systemd-run —scope -p IOReadBandwidthMax / IOWriteBandwidthMax / MemoryMax / CPUQuota 给 Agent 进程装 resource cap——硬上限 + 超限自动 kill
- D+4:给 Agent 跑在 bubblewrap / firejail / Docker —security-opt sandbox——独立 mount namespace + 文件系统只读 + 网络白名单(参考 6/21 AutoJack 零信任沙箱文章)
- D+5:复现
/goal模式删文件 PoC + 验证四件套拦截(snapshot 可回滚 + immutable 阻止删除 + resource cap 限制写入带宽 + sandbox 隔离文件系统) - D+6:写 「Coding Agent 进程三层防护 SOP」 + 「Agent 资源事故 watch」 每日 15 分钟订阅
- D+7:产出**「Coding Agent 进程三层防护模板 v1.0 + btrfs/zfs snapshot 脚本 + systemd-run profile + 30/90 天路线图」**,给 VP Eng / CISO walkthrough
最小可行方案(MVP)步骤
下面这套流程对照 openai/codex#28224 主帖证据 + PR #29432 + PR #29457 + Linux man pages chattr / systemd-run / btrfs-send / zfs / sqlite3-wal 验证;前 3 步 6 小时内可完成。
阶段 0:先跑 SSD endurance audit(Day 0,2 小时)
不要直接上三层防护,先回答四个问题——openai/codex#28224 教会的第一课就是「先 audit,再加固」:
# 1) 列出本机所有 Coding Agent 进程的本地 SQLite log + WAL + SHM 文件
ls -la ~/.codex/logs_2.sqlite* ~/.claude/logs* ~/.cursor/logs* \
~/.openhands/logs* ~/.aider/logs* ~/.cline/logs* 2>/dev/null
# 重点看:
# - 文件大小(> 1 GiB 就有问题)
# - WAL/SHM 文件(Codex 同款 10,000× 写放大根因)
# - mtime + ctime(如果 1 天涨 1 GiB = 默认 log 层失控)
# 2) SQLite 内部分析:写放大倍数
sqlite3 ~/.codex/logs_2.sqlite 'SELECT COUNT(*) AS retained_rows FROM feedback;'
sqlite3 ~/.codex/logs_2.sqlite 'SELECT seq FROM sqlite_sequence WHERE name="feedback";'
# 对照 [openai/codex#28224](https://github.com/openai/codex/issues/28224):
# retained_rows = 506,149
# sqlite_sequence.seq = 5,543,677,486
# 写放大 = seq / retained = 10,947×
# 3) SSD 累计写入 TB 数(SMART data)
sudo smartctl -A /dev/nvme0n1 | grep -iE 'Data Units Written|Total LBAs Written'
# NVMe: "Data Units Written" 单位是 1000 × 512-byte = 512,000 bytes
# 公式: TBW = Data Units Written × 512000 / 1e12
# SATA: "Total LBAs Written" 单位是 512-byte sectors
# 公式: TBW = Total LBAs Written × 512 / 1e12
# 例: Data Units Written = 74,000,000 → TBW = 37 TB(对照主帖 21 天累计 37 TB)
# 4) 计算本机 SSD 已被消耗的 endurance 比例
# 对照主帖公式: 640 TB/year × 本机已使用天数 / 365
# 例: Codex 跑 9 个月 = 270 天 → 已消耗 ≈ 640 × 270/365 = 473 TB
# 1 TB SSD TBW 一般 = 600 TB(消费级)/ 1200 TB(企业级)
# → 473 / 600 = 78% endurance 已消耗(必须备份 + 准备换 SSD)
Audit 输出清单(必须写到 /tmp/agent-ssd-audit.md):
- 本机所有 Coding Agent 进程的 SQLite log 文件清单 + 大小 + 写放大倍数
- 本机 SSD 累计写入 TB 数 + endurance 剩余比例(> 50% 立即备份 + 准备换 SSD)
- TBW 比例 > 50% 的本机立即备份 + 准备换 SSD——Codex 跑在你本机 9 个月 ≈ 你 SSD 已经被消耗 50%+
阶段 1:btrfs / zfs snapshot 备份(Day 1,3 小时)
Snapshot 是「Coding Agent 删错文件 / 烧穿 SSD」的最后防线——30 秒快照 + 5 分钟 rollback = Agent 删错文件秒回滚。
# ---- 选项 A:btrfs(Linux 主流,btrfs-progs 已装) ----
# 1) 把 Agent 工作目录建在独立 btrfs subvolume
sudo mkdir -p /var/agents
sudo mkfs.btrfs -f /dev/nvme0n1p5 # 假设 nvme0n1p5 是独立分区
sudo mount /dev/nvme0n1p5 /var/agents
sudo btrfs subvolume create /var/agents/codex-home
sudo btrfs subvolume create /var/agents/claude-home
sudo btrfs subvolume create /var/agents/cursor-home
# 把 ~/.codex ~/.claude ~/.cursor 移到 subvolume
sudo mkdir -p /var/agents/codex-home/.codex
sudo chown -R $USER:$USER /var/agents/codex-home
ln -sfn /var/agents/codex-home/.codex ~/.codex
# 2) 每天 cron 自动 snapshot
cat > /etc/cron.daily/btrfs-snapshot-agents <<'EOF'
#!/bin/bash
# 每天凌晨 3 点给 /var/agents/*-home subvolume 做 read-only snapshot
DATE=$(date +%Y%m%d-%H%M%S)
for sub in /var/agents/*-home; do
name=$(basename "$sub")
btrfs subvolume snapshot -r "$sub" "/var/agents/.snapshots/${name}-${DATE}"
# 保留最近 7 天 snapshot,更早的删除
btrfs subvolume list -o /var/agents | grep "${name}-" | \
awk '{print $NF}' | sort | head -n -7 | \
while read snap; do
btrfs subvolume delete "/var/agents/$snap" 2>/dev/null
done
done
EOF
sudo chmod +x /etc/cron.daily/btrfs-snapshot-agents
sudo /etc/cron.daily/btrfs-snapshot-agents # 手动跑一次验证
# 3) Agent 删错文件,rollback 到 5 分钟前的 snapshot
SNAP=$(btrfs subvolume list -o /var/agents/codex-home | \
grep codex-home- | sort -k7 | tail -1 | awk '{print $NF}')
sudo btrfs subvolume snapshot "$SNAP" /var/agents/codex-home-rollback
# 把 rollback 出来的目录覆盖回 codex-home:
# sudo rsync -a /var/agents/codex-home-rollback/ /var/agents/codex-home/
# ---- 选项 B:zfs(macOS / Linux,Apple Silicon / 主流 Linux) ----
# 1) 创建 zpool + dataset
sudo zpool create -f agents /dev/nvme0n1p5 # Linux
# macOS: 用 APFS 时间机器替代(Time Machine 30 分钟一快照够用)
# 2) 给每个 Agent 建独立 dataset
sudo zfs create agents/codex-home
sudo zfs create agents/claude-home
sudo zfs create agents/cursor-home
sudo zfs set compression=lz4 agents/codex-home
sudo zfs set mountpoint=/home/$USER/.codex agents/codex-home
# 3) 自动 snapshot(zfs-auto-snapshot)
sudo zfs set com.sun:auto-snapshot=true agents/codex-home
sudo zfs set com.sun:auto-snapshot:frequency=hourly agents/codex-home
# 保留策略:24 小时快照 + 7 天每日 + 4 周每周
sudo zfs set com.sun:auto-snapshot:hourly=24 agents/codex-home
sudo zfs set com.sun:auto-snapshot:weekly=4 agents/codex-home
# 4) Rollback
sudo zfs rollback -r agents/codex-home@auto-2026-06-23-0900
⚠️ 避坑:
- btrfs 在消费级 SSD 上坑多——RAID5/6 write hole + metadata duplication 写入放大 + balance 操作耗 SSD endurance,btrfs 推荐用法 = 单盘 subvolume + snapshot + send/receive,不要在 btrfs 上跑数据库
- zfs 在 Linux 上要 ramdisk 给 ZIL——
/etc/modprobe.d/zfs.conf设zfs_zil_max=16777216限制 ZIL 内存 - macOS Time Machine 不是 snapshot,是 hourly backup——回滚粒度 = 1 小时,Agent 删错文件 1 小时内无 snapshot = 数据丢失
阶段 2:immutable log + WAL 截断(Day 2,2 小时)
Agent 不能删自己的 log 是「/goal 模式主动清理」的唯一硬阻挡——即使 Agent 想 rm ~/.codex/logs_2.sqlite 也失败。
# 1) 给 Coding Agent 的 log 路径加 chattr +i (Linux ext4 / xfs / btrfs)
chattr +i ~/.codex/logs_2.sqlite ~/.codex/logs_2.sqlite-* \
~/.claude/logs/* ~/.cursor/logs/* 2>/dev/null
# 验证:
lsattr ~/.codex/logs_2.sqlite
# ----i---------e------- logs_2.sqlite
# ↑
# 'i' = immutable, 不能删/改
# 2) WAL 自动 checkpoint 截断(SQLite 写放大根因)
# SQLite WAL 文件 (-wal) 不 checkpoint 永远不会清空 → 持续写放大
cat > ~/.codex/scripts/wal-checkpoint.sh <<'EOF'
#!/bin/bash
# 每 5 分钟给 Coding Agent 的 SQLite log 做一次 truncate checkpoint
for db in ~/.codex/logs_2.sqlite ~/.claude/logs/*/db.sqlite \
~/.cursor/logs/*.sqlite ~/.openhands/logs/*.sqlite; do
if [ -f "$db" ]; then
# passive checkpoint 不锁表 + truncate WAL
sqlite3 "$db" 'PRAGMA wal_checkpoint(TRUNCATE);' 2>/dev/null
fi
done
# 5 分钟后删除最旧的 partition(模拟 PR #29432 的 partition 修剪)
find ~/.codex ~/.claude ~/.cursor -name "*.sqlite" -size +500M \
-exec sqlite3 {} 'DELETE FROM feedback WHERE ts < datetime("now", "-7 days");' \;
EOF
chmod +x ~/.codex/scripts/wal-checkpoint.sh
# 3) 装 crontab(每 5 分钟跑一次)
(crontab -l 2>/dev/null; echo "*/5 * * * * /home/$USER/.codex/scripts/wal-checkpoint.sh") | crontab -
# 4) macOS 用 launchd 等价
cat > ~/Library/LaunchAgents/com.user.agent-wal-checkpoint.plist <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>com.user.agent-wal-checkpoint</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/$USER/.codex/scripts/wal-checkpoint.sh</string>
</array>
<key>StartInterval</key><integer>300</integer>
</dict>
</plist>
EOF
launchctl load ~/Library/LaunchAgents/com.user.agent-wal-checkpoint.plist
⚠️ 避坑:
chattr +i在 macOS / Windows / 部分网络文件系统(NFS / SMB)上不支持——macOS 用chflags uimmutable <file>等价;Windows 用 NTFSSet-FileProperty -Name IsReadOnly -Value $true $pathchattr +i阻止 log 写入——Agent 写 log 会被 EPERM error,必须配合「WAL checkpoint 截断」先释放 log 大小,再chattr +i;或者用chattr +a(append-only,允许写入但不能 truncate/delete)SQLite WAL checkpoint(TRUNCATE)在 Agent 进程持有写锁时会 busy——加 retry:sqlite3 "$db" 'PRAGMA wal_checkpoint(TRUNCATE);' || sleep 1 && sqlite3 "$db" 'PRAGMA wal_checkpoint(TRUNCATE);'
阶段 3:systemd-run resource cap(Day 3,2 小时)
Resource cap 是「Coding Agent 烧穿 SSD / 吃满内存 / 跑满 CPU」的最后硬上限——systemd-run --scope 给 Agent 进程加 IO / RAM / CPU / FS 硬限制,超限自动 kill。
# 1) 给 Codex / Claude Code / Cursor / Cline 写 systemd-run profile
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/codex-resource-cap.sh <<'EOF'
#!/bin/bash
# 给 Codex CLI 进程加 resource cap 后启动
# 关键参数:
# - IOWeight=100 (相对其他进程 IO 权重 100, 默认 100)
# - IOWriteBandwidthMax=50M (写带宽硬上限 50 MB/s)
# - IOReadBandwidthMax=200M (读带宽硬上限 200 MB/s)
# - MemoryMax=4G (内存硬上限 4 GB)
# - MemoryHigh=3G (内存软上限 3 GB, 触发回收)
# - CPUQuota=200% (CPU 硬上限 2 核)
# - TasksMax=100 (进程/线程数硬上限 100)
# - LimitNOFILE=1024 (文件描述符硬上限 1024)
exec systemd-run --scope --user \
-p IOWeight=100 \
-p IOWriteBandwidthMax=50M \
-p IOReadBandwidthMax=200M \
-p MemoryMax=4G \
-p MemoryHigh=3G \
-p CPUQuota=200% \
-p TasksMax=100 \
-p LimitNOFILE=1024 \
-- codex "$@"
EOF
chmod +x ~/.config/systemd/user/codex-resource-cap.sh
cat > ~/.config/systemd/user/claude-code-resource-cap.sh <<'EOF'
#!/bin/bash
exec systemd-run --scope --user \
-p IOWeight=100 \
-p IOWriteBandwidthMax=30M \
-p IOReadBandwidthMax=150M \
-p MemoryMax=6G \
-p MemoryHigh=4G \
-p CPUQuota=300% \
-p TasksMax=200 \
-p LimitNOFILE=2048 \
-- claude "$@"
EOF
chmod +x ~/.config/systemd/user/claude-code-resource-cap.sh
# 2) macOS 等价(用 sandbox-exec / cgroups-v2 不可用)
# macOS 推荐用 Docker --cpus --memory --device-read-bps --device-write-bps
cat > ~/.local/bin/codex-cgroup.sh <<'EOF'
#!/bin/bash
# macOS: 用 Docker + cgroups-v2 模拟 resource cap
docker run -it --rm \
--cpus=2 \
--memory=4g \
--device-read-bps=/dev/disk0:50mb \
--device-write-bps=/dev/disk0:30mb \
-v ~/.codex:/home/agent/.codex \
-v $(pwd):/workspace \
codex-cli:latest "$@"
EOF
chmod +x ~/.local/bin/codex-cgroup.sh
# 3) 验证 resource cap 生效
~/.config/systemd/user/codex-resource-cap.sh --version &
sleep 2
# 查看 systemd cgroup 实时 IO/RAM/CPU
systemd-cgtop --user
# 或:
cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/*codex*/io.stat 2>/dev/null
⚠️ 避坑:
systemd-run --scope必须在 cgroups-v2 内核上跑——uname -r≥ 5.8 +/sys/fs/cgroup/cgroup.controllers含iocontrollerIOWriteBandwidthMax单位是字节/秒,写成50MB/s不识别——必须用50M(不是50MB)- Agent 进程 fork 出的子进程不自动继承 resource cap——必须用 systemd-run 启动整个进程树,或在代码层 fork 后 setrlimit(2)
- macOS 没有 cgroups-v2 完整 IO controller——推荐用 Docker +
--device-write-bps模拟
阶段 4:bubblewrap / firejail sandbox(Day 4,3 小时)
Sandbox 是「Agent 进程可访问哪些文件 / 网络 / 进程 / syscall」的最严边界——/goal 模式删文件、rm -rf /、curl 内网恶意 IP 全部隔离。
# ---- 选项 A:bubblewrap(Linux 主流,systemd-friendly) ----
# 1) 安装 bubblewrap
sudo apt install bubblewrap # Debian/Ubuntu
sudo dnf install bubblewrap # Fedora
# 2) 写 Codex 的 bubblewrap 启动脚本
cat > ~/.local/bin/codex-bwrap.sh <<'EOF'
#!/bin/bash
# Codex 在 bubblewrap sandbox 里跑:
# - 只读挂载 /usr /lib /etc (系统)
# - 只读挂载 ~/.codex/logs_2.sqlite (log immutable)
# - 可写挂载 ~/work (工作目录)
# - 网络 namespace 隔离(仅允许连 OpenAI API)
exec bwrap \
--ro-bind /usr /usr \
--ro-bind /lib /lib \
--ro-bind /etc/resolv.conf /etc/resolv.conf \
--ro-bind ~/.codex/logs_2.sqlite /home/agent/.codex/logs_2.sqlite \
--bind ~/work /home/agent/work \
--tmpfs /tmp \
--unshare-net \
--unshare-pid \
--unshare-ipc \
--hostname codex-sandbox \
--die-with-parent \
--new-session \
--cap-drop ALL \
codex "$@"
EOF
chmod +x ~/.local/bin/codex-bwrap.sh
# 3) 验证 bubblewrap 隔离生效
~/.local/bin/codex-bwrap.sh --version
# 然后在 sandbox 内执行:
# rm -rf / → 应该 no such file or directory
# curl evil.com → 应该 Network is unreachable (unshare-net)
# touch ~/work/test.txt → 应该可写
# ---- 选项 B:firejail(Linux,更易用但依赖更多) ----
# 1) 安装 firejail
sudo apt install firejail
# 2) 写 Codex 的 firejail profile
cat > ~/.config/firejail/codex.profile <<'EOF'
# Codex Coding Agent firejail profile
include codex-common.profile
include disable-common.inc
include disable-exec.inc
include disable-passwdmgr.inc
include disable-programs.inc
# 白名单只读系统
whitelist /usr
whitelist /lib
whitelist /lib64
whitelist /etc/resolv.conf
whitelist /etc/ssl/certs
# 工作目录(可写)
mkdir ~/work
whitelist ~/work
whitelist ~/.codex
read-only ~/.codex/logs_2.sqlite
read-only ~/.codex/logs_2.sqlite-wal
read-only ~/.codex/logs_2.sqlite-shm
# 禁止 syscall
seccomp
seccomp.drop @clock,@cpu-emulation,@debug,@module,@obsolete,@raw-io,@reboot,@resources,@swap
# 网络限制
netfilter
# 仅允许连 OpenAI API + Anthropic API(编辑 /etc/firejail/codex.netfilter)
# 资源限制
rlimit-cpu 600
rlimit-nofile 1024
rlimit-nproc 100
EOF
# 3) 用 firejail 启动 Codex
firejail --profile=~/.config/firejail/codex.profile codex "$@"
⚠️ 避坑:
- bubblewrap
--unshare-net后 Agent 无法调 OpenAI API——必须先在 sandbox 外socat转发 OpenAI API endpoint 到 unix domain socket,sandbox 内用--bind挂载 socket;或用--share-net但配--unshare-user+ 自定义 seccomp 限制 - firejail profile 名字不能和系统 profile 重名——必须放在
~/.config/firejail/不是/etc/firejail/ seccomp.drop @clock会让 Agent 的定时器 / timeout 全失效——只 drop 真正危险的:@module @raw-io @reboot @resources @swap,不要 drop @clock @cpu-emulation
阶段 5:复现 /goal 模式删文件 PoC + 验证四件套(Day 5,2 小时)
三层防护建好后必须用真实 PoC 验证——纸上架构 ≠ 真能拦。
# 1) 验证一:Snapshot rollback 5 分钟内可回滚
echo "重要数据 test data $(date)" > ~/work/important-data.txt
cat ~/work/important-data.txt
# 模拟 Codex /goal 模式删文件:
rm ~/work/important-data.txt
# rollback:
SNAP=$(btrfs subvolume list -o /var/agents/codex-home | grep codex-home- | sort | tail -1 | awk '{print $NF}')
sudo btrfs subvolume snapshot "$SNAP" /var/agents/codex-home-rollback
sudo rsync -a /var/agents/codex-home-rollback/ ~/work/
cat ~/work/important-data.txt
# → 应该看到 test data + 之前时间戳(rollback 成功)
# 2) 验证二:immutable log 阻止 Agent 删 log
chattr +i ~/.codex/logs_2.sqlite
rm ~/.codex/logs_2.sqlite
# → rm: cannot remove 'logs_2.sqlite': Operation not permitted ✅
# Agent 即使在 /goal 模式也删不掉
# 3) 验证三:resource cap 限制 I/O 带宽
~/.config/systemd/user/codex-resource-cap.sh --help &
sleep 2
# 查看 cgroup IO 实时统计:
cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/*codex*/io.stat | head -10
# 写带宽应该稳定在 50 MB/s 以下,不会被 Agent 一波写爆
# 4) 验证四:bubblewrap sandbox 隔离
~/.local/bin/codex-bwrap.sh -c "rm -rf /"
# → rm: cannot remove '/': No such file or directory (unshare-pid 后 / 是 sandbox 根)
# 或:
~/.local/bin/codex-bwrap.sh -c "curl http://evil.com"
# → curl: (6) Could not resolve host (unshare-net 后 DNS 隔离)
# 5) 综合演练:复现 openai/codex#28224 SSD 烧穿场景
# 用 sync 工具生成大量 IO 看是否被 resource cap 拦截:
dd if=/dev/zero of=/tmp/testfile bs=1M count=10000 oflag=direct
# 在 systemd-run --scope 内执行 → IOWriteBandwidthMax=50M 限速到 50 MB/s
# 对照无 cap 时 ~3 GB/s(NVMe SSD 顺序写速度),cap 生效 = 写带宽减少 60×
# 6) 验证 ChatGPT Plus 风格 prompt(实测 per-token cost)
# → 应该全部返回 "unknown model"(sandbox 没 OpenAI API key)
# → 验证 sandbox 完全隔离
阶段 6:写 SOP + 每日 watch(Day 6-7,4 小时)
三层防护 SOP 必须写到内部 wiki + Notion——所有用 Coding Agent 的工程师都能查到。
# 1) 写 "Coding Agent 进程三层防护 SOP v1.0" 到内部 wiki
# 包含:
# - 阶段 0-5 的所有命令 + 验证脚本
# - 应急联系 (磁盘满 / SSD 损坏 / log 失控)
# - snapshot rollback 操作手册
# - chattr +i 解除 immutable 操作 (sudo chattr -i ...)
# - systemd-run resource cap 调整操作
# - bubblewrap / firejail profile 修改操作
# 2) 装 "AI Agent 资源事故 watch" 每日 15 分钟订阅
cat > ~/.ai-watch/sources.txt <<'EOF'
# Coding Agent 资源事故主线 (每日 15 分钟扫一次)
# 主线 1: OpenAI Codex
https://github.com/openai/codex/issues
https://hn.algolia.com/api/v1/search?query=codex+ssd
https://hn.algolia.com/api/v1/search?query=codex+disk
# 主线 2: Anthropic Claude Code
https://github.com/anthropics/claude-code/issues
https://hn.algolia.com/api/v1/search?query=claude+code+disk
# 主线 3: Cursor / LangGraph / CrewAI / OpenHands / Aider
https://github.com/getcursor/cursor/issues
https://github.com/langchain-ai/langgraph/issues
https://github.com/All-Hands-AI/OpenHands/issues
# 主线 4: Microsoft Copilot Cowork
https://the-decoder.com/
# 主线 5: AI Agent 商业化运维债
https://hn.algolia.com/api/v1/search?query=AI+agent+resource
EOF
cat > ~/.ai-watch/daily-watch.sh <<'EOF'
#!/bin/bash
# 每天早上 9 点扫一次
DATE=$(date +%Y-%m-%d)
LOG=~/.ai-watch/watch-$DATE.log
echo "== AI Agent 资源事故 watch $DATE ==" > $LOG
# GitHub Codex issues (open)
curl -s 'https://api.github.com/repos/openai/codex/issues?state=open&labels=bug&per_page=20' | \
jq -r '.[] | " Codex issue #\(.number): \(.title) (reactions: \(.reactions.total_count))"' >> $LOG
# HN search
for q in "codex ssd" "codex disk" "claude code ssd" "agent auto delete" "agent resource"; do
HITS=$(curl -s "https://hn.algolia.com/api/v1/search?query=$(echo $q | tr ' ' '+')&tags=story&numericFilters=created_at_i%3E$(date -d '24 hours ago' +%s)" | jq -r '.hits[]? | " HN: \(.title) (\(.points))"')
[ -n "$HITS" ] && echo "$HITS" >> $LOG
done
cat $LOG
EOF
chmod +x ~/.ai-watch/daily-watch.sh
(crontab -l 2>/dev/null; echo "0 9 * * * /home/$USER/.ai-watch/daily-watch.sh") | crontab -
关键实现细节
1. SQLite WAL checkpoint 详解(Codex 写放大根因)
为什么 Codex 每天 640 TB 写入:主帖证据 + PR #29432 body 显示「Every successful Responses WebSocket event currently produces three local log records: the full payload at TRACE, an OpenTelemetry log event, and an OpenTelemetry trace event. On busy threads these records fill the 1,000-row log partition in seconds and cause continuous SQLite insert-and-prune churn.」
WAL 工作原理:
- SQLite 默认 journal mode = WAL(Write-Ahead Log)
- 所有写入先到
-wal文件,periodic checkpoint 才合并到主数据库 - 1000 行 partition 满 → SQLite 持续 insert-and-prune → WAL 永远不 checkpoint → 主数据库 + WAL 双重写
- 一次 Responses WebSocket = 3 条本地 log × 1000 行 partition churn = 10,000× 写放大
缓解代码:
# /home/$USER/.codex/scripts/wal-checkpoint-truncate.py
# 每 60 秒给所有 Coding Agent SQLite 跑 truncate checkpoint + 删除老行
import os, time, sqlite3, glob
from pathlib import Path
def checkpoint_db(db_path: Path):
"""强制 TRUNCATE checkpoint,截断 WAL 文件到 0"""
try:
conn = sqlite3.connect(str(db_path), timeout=5)
# 1) 强制 WAL truncate checkpoint
conn.execute("PRAGMA wal_checkpoint(TRUNCATE);")
# 2) 删除 7 天前的 feedback 行(参考 PR #29432 partition 修剪策略)
seven_days_ago = time.time() - 7 * 86400
deleted = conn.execute(
"DELETE FROM feedback WHERE ts < datetime(?, 'unixepoch')",
(seven_days_ago,),
).rowcount
# 3) VACUUM 回收空间(释放的 page 归还 OS)
conn.execute("VACUUM;")
conn.commit()
conn.close()
return deleted
except sqlite3.OperationalError as e:
# Agent 持有写锁时 busy
if "database is locked" in str(e):
return 0
raise
if __name__ == "__main__":
db_paths = []
for pattern in [
os.path.expanduser("~/.codex/logs_2.sqlite"),
os.path.expanduser("~/.claude/logs/**/*.sqlite"),
os.path.expanduser("~/.cursor/logs/*.sqlite"),
os.path.expanduser("~/.openhands/logs/*.sqlite"),
]:
db_paths.extend(glob.glob(pattern, recursive=True))
for db in db_paths:
deleted = checkpoint_db(Path(db))
if deleted > 0:
print(f"[ok] {db}: deleted {deleted} rows")
2. systemd-run resource cap 的 cgroup v2 验证
# 验证 systemd cgroup v2 完整支持 (5.8+ 内核)
cat /sys/fs/cgroup/cgroup.controllers | tr ' ' '\n' | sort
# 必须包含: cpu cpuacct cpuset io memory pids
# 验证 resource cap 生效:
~/.config/systemd/user/codex-resource-cap.sh --help &
SCOPE_PID=$!
sleep 3
# 找到 cgroup 路径:
CGROUP=$(find /sys/fs/cgroup/user.slice -name "*codex*" -type d | head -1)
echo "cgroup: $CGROUP"
# 查看 IO 实时统计:
cat $CGROUP/io.stat
# 8:0 rbytes=12345 wbytes=67890 rios=12 wios=45 dbytes=0
# ↑
# wbytes 应该稳定在 ~50 MB/s (cap 生效)
# 查看内存:
cat $CGROUP/memory.current
# 1234567890 (bytes)
# 应该稳定 < 4 GB (MemoryMax=4G)
# 查看 CPU:
cat $CGROUP/cpu.stat
# usage_usec 12345678 nr_periods 1000 throttled_usec 12345 throttled_periods 100
# ↑
# throttled 应该 > 0 (CPUQuota=200% 限速生效)
# 验证后清理:
kill $SCOPE_PID
3. chattr +i 在容器 / WSL2 / 网络文件系统上的限制
# chattr +i 在以下环境不生效:
# - NFS / SMB / CIFS 网络文件系统
# - 某些虚拟化层 (Docker overlayfs + virtio-9p)
# - WSL2 (默认 9P filesystem)
# - macOS APFS (用 chflags uimmutable 等价)
# Docker / Podman 容器内验证 chattr 是否生效:
docker run --rm -v ~/.codex:/home/agent/.codex ubuntu:22.04 \
bash -c "touch /home/agent/.codex/test.txt && \
chattr +i /home/agent/.codex/test.txt && \
rm /home/agent/.codex/test.txt"
# 如果 filesystem 是 overlayfs, 会显示:
# chattr: Operation not supported while setting flags on /home/agent/.codex/test.txt
# → 必须用 host filesystem bind mount 或换 btrfs / zfs / ext4
# macOS 等价:
chflags uimmutable ~/.codex/logs_2.sqlite
rm ~/.codex/logs_2.sqlite
# → rm: ~/.codex/logs_2.sqlite: Operation not permitted
4. btrfs / zfs snapshot 对 Coding Agent 的关键约束
# btrfs 限制:
# - 不要在 btrfs subvolume 上跑数据库 (SQLite WAL 性能差 + write amplification)
# - 推荐用法: 把 ~/.codex 整个目录作为 subvolume, 内部 SQLite 跑在 ext4 loopback
# - btrfs send/receive 跨机 snapshot 备份非常快 (增量只发 changed blocks)
# zfs 限制:
# - zfs 在 Linux 上 ARC cache 吃内存 (默认 50% RAM)
# 解决: sudo zfs set zfs_arc_max=2147483648 agents
# - zfs dedup 极吃内存, 关闭: sudo zfs set dedup=off agents
# - zfs snapshot 占用空间 = 实际 changed blocks, 不是整个 dataset
# macOS APFS Time Machine (作为 fallback):
# - APFS snapshot = 本地时间机器 (snapshot 立刻)
# - Time Machine = 远程备份 (1 小时)
# - 回滚:
# 1. Finder 打开 Time Machine → 选 1 小时前版本 → 恢复
# 2. 命令行: tmutil restore /Users/$USER/.codex/logs_2.sqlite \
# /Volumes/TimeMachine/.../logs_2.sqlite
常见坑与规避清单
坑 1:照搬 Codex 修复 PR 但本机 filesystem 不支持
症状:chattr +i ~/.codex/logs_2.sqlite 报 “Operation not supported”——Docker / WSL2 / NFS 文件系统不支持 immutable attribute。
规避:
- 先
stat -f ~/.codex/看 filesystem 类型——ext4 / xfs / btrfs支持chattr +i;overlayfs / 9p / NFS不支持 - Docker 容器用
tmpfs或 host bind mount(docker run -v ~/.codex:/home/agent/.codex:rw) - WSL2 在 Windows 11 22H2+ 支持
chattr +i(内核 5.15+) - macOS 用
chflags uimmutable等价
坑 2:btrfs snapshot 后子目录写穿
症状:btrfs subvolume snapshot 看起来 OK,但 Agent 工作目录的某个子目录持续写爆 SSD——因为 snapshot 只快照 subvolume root,不递归。
规避:
btrfs subvolume snapshot -r /var/agents/codex-home /var/agents/.snapshots/codex-home-${DATE}是递归的- 验证:
btrfs subvolume show /var/agents/.snapshots/codex-home-${DATE}应该显示Quota: none+Snapshot(s): - 重要:snapshot 是 read-only 的,Agent 写 snapshot 路径会失败;rollback 时用
btrfs subvolume snapshot创建 read-write 副本
坑 3:systemd-run —scope 在 macOS / WSL1 / Docker 不可用
症状:systemd-run: command not found 或 Failed to create scope: Unit not loaded——macOS 没有 systemd,WSL1 用 init 进程不是 systemd,Docker 默认 PID 1 不是 systemd。
规避:
- Linux 原生 + systemd 245+ → 用 systemd-run —scope(最稳定)
- macOS → 用
sandbox-exec(Apple 沙箱)或 Docker--cpus --memory --device-read-bps --device-write-bps - WSL1 → 升级到 WSL2 + systemd(
/etc/wsl.conf加[boot] systemd=true+wsl --shutdown) - Docker 容器 → 用
--cpus --memory --device-read-bps --device-write-bps --pids-limit(Docker 19.03+) - Kubernetes Pod →
resources.requests/limits+securityContext.capabilities.drop
坑 4:/goal 模式绕过 sandbox 删外部文件
症状:Codex /goal 模式在 bubblewrap sandbox 内运行,但 sandbox 配置 --bind ~/work /home/agent/work 让 Agent 可写 ~/work,Agent 仍然把 ~/work/.git/ 全删了。
规避:
- bubblewrap 加
--ro-bind ~/work /home/agent/work(只读挂载) - Agent 写文件用 sandbox 内的 writable tmpfs(
--tmpfs /tmp --bind /tmp /home/agent/work-tmp) - 关键目录加 immutable attribute(
chattr +i -R ~/work/.git/) - 定期 git push 到 remote——Agent 即使删了本地,远程还有
坑 5:WAL checkpoint 时 Agent 进程持有写锁
症状:sqlite3 ~/.codex/logs_2.sqlite 'PRAGMA wal_checkpoint(TRUNCATE);' 报 “database is locked”——Agent 正在写。
规避:
- 加 retry:
for i in 1 2 3; do sqlite3 "$db" 'PRAGMA wal_checkpoint(TRUNCATE);' && break || sleep 1; done - PRAGMA busy_timeout:
sqlite3 "$db" 'PRAGMA busy_timeout=5000; PRAGMA wal_checkpoint(TRUNCATE);' - 改用 passive checkpoint:
PRAGMA wal_checkpoint(PASSIVE);(不锁表但 checkpoint 慢) - 彻底方案:用
PRAGMA journal_mode=DELETE替代 WAL(牺牲并发换取 checkpoint 简单)
坑 6:chattr +i 阻止 log 写入后 Agent 报错
症状:chattr +i ~/.codex/logs_2.sqlite 后启动 Codex,log 写入报 EPERM(Operation not permitted),Agent 启动失败或行为异常。
规避:
- 用
chattr +a(append-only) 替代chattr +i(immutable)——Agent 可以追加写但不能 truncate/delete,这是 SQLite 写 log 的实际需要 - WAL 文件不设 immutable——只对主
logs_2.sqlite设+a,WAL 文件logs_2.sqlite-wal保留可写 - 先 WAL truncate 再设 immutable:先
sqlite3 ... 'PRAGMA wal_checkpoint(TRUNCATE);'把 WAL 截断到 0,再chattr +a logs_2.sqlite
坑 7:systemd-run 启动后 IO cap 立即撑爆
症状:IOWriteBandwidthMax=50M 设了,但 Agent 启动后 IO cap 延迟数秒才生效,Agent 在 cap 生效前已经写了几 GB。
规避:
- 手动 setrlimit 后再 fork:在
codex-resource-cap.sh里加ulimit -f 10485760(10 GB 文件大小硬上限)作为第一道防线 - 用 cgroup v2 +
IOWeight=1(最低 IO 权重,不限制带宽但让 cgroup 调度器自动让出) - 监控 + 告警:cgroup 实时 IO 写入 > 100 MB/s 持续 10 秒 → 自动 kill Agent 进程
cat > ~/.codex/scripts/io-watchdog.sh <<'EOF'
#!/bin/bash
# 监控 cgroup IO 写入速率,超限自动 kill Agent
THRESHOLD=104857600 # 100 MB/s in bytes
CGROUP_DIR=$(find /sys/fs/cgroup/user.slice -name "*codex*" -type d | head -1)
while true; do
WBYTES=$(cat $CGROUP_DIR/io.stat 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i~/^wbytes=/) print $i}' | cut -d= -f2 | head -1)
[ -z "$WBYTES" ] && sleep 5 && continue
WMBPS=$((WBYTES / 1024 / 1024))
if [ $WMBPS -gt 100 ]; then
echo "[kill] Codex IO 写入 ${WMBPS} MB/s 超限,自动 kill"
pkill -f "codex"
break
fi
sleep 5
done
EOF
坑 8:Snapshot rollback 后 Agent 配置丢失 / secret 泄漏
症状:rollback snapshot 到 5 分钟前,Agent 的 API key / OAuth token / 配置全没了——必须重新登录。
规避:
- Agent 配置 / secret 不在 subvolume 里——单独目录
~/.agents-config/用pass/gopass/1Password CLI管理 - subvolume 只包含 agent work data(代码 + log + workspace)
- rollback 时精确指定要回滚的目录(不要 rollback 整个 home):
sudo rsync -a /var/agents/codex-home-rollback/home/agent/work/ ~/work/
# 只回滚 ~/work,不回滚 ~/.codex/config.toml / ~/.codex/auth.json
坑 9:忽略 SQLite 的 auto_vacuum 配置
症状:WAL checkpoint + DELETE 老行后,logs_2.sqlite 文件大小不缩小——SQLite 默认不会自动回收空间。
规避:
- 手动 VACUUM:
sqlite3 ~/.codex/logs_2.sqlite 'VACUUM;'(耗时长但回收空间) - 启用 auto_vacuum=INCREMENTAL:
sqlite3 ~/.codex/logs_2.sqlite 'PRAGMA auto_vacuum=INCREMENTAL; PRAGMA incremental_vacuum;'(每页 free 标记为可复用) - 定期手动 VACUUM(cron 每周一次 + checkpoint 后)
坑 10:单一 snapshot 备份不够(勒索软件 + 本机硬盘损坏)
症状:btrfs snapshot 在本机,单盘损坏后 snapshot 也损坏——勒索软件加密 + 硬盘烧毁 = 数据全部丢失。
规避:
- btrfs send/receive 到远程:
btrfs send /var/agents/.snapshots/codex-home-latest | ssh backup@nas "btrfs receive /backup/agents/.snapshots/codex-home-latest" - zfs send 到远程:
zfs send agents/codex-home@auto-snapshot | ssh backup@nas "zfs receive backup/codex-home" - 3-2-1 备份:3 份拷贝 / 2 种介质 / 1 份异地——本机 + NAS + 冷备份(offline 硬盘)
- 定期 restore drill:每月从远程 snapshot restore 一次验证可用
坑 11:macOS / Windows 上没有等价工具链
症状:macOS 没有 chattr +i(用 chflags uimmutable 等价)、Windows 没有 btrfs、macOS 没有 systemd-run。
规避:
- macOS 工具链:
chflags uimmutable+ APFS snapshot +sandbox-exec+ Docker - Windows 工具链:
Set-FileProperty -Name IsReadOnly -Value $true $path+ VSS shadow copy + Windows Sandbox + WSL2 - 跨平台一致性:优先用 Docker 容器跑 Coding Agent(隔离 + resource cap + snapshot 三层都好用)
- 重要:macOS Time Machine + APFS 本地 snapshot 是 30 分钟-1 小时粒度,不是 5 分钟粒度——
/goal模式 30 分钟内删文件可以回滚,5 分钟内删文件恢复困难
坑 12:忽略 Coding Agent 子进程的资源消耗
症状:systemd-run --scope -p MemoryMax=4G codex 启动 Codex,但 Codex fork 出的 git / npm / python 子进程不受 cap 限制,吃满 32 GB 内存。
规避:
- cgroup v2 自动包含整个进程树——
systemd-run --scope是 cgroup 范围,fork 的子进程自动继承 - 验证子进程在 cgroup 内:
CGROUP=$(find /sys/fs/cgroup/user.slice -name "*codex*" -type d | head -1)
for pid in $(pgrep -f codex); do
pid_cgroup=$(cat /proc/$pid/cgroup | head -1 | cut -d: -f3)
echo "codex pid=$pid cgroup=$pid_cgroup"
done
# 所有 codex 相关 pid 的 cgroup 应该都包含 codex
- 不用 systemd-run 而是
systemd-run --unit——更彻底隔离:
systemd-run --unit=codex-temp --scope \
-p MemoryMax=4G -p CPUQuota=200% \
codex "$@"
成本/性能/维护权衡
性能开销(实测,2026 年 6 月)
| 防护层 | 性能开销 | 实测数据 |
|---|---|---|
| btrfs snapshot 每天 1 次 | < 5 秒(30 GB subvolume) | snapshot 创建延迟 < 1 秒 |
| btrfs rollback | < 1 分钟(30 GB 全量 rollback) | rsync 增量 rollback < 30 秒 |
| zfs snapshot 每小时 1 次 | < 2 秒 | send/receive 增量 < 100 ms |
| chattr +a (append-only) | < 1% 写性能影响 | SQLite WAL append 几乎无差异 |
| chattr +i (immutable) | 0% 写性能影响(写入直接 EPERM) | 0 写入 |
| SQLite WAL checkpoint 每 5 分钟 | < 1 秒 | TRUNCATE checkpoint ~200ms / GB |
| systemd-run MemoryMax=4G | 0% 性能影响(只是硬上限) | Agent 在 < 4 GB 时无开销 |
| systemd-run IOWriteBandwidthMax=50M | ~5-15% 性能影响(NVMe 顺序写从 3 GB/s → 50 MB/s) | SQLite WAL 写从 ~500 MB/s → 50 MB/s |
| systemd-run CPUQuota=200% | 0-5% 性能影响(agent CPU 利用率 < 200%) | 大部分时间 CPU < 100% |
| bubblewrap unshare-pid + unshare-net | ~1-3% syscall 开销 | ls / rm / curl 延迟 +1-3ms |
| firejail seccomp | ~5-10% syscall 开销(受 seccomp.filter 影响) | 进程 fork +3-8ms |
关键权衡:
IOWriteBandwidthMax=50M对 Codex 影响最大——SQLite WAL 频繁写入会被限速,导致 Agent 响应慢;建议先100M然后根据实际调优到50Mbubblewrap unshare-net让 Agent 无法访问 OpenAI API——必须在 sandbox 外用 socat 转发(复杂);或--share-net但配 seccomp 限制网络 syscallMemoryMax=4G对 Claude Code / Cursor 等大内存 agent 太低——建议 Claude Code = 6G / Cursor = 8G
维护成本
| 组件 | 维护频率 | 维护成本(人时 / 月) | 自动化程度 |
|---|---|---|---|
| btrfs/zfs snapshot | cron 自动 + 季度 drill | 1-2 小时 | 高(cron + send/receive) |
| chattr +a immutable | 加 log 路径时一次 + Agent 更新时重设 | 0.5-1 小时 | 中(脚本化) |
| WAL checkpoint truncate | cron 每 5 分钟 | 0.5 小时(看日志) | 高(python 脚本 + crontab) |
| systemd-run resource cap | Agent 版本变更时调整 | 1-2 小时 | 中(profile 脚本化) |
| bubblewrap/firejail profile | Agent 新增 syscall / 网络需求时 | 2-4 小时 | 低(手动调 profile) |
| 三层防护 SOP 更新 | 季度 + Agent 大版本 | 1-2 小时 | 低(手动更新 wiki) |
| 远程 snapshot 备份 | 每天自动 + 每月 restore drill | 2-4 小时 | 中(send/receive + cron) |
| 总计 | — | 8-16 小时 / 月 | — |
自动化建议:
- 用
btrfs send/receive或zfs send把 snapshot 异地备份(NAS / S3 / 离线硬盘) - WAL checkpoint truncate 脚本 + crontab 全自动
- systemd-run profile 进 git,每次 Agent 版本变更时 PR review
- 每月一次 restore drill 验证远程 snapshot 可用
成本对比(per 工程师 / 月,2026 年 6 月)
| 方案 | 一次性成本 | 月度维护 | 故障成本(SSD 损坏) | 适用场景 |
|---|---|---|---|---|
| 无防护 | $0 | $0 | $500-2000(数据丢失 + 换 SSD) | 个人 demo / 一次性任务 |
| 仅 snapshot(btrfs + 远程 send) | $0 | $5(NAS 存储) | $0-100(rollback 即可) | 个人开发者 |
| snapshot + immutable log | $0 | $5 + 0.5 小时 | $0-50 | 团队 Coding Agent |
| snapshot + immutable + resource cap | $0 | $5 + 1 小时 | $0-20 | 团队生产 |
| 四件套 + bubblewrap sandbox | $0 | $5 + 2-4 小时 | $0 | 企业生产 / 内网 |
| 四件套 + 远程异地备份 + DR drill | $50(NAS) | $10 + 4-6 小时 | $0 | 关键业务 |
推荐组合(个人 / 小团队 / 企业):
- 个人开发者:snapshot + chattr +a + WAL truncate(0 成本 / 0.5 小时 / 月)
- 小团队(5-20 人):四件套 + systemd-run + 远程 NAS snapshot($10 / 月 / 团队 / 1-2 小时 / 月)
- 企业生产:四件套 + bubblewrap + SIEM 接入 + 季度 DR drill($50-200 / 月 / 企业 / 4-8 小时 / 月)
一周内可执行行动清单
D+0(今天,3 小时)
- 跑 SSD endurance audit:
smartctl -A /dev/nvme0n1 | grep -iE 'Data Units Written|Total LBAs Written'查累计写入 TB 数 - 跑 SQLite log 审计:
ls -la ~/.codex/logs_2.sqlite* ~/.claude/logs* ~/.cursor/logs*查 Coding Agent 进程是否在本地写 SQLite log - 算 SQLite 写放大:
sqlite3 ~/.codex/logs_2.sqlite 'SELECT COUNT(*) FROM feedback; SELECT seq FROM sqlite_sequence WHERE name="feedback";'对比主帖 10,000× 系数 - 算本机 SSD endurance 剩余比例:640 TB/year × 本机已使用天数 / 365 → > 50% 立即备份 + 准备换 SSD
- 跑
/goal模式测试:在隔离环境用 Codex/goal "delete temporary files"验证是否真的会删文件 - 输出「AI Coding Agent SSD endurance audit 报告 v0.1」+「需要换 SSD 的本机清单」
D+1(明天,3 小时)
- 检查 filesystem:
stat -f ~/.codex/看是 ext4 / xfs / btrfs / overlayfs / 9p - 检查内核:
uname -r≥ 5.8 +cat /sys/fs/cgroup/cgroup.controllers含iocontroller - 建 btrfs subvolume 或 zfs dataset 给 Agent 工作目录
- 装 btrfs-snapshot cron / zfs-auto-snapshot
- 验证 snapshot 创建 + rollback 成功(用 dummy 文件测试)
- 跑 send/receive 到远程 NAS(如果有)
D+2(第 3 天,2 小时)
- 给 Coding Agent 的 SQLite log 路径加
chattr +a(append-only) - macOS 用
chflags uimmutable等价 - 验证 SQLite 写 log 不被阻止(agent 启动 + 写一条 log → log 文件 size 增加)
- 验证
rmlog 失败:报 Operation not permitted - 写 WAL checkpoint truncate 脚本 + crontab 每 5 分钟
- 验证 SQLite WAL 文件 (-wal) checkpoint 后 truncate 到 0 字节
D+3(第 4 天,2 小时)
- 写 systemd-run resource cap profile(IOWriteBandwidthMax=50M / MemoryMax=4G / CPUQuota=200%)
- macOS 写 Docker 等价 profile(—cpus —memory —device-write-bps)
- 启动 Codex + systemd-run + 验证 cgroup v2 IO/Memory/CPU cap 生效
- 跑 IO 撑爆测试:
dd if=/dev/zero of=/tmp/testfile bs=1M count=10000 oflag=direct看是否被 cap - 装 IO watchdog 脚本(超限自动 kill)
D+4(第 5 天,3 小时)
- 装 bubblewrap 或 firejail(按 Linux 发行版选)
- 写 Codex 的 bubblewrap profile(只读挂载 + unshare-pid + unshare-net + cap-drop ALL)
- 写 Codex 的 firejail profile(白名单 + seccomp + netfilter + rlimit)
- 验证 sandbox 隔离:
rm -rf /失败 +curl evil.com失败 + Agent 仍能调 OpenAI API(用 socat 转发) - 验证 sandbox 内 Agent 工作目录可写(
--bind ~/work /home/agent/work)
D+5(第 6 天,2 小时)
- 综合演练 1:创建 test file → rm → btrfs snapshot rollback → file 恢复
- 综合演练 2:模拟
/goal模式删文件 → immutable log + sandbox + rollback 三层全拦截 - 综合演练 3:跑
dd if=/dev/zero of=/tmp/testfile bs=1M count=10000→ IOWriteBandwidthMax 限速到 50 MB/s - 综合演练 4:跑
codex-cli 0.141.0(macOS) → 看 SQLite log layer 是否仍以 TRACE 挂载(未 rollout 修复 = 默认不安全) - 记录每条链路延迟 + 成功率,调整 IO/Memory/CPU cap 参数
D+6(第 7 天,4 小时)
- 写「Coding Agent 进程三层防护 SOP v1.0」到内部 wiki / Notion
- 包含所有命令 + 应急联系 + rollback 操作手册 + chattr +a 解除方法 + systemd-run 调整方法
- 装「AI Agent 资源事故 watch」每日 15 分钟订阅(GitHub / HN / The Decoder)
- 给 VP Eng / CISO 发 walkthrough 邮件,附 SSD audit 报告 + SOP 链接 + 风险评估
D+7(本周结束)
- 产出**「Coding Agent 进程三层防护模板 v1.0 + btrfs/zfs snapshot 脚本 + systemd-run profile + bubblewrap/firejail sandbox 配置 + 30/90 天路线图」**
- 给团队做 30 分钟 walkthrough + 内部 demo
- 提交 PR 到内部 wiki / Notion / GitOps repo
- 设定月度复盘节奏(每月 1 号跑一次 SSD audit + restore drill + Agent 资源事故 watch)
30 天路线图(Q3 2026)
- Week 2:把三层防护接入 Ansible / Terraform / Pulumi,企业 IT 可以批量部署
- Week 3:把 SSD endurance 监控接入 Prometheus + Grafana,写「Agent 资源消耗实时 dashboard」
- Week 4:评估是否上云端 snapshot 备份(AWS EBS snapshot / GCP persistent disk snapshot / Azure disk snapshot)
- Day 30:跑月度复盘,看本机 SSD endurance 趋势 + Agent 资源消耗统计 + 0 资源事故目标
90 天路线图(Q4 2026)
- Week 5-8:评估 Repurposed Agent Watchdog(RepAW) 等开源工具,把 watchdog + resource cap + sandbox 三层串成统一平台
- Week 9-12:跟踪 openai/codex#28879 rate-limit + openai/codex#28224 SSD endurance + Cursor / Windsurf / Claude Code 同类 issue,把三层防护 SOP 同步给所有用 Coding Agent 的工程师
- Day 90:Q4 复盘,对比 6/23 的三层防护 vs 现状,迭代 v2.0 + 把 SOP 推广到全公司
待观察
- openai/codex#28224 的 PR #29432 + #29457 是否在 codex-cli 0.142.0 / 0.143.0 macOS + Windows + Linux 三平台 lockstep rollout? 主帖 6/22 22:23 UTC closed via 2 PRs,用户 @prodan-s 6/20 报:codex-cli 0.141.0 macOS 上 SQLite log layer 仍以 TRACE 挂载。关键未确认:6 月 23-30 日 OpenAI 是否发布 codex-cli 0.142.0 changelog 明确「SQLite log layer 默认 filter noisy target」+ 三平台 release notes lockstep;
brew upgrade codex之后本机~/.codex/logs_2.sqlite是否停止 1000× 写放大。 - **openai/codex#28879 rate-limit 357 reactions / OpenAI 9 天 + counting 0 回应 vs openai/codex#28224 SSD endurance 352 reactions / OpenAI 8 天 2 PR 修复 同周同产品双 issue 的「OpenAI 优先级排序 = 用户硬件 > 用户钱包」**是否在 7-8 月 IPO 招股书披露?
- Anthropic Claude Code 是否在 6 月 23-30 日公开承认「default-on TRACE log layer」同类 attack surface? HN 6/22 282 分「The text in Claude Code’s Extended Thinking output」 是否暗示 Claude Code 也有 SQLite log 写放大问题?
- Cursor / Windsurf / JetBrains AI / Tabnine / Aider / Cline / Continue.dev 是否在 6 月 23-30 日公开承认「Coding Agent 默认 log layer」 + 「auto-cleanup 行为」同类 attack surface 并发 patch?
- Trail of Bits / NCC / Cure53 / Microsoft Security 是否在 6 月底前发布《AI Coding Agent 框架资源消耗审计报告》+《Agent auto-cleanup 风险评估》?
- bubblewrap / firejail / Docker / Podman / Kubernetes 是否在 6 月 23-30 日针对 Coding Agent 场景发布官方 resource cap 模板 / sandbox profile?
- 企业 Coding Agent 采购 SLA 是否开始包含「SSD endurance SLA = 90 天 production 资源消耗报告必须 < 本机 SSD TBW 的 10%」+「auto-cleanup 行为 allowlist」+「PR 合并到用户本机升级的 SLA ≤ 72h」3 项硬条款?
本文为每日技术热点落地文。事件核心事实(openai/codex#28224 主帖证据:21 天累计 37 TB 写入、SQLite AUTOINCREMENT 5,543,677,486 vs 保留 506,149 行 = 10,000× 写放大、外推到 640 TB/year、PR #12969(2025/9)引入 SQLite feedback log sink at TRACE level、PR #29432 + PR #29457 6/22 15:43 + 16:17 UTC 合并、issue 6/22 22:23 closed、codex-cli 0.141.0 macOS 仍未 rollout 修复、ZenulAbidin 报 /goal 模式主动删除文件腾空间)均来自 openai/codex#28224 GitHub issue + PR #29432 + PR #29457 + HN Algolia 6/22 07:30 item 48626930 469 分 的交叉印证。关联事件(Anthropic 估值 1 万亿 Series H 650 亿(The Decoder 6/22)、Microsoft Copilot Cowork usage-based billing(The Decoder 6/22) + [昨天文章 openai/codex#28879 rate-limit 357 reactions + AutoJack 零信任沙箱 6/21)作为同一 24-48 小时窗口内的强相关信号列出。所有命令片段(chattr +a、systemd-run --scope -p IOWriteBandwidthMax、btrfs subvolume snapshot、sqlite3 'PRAGMA wal_checkpoint(TRUNCATE)')均来自 Linux man pages + systemd 文档 + btrfs wiki + SQLite 文档,未独立验证在你的内核版本 / filesystem / hardware 环境下的实际表现。OpenAI 官方对 openai/codex#28879 0 回应的状态截至 2026-06-22 23:00 UTC + openai/codex#28224 closed via 2 PRs 截至 2026-06-22 22:23 UTC,后续变化需独立确认。