| Postgres 每日 pg_dump + 恢复演练 | R10 拆解第 2 条 / deploy-cn-lightweight.md §5 | 不做 | 无兜底,风险显式留下:docs/deploy-environments.md 第 7 条与 §5 里「涉及不可逆迁移时先恢复备份」成为悬空引用——真遇到不可逆迁移出错时没有可恢复的备份。记 BACKLOG,R11 上线前须再裁定 |
| Caddy 安全响应头 | 本轮扫描新发现(不在 R10 拆解内) | 不做,记 BACKLOG | deploy/Caddyfile 与 apps/web/next.config.ts 当前一个安全响应头都没有(nosniff / Referrer-Policy / X-Frame-Options 全缺)。属新增约束,按规则 8/9 需所有者裁定放哪轮 |
| /api/mcp IP 白名单 | 检查单第 9 条尾 / R10 拆解第 3 条(标「可选」) | 本轮不启用 | 130 是内网预发,源 IP 同网段,白名单在这里没有验证价值。本轮只核对 deploy/Caddyfile 模板语法与文档一致,把「生产按真实出口 IP 启用」写进 R11 前置。既有防线不变:静态 bearer token + 审计 |
逐项对应 docs/deploy-cn-lightweight.md §6。全部在 130 上针对 SHA 5c98b3e 实跑;第 1 项在本机仓库跑。
| # | 检查 | 命令 / 期望 |
|---|---|---|
| 1 | gitleaks 无密钥 | docker run --rm -v <repo>:/repo zricethezav/gitleaks dir /repo 与 ... git /repo(含历史)双跑 → 0 leaks |
| 2a | .env 权限 600 | 130 上 stat -c '%a %U:%G' ~/deploy/.env → 600 且属主为部署用户 |
| 2b | 明文 key 不落镜像 | docker compose config 里的密钥值来自 .env 运行期注入;docker inspect 镜像层与 docker history 无明文 key;api 容器 env 里的 key 不出现在任一镜像 |
| 3 | api/web 容器约束 | docker inspect:User=10001:10001、ReadonlyRootfs=true、CapDrop=[ALL]、PidsLimit、Memory、no-new-privileges、tmpfs noexec;无 docker.sock 挂载(全容器逐个核) |
| 4 | 最终运行镜像无 Node.js | 按 CLAUDE.md 规则 11 的正确判据:node -p "process.versions.bun" 有值 + /usr/bin/node·/usr/local/bin/node 不存在 + dpkg -l 无 nodejs 包(api 与 web 两个镜像) |
| 5 | 已删服务 404 | /api/spike/mem → 404;/admin → 404 |
| 6 | IMAGE_TAG 可追溯 | .env 的 IMAGE_TAG = git SHA(非 latest);该 SHA 在 main 上存在;运行中容器的镜像 tag 与之一致 |
| 7 | 迁移可追溯 | ./migrate.sh --status → 「已是最新」且报得出版本号;schema_migrations 与镜像内 SQL 版本一致;空库直起的 500 窗口由「先迁移后起服务」顺序消除(文档条款核对) |
| 8 | 网络分段 | 从 web / caddy 容器 getent hosts postgres → NXDOMAIN 且 nc -z postgres 5432 不通;api 可通 |
| 9 | MCP 认证与审计 | 无 token / 错 token / GET → 一律 401 且 mcp_audit 各留一条 denied;带 token 的 server/discover 正常 |
| 10 | SSE 脱敏 | POST /agent/ask 与 GET /trace/stream 原始字节中 authorization / api-key / apikey / bearer / x-api-key / 明文 key / key 后 8 位 全 0 命中;before_provider_headers 帧只剩 type |
| 11 | SSE 优雅关闭 | docker compose stop api 时客户端明确断流(curl exit 18)而非静默挂起;up -d 后可恢复 |
| 12 | 所有者裁定不重跑,引 R9 smoke.md §5 | |
| 13 | N/A 本轮:ICP 备案在 R11(deploy-cn-lightweight.md §1),预发不备案 |
收口标准:1–11 全绿。任一项不过 → 当轮整改并重验;同一项针对性整改后连续 2 次仍不过 → 写 rounds/round-10/BLOCKED.md 停下呼人。
⚠️ 上表是开工时抄自 docs/ 的原始判据,其中 4/9/10/11 四条实跑后证明会误判(见「本轮实测」 偏离 2),docs/ 已就地改准。要照着核请用 docs/deploy-cn-lightweight.md §6 的现行版本, 别用这张表。这里原样留着,是为了让「判据被改了什么」有个对照。
同一验收项针对性整改后连续 2 次验证仍不过 → 写 rounds/round-10/BLOCKED.md,停下呼人。禁止放宽验收标准自我通过。
逐项证据在 checklist.md。这里只记结论与偏离。
| # | 检查 | 结果 |
|---|---|---|
| 1 | gitleaks | ✅ dir 与 git(72 commits)双 no leaks found |
| 2a | .env 600 | ✅ 600 chenkun:chenkun |
| 2b | 明文 key 不落镜像 | ✅ 4 个密钥值在两个镜像的层历史 + Config 中命中 0 |
| 3 | 容器约束 | ✅ 全项达标;全机无容器挂 docker.sock |
| 4 | 镜像无 Node.js | ✅ 三条判据在 api/web 均成立 |
| 5 | 已删服务 404 | ✅ /api/spike/*·/admin* 全 404,对照组全 200 |
| 6 | IMAGE_TAG | ✅ 5c98b3e,在 main 上;main 顶端只多一个纯 .md 提交 |
| 7 | 迁移可追溯 | ✅ 版本 6 / 无待执行 / dirty=f / 14 表 |
| 8 | 网络分段 | ✅ 域名 NXDOMAIN 且按 IP 也不通;back internal=true |
| 9 | MCP 认证审计 | ✅ 四种未授权全 401 且响应体一致;5 条 denied 审计;24 工具 |
| 10 | SSE 脱敏 | ✅ 60 帧结构化扫描 0 个凭据形状的键 |
| 11 | SSE 优雅关闭 | ✅ 停机 +0s 终止,恢复 2s |
| 12 | 限额演练 | ⏭ 所有者裁定不重跑,引 R9 smoke.md §5 |
| 13 | 备案号 footer | N/A —— R11 |
多出一个非文档产出 .gitleaks.toml(计划里写的是「代码/配置改动预期为 0」)。 起因是第 1 项裸跑报 15 条(dir)/ 7 条(git),逐条看完全部是构建产物与刻意写成 假密钥的测试夹具——0 条真泄漏。但「每次跑都报 15 条、要人眼过一遍」正是真泄漏藏得住的地方, 这项也就没有可证伪的期望值。所以把判据写成配置:路径排除构建产物与 gitignored 的本地密钥文件, 假夹具按具体的值放行。生效后期望值是 0,且 dir 从 169 MB/95s 降到 1.46 MB/1.6s。
这个配置的第一版是错的,是探针查出来的。 「变绿」本身不构成证据——它同样可能只是把报警 关掉了。所以往三处各插了一行新的真实形状 key 做证伪:第一版写的 paths + regexes + condition = "AND" 下,仓库根的探针抓到了,而插进 mcp.test.ts 与 events.ts 的两个探针 全部漏报 —— condition 没有按预期收紧,路径一命中就整文件放行,而这两个文件恰恰是全仓库 最容易出现密钥形状字符串的地方。改成只按值放行(默认 regexTarget = 检出的 secret,^…$ 全串锚定)后三个探针全中,干净仓库仍是 no leaks found;探针已还原,apps/ 无残留改动。
本轮的实际价值是「修判据」而不是「打勾」:5 条发现里 3 条是检查单自身写得会误判 —— ①第 4 条的 node --version 应失败 会把人引向反面(bun 的 node 兼容层不支持单独 --version, 报错却写着 Node.js-compatible REPL);②「GET 一律 401」漏限定,带正确 token 的 GET 是 405; ③「SSE 优雅关闭」钉死 curl exit 18,而本轮实测 0(要判的是「停机同刻终止」,不是某个码)。 三条已就地改进 docs/,并给检查单补了留证指针。另外两条(第 10 项要用结构化判据而不是 grep -i authorization;第 5 项必须带正式端点对照组)也写进了条目里。
两条加固被所有者裁定出本轮(2026-09-01):全站无安全响应头、130 上的明文 .llm-key。 后者扩散面已查清(~/deploy 其余文件 / /tmp / ~/.bash_history 全 0 命中,库里是 79 字节密文 = 12+51+16,与 security.md §3 的布局吻合),没有当场删 —— 删了下次重写 provider 得回 provider 控制台重取,那是所有者的东西。两条均记 BACKLOG 并写进 R11 前置。