post cover

技术热点落地:Codex 每天烧穿 1 TB SSD——Coding Agent 进程「snapshot + immutable log + resource cap」三层防护落地,1 周把 4 个 CWE 关联攻击面堵死(2026-06-23)


适用场景与目标

过去 24 小时的最强信号(与 6/23 AI 快报 Codex 烧 SSD 完整证据链 呼应):

6/18 + 6/19 + 6/20 + 6/21 + 6/22 + 6/23 的工程化推论

时间信号工程化产物
6/18AutoJack localhost 攻击链「进程零信任沙箱」必须装6/21 文章
6/19MCP EMA stable「怎么治协议」6/19 文章
6/20Mcp2cli + Context Mode + Prompt Caching 三件套「怎么省 token」6/20 文章
6/21AutoGen Studio 4 CWE 堵死「localhost 信任边界破产」
6/22Codex 烧 SSD + /goal 删文件「本机 SSD endurance audit 必须做」
6/23codex-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

核心目标(一周)

  1. D+0(今天,3 小时):跑本机 SSD endurance audit——smartctl 查累计写入 TB 数 + ls ~/.codex/logs_2.sqlite* ~/.claude/logs* ~/.cursor/logs* 查 Coding Agent 进程是否在本地写 SQLite log
  2. D+1:给 Agent 工作目录装 btrfs subvolume + zfs filesystem + 每天 snapshot——30 秒快照 + 5 分钟 rollback = Agent 删错文件秒回滚
  3. D+2:给 Agent log 路径加 chattr +i immutable + WAL 自动 checkpoint 截断——Agent 不能删自己的 log,即使 /goal 模式也不会清理
  4. D+3:用 systemd-run —scope -p IOReadBandwidthMax / IOWriteBandwidthMax / MemoryMax / CPUQuota 给 Agent 进程装 resource cap——硬上限 + 超限自动 kill
  5. D+4:给 Agent 跑在 bubblewrap / firejail / Docker —security-opt sandbox——独立 mount namespace + 文件系统只读 + 网络白名单(参考 6/21 AutoJack 零信任沙箱文章
  6. D+5:复现 /goal 模式删文件 PoC + 验证四件套拦截(snapshot 可回滚 + immutable 阻止删除 + resource cap 限制写入带宽 + sandbox 隔离文件系统)
  7. D+6:写 「Coding Agent 进程三层防护 SOP」 + 「Agent 资源事故 watch」 每日 15 分钟订阅
  8. 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.confzfs_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 用 NTFS Set-FileProperty -Name IsReadOnly -Value $true $path
  • chattr +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.controllersio controller
  • IOWriteBandwidthMax 单位是字节/秒,写成 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 +ioverlayfs / 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 foundFailed 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 Podresources.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 attributechattr +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 正在写。

规避

  • 加 retryfor i in 1 2 3; do sqlite3 "$db" 'PRAGMA wal_checkpoint(TRUNCATE);' && break || sleep 1; done
  • PRAGMA busy_timeoutsqlite3 "$db" 'PRAGMA busy_timeout=5000; PRAGMA wal_checkpoint(TRUNCATE);'
  • 改用 passive checkpointPRAGMA 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 默认不会自动回收空间。

规避

  • 手动 VACUUMsqlite3 ~/.codex/logs_2.sqlite 'VACUUM;'(耗时长但回收空间)
  • 启用 auto_vacuum=INCREMENTALsqlite3 ~/.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=4G0% 性能影响(只是硬上限)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 然后根据实际调优到 50M
  • bubblewrap unshare-net 让 Agent 无法访问 OpenAI API——必须在 sandbox 外用 socat 转发(复杂);或 --share-net 但配 seccomp 限制网络 syscall
  • MemoryMax=4G 对 Claude Code / Cursor 等大内存 agent 太低——建议 Claude Code = 6G / Cursor = 8G

维护成本

组件维护频率维护成本(人时 / 月)自动化程度
btrfs/zfs snapshotcron 自动 + 季度 drill1-2 小时高(cron + send/receive)
chattr +a immutable加 log 路径时一次 + Agent 更新时重设0.5-1 小时中(脚本化)
WAL checkpoint truncatecron 每 5 分钟0.5 小时(看日志)高(python 脚本 + crontab)
systemd-run resource capAgent 版本变更时调整1-2 小时中(profile 脚本化)
bubblewrap/firejail profileAgent 新增 syscall / 网络需求时2-4 小时低(手动调 profile)
三层防护 SOP 更新季度 + Agent 大版本1-2 小时低(手动更新 wiki)
远程 snapshot 备份每天自动 + 每月 restore drill2-4 小时中(send/receive + cron)
总计8-16 小时 / 月

自动化建议

  • btrfs send/receivezfs 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.controllersio controller
  • 建 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 增加)
  • 验证 rm log 失败:报 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)


待观察

  • 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 +asystemd-run --scope -p IOWriteBandwidthMaxbtrfs subvolume snapshotsqlite3 '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,后续变化需独立确认。