记录(08-23-isolated-backup-restore-drill): 固化Attempt 4执行前门禁

这个提交包含在:
2026-08-25 13:20:45 +08:00
父节点 5ec7db13b2
当前提交 f216387837
共修改 3 个文件,包含 46 行新增和 1 行删除
@@ -1374,6 +1374,10 @@ validate_copied_batch(private/batch, source_metadata)
start, dump list, target confirmation, restore apply and storage restore each
append a fixed stage marker and their private output, so a later failure does
not erase earlier-stage diagnostics before final teardown.
- A source migration fingerprint enumerates only direct directory objects under
`server/prisma/migrations` at the source commit, validates every directory
name, sorts the names and hashes that exact non-empty set. Files such as
`migration_lock.toml` are not migrations and must never enter the fingerprint.
### 4. Validation & Error Matrix
@@ -1398,6 +1402,9 @@ validate_copied_batch(private/batch, source_metadata)
remains valid for a locally protected render.
- Any raw-log truncating redirect after initialization, or a missing fixed stage
marker -> tracked contract failure; do not publish a candidate.
- A source-tree listing that mixes migration directories with ordinary files ->
reject the generator result or filter by Git directory object type before
hashing; never reinterpret the extra file as schema drift.
- Candidate differs from the deterministic render or has not passed the tracked
contract -> do not upload or install it.
@@ -1436,6 +1443,9 @@ validate_copied_batch(private/batch, source_metadata)
- Statically require exactly one raw-log truncation at initialization and fixed
append markers for container start, dump list, target confirmation, restore
apply and storage restore.
- Build a source-tree fixture containing migration directories plus
`migration_lock.toml`; assert the fingerprint includes only sorted directory
names and still matches the restored successful migration set.
- Directly test source/copy identity, dynamic migration fingerprint and the
tracked attachment validator. Run `check-sensitive-content.mjs` explicitly on
all three tracked runner assets and require zero findings.
@@ -106,7 +106,8 @@
- [x] `.gitignore` 增加 `/.restore-drill-private/` 专用目录;合同分别证明仓库内未忽略的私有 JSON、未忽略的现场候选均在创建输出前失败,ignored 输入/输出正例通过。
- [x] 私有原始日志保留唯一初始化截断,五个固定阶段均以标记分隔并追加写;静态合同拒绝后续阶段再次截断。
- [x] 完整复跑 runner 合同、既有隔离备份/恢复演练和自动异机备份 74 项;task、Trellis、process、默认/定向敏感扫描及空白门禁通过,测试容器和本地私有路径残留均为 `0`。
- [ ] Attempt 4 候选尚未渲染或上传;实际恢复前须再次选择最新批次并取得明确批准。
- [x] Attempt 4 最新批次只读探针重新执行并通过;候选已由提交 `5ec7db1` 的跟踪模板确定性渲染,完整合同、依赖钉住和 SHA-256 复核通过。
- [ ] Attempt 4 候选尚未上传或安装;实际恢复须在本次探针和候选证据审查后另行取得明确批准。
## 验证命令类别
@@ -291,3 +291,37 @@ Attempt 4 的 runner 产生过程已从个人 workspace 人工产物改为“跟
- 本轮新增门禁回归全部 `PASS`;完成完整质量门禁并形成可追溯 Git 提交前,仍不得准备或上传 Attempt 4 候选。
完整本地门禁随后通过:runner 合同全部 `PASS`,既有隔离备份/恢复合成演练 `PASS`,自动异机备份合同 `74/74 PASS`;task validate、Trellis governance、process baseline、默认敏感扫描和三个新增文件定向敏感扫描均 `PASS`。文档审计错误 `0`,仅保留既有未登记文件 warning;`shellcheck` 在本机不可用,已以 Bash 语法、真实双路径集成回归和仓库合同覆盖。测试容器、本地私有渲染目录及候选残留均为 `0`。
## Attempt 4 环境差异预先裁决规则
本节在 Attempt 4 新批次探针和实际恢复之前追加,不能按执行结果事后改写。
- Attempt 2 的源/副本身份重绑和 Attempt 3 的三阶段诊断已经由提交 `5ec7db1` 下的可复跑合同机械把关;合同失败时不得生成或上传候选。
- 若同一提交的合同、候选 SHA-256 和 ARM 安装前摘要均通过,但 Attempt 4 再次在恢复完成前暴露演练器侧失败,则默认 finding 升级为“本地合同环境与 ARM 实际执行环境存在系统性差异”,不再直接归为又一个孤立 runner 缺陷。
- 后续调查必须先形成脱敏环境差异矩阵,至少比较 Docker/Podman 实现与版本、PostgreSQL 16 镜像摘要和工具版本、shell/coreutils/openssl/python 行为、文件系统与权限/SELinux/AppArmor、可用 PATH、恢复脚本及依赖摘要、网络模式和资源约束。未取得差异证据前,不继续逐点放宽或修补 runner。
- 该规则不把任何失败预判为 ARM 环境问题,也不改变备份内容判定。若阶段诊断明确证明 dump、数据库对象、migration 或附件内容不满足既有合同,仍按对应数据恢复 finding 如实分类。
## 2026-08-25 Attempt 4 执行前最终探针与候选
本节仅追加最新批次只读探针、候选本地渲染与合同结果;未上传或安装恢复候选,未执行 Attempt 4 实际恢复,未写腾讯云生产或 ARM 正式归档。
| 检查项 | 结果 |
| --- | --- |
| ARM 最新正式批次探针 | `PASS`;动态重选后仍为同一最新批次 |
| 最新批次构建短标识 | `7b86ffb3` |
| 来源与当前生产构建关系 | `SAME` |
| 批次年龄 | `38572` 秒,约 10 小时 43 分,`within_24h=yes` |
| run id 与目录配对 | `PASS` |
| DB/附件大小与 SHA-256 | `PASS` |
| source image digest | 存在 |
| manifest 脱敏摘要前缀 | `ee1f97a5b42d` |
| 探针临时 root 入口/sudoers 残留 | `0/0` |
| 普通用户探针暂存 | 再次通过 SHA 清单后逐一删除,残留 `0` |
| ARM dead-man/健康 timer | `active/active` |
| 来源/当前 migration 目录 | `65/65`,差异条目 `0` |
候选由提交 `5ec7db1` 的 `scripts/qa/offhost-shadow-restore-runner.template.sh` 和 ignored 私有 JSON 确定性渲染。私有 JSON 权限为 `0600`、精确 20 个字段,runner 权限为 `0700`,输入与输出均命中仓库根锚定 ignore。两次独立渲染的字节和 SHA-256 完全一致;候选 SHA-256 为 `81f4eca2cf173196e1a57b781d28629412de7b7fe1a09b001b02d2025950391c`,合同报告值与本地 `sha256sum` 重算一致。
完整 runner 合同再次全部 `PASS`:源/副本身份、三条身份负例、dynamic migration、附件安全、五阶段追加日志、失败先诊断后清理、真实 `restore-db.sh` Docker stdin/host-file 双路径、退出码和敏感输出边界均通过。私有候选包共 6 个文件(runner、附件校验器、两份现有恢复脚本、sudoers、SHA 清单),包内 SHA 清单复核 `PASS`;runner 钉住的三份依赖摘要全部匹配,sudoers 固定命令与 runner 自身路径一致,`scripts/restore-db.sh` 相对生产构建仍无字节漂移,本地测试容器残留 `0`。
准备过程有一次安全失败:首次来源 migration 枚举误把 `migration_lock.toml` 当作 migration 名称,现场显示 `66/65`。该错误发生在候选渲染前,没有产生候选;随后改为只读取来源提交 `server/prisma/migrations` 树下的目录对象,并与当前工作树目录集合独立比较,结果为 `65/65`、差异 `0` 后才生成私有配置。Attempt 4 若获批准,安装前仍须在 ARM 复核上述候选包 SHA 清单;批次年龄和最新批次身份也须以实际执行开始时为准,超过 24 小时或最新批次变化时重新探针,不沿用本节结论。