diff --git a/.trellis/spec/hyb-oa/deployment-trialrun.md b/.trellis/spec/hyb-oa/deployment-trialrun.md index 519897db..030f80d0 100644 --- a/.trellis/spec/hyb-oa/deployment-trialrun.md +++ b/.trellis/spec/hyb-oa/deployment-trialrun.md @@ -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. diff --git a/.trellis/tasks/08-23-isolated-backup-restore-drill/implement.md b/.trellis/tasks/08-23-isolated-backup-restore-drill/implement.md index 410fcd00..3d9b5705 100644 --- a/.trellis/tasks/08-23-isolated-backup-restore-drill/implement.md +++ b/.trellis/tasks/08-23-isolated-backup-restore-drill/implement.md @@ -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 候选尚未上传或安装;实际恢复须在本次探针和候选证据审查后另行取得明确批准。 ## 验证命令类别 diff --git a/.trellis/tasks/08-23-isolated-backup-restore-drill/research/restore-drill-evidence.md b/.trellis/tasks/08-23-isolated-backup-restore-drill/research/restore-drill-evidence.md index c51580fc..f8ec4133 100644 --- a/.trellis/tasks/08-23-isolated-backup-restore-drill/research/restore-drill-evidence.md +++ b/.trellis/tasks/08-23-isolated-backup-restore-drill/research/restore-drill-evidence.md @@ -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 小时或最新批次变化时重新探针,不沿用本节结论。