5.3 KiB
部署合同单一事实源与失败路径覆盖:设计
1. 根因与设计目标
历史缺陷不是 Compose 本身无法校验,而是调用链在不同位置重新定义“候选构建身份”:
deploy.sh
-> provenance.commit + provenance.shortCommit
-> BUILD_SHA / VITE_BUILD_SHA
production-preflight.mjs
-> CANDIDATE_COMMIT
-> 自行 slice(0, 12)
-> BUILD_SHA / VITE_BUILD_SHA
两条路径的键名和派生规则相同,却没有共享可执行来源。新增 Compose 必填值或调整短标识规则时,其中一条可能漏改。设计目标是把该合同收敛到已有 provenance 模块,同时保留远端消费校验,并让 synthetic harness 执行真实 orchestration/remote helper 进程。
2. 单一合同形态
在 check-source-provenance.mjs 导出:
export function deriveCandidateBuildEnv(commit) {
// validate 40..64 lowercase hex
return Object.freeze({
BUILD_SHA: commit,
VITE_BUILD_SHA: commit.slice(0, 12),
});
}
具体实现可在不改变合同的前提下调整错误类或冻结方式,但调用方不得自己派生 VITE_BUILD_SHA。
collectSourceProvenance 先调用该函数,再以同一结果形成:
commit = buildEnv.BUILD_SHA
shortCommit = buildEnv.VITE_BUILD_SHA # 兼容字段
buildEnv = { BUILD_SHA, VITE_BUILD_SHA }
共享 API 只导出一次返回完整对象的派生函数,不另行导出可能与对象漂移的键数组,也不提供 getBuildSha() / getViteBuildSha() 之类可分别调用的接口。两个调用方必须通过 Object.entries(buildEnv) 或等价的完整对象遍历生成整组远端环境赋值;单独选择某个键注入属于合同失败。
非法输入在共享函数处失败。provenance 自身使用既有 SourceProvenanceError;production preflight 将该失败稳定映射为既有 CANDIDATE_COMMIT_INVALID,不把内部错误名暴露为新的操作合同。
3. 调用链
3.1 正式部署
check-source-provenance CLI
-> buildEnv
-> deploy.sh 读取 BUILD_SHA / VITE_BUILD_SHA
-> 远端 shell env
-> docker compose config/build/runtime
deploy.sh 可继续保留 SOURCE_COMMIT / SOURCE_SHORT_COMMIT 局部名称用于日志和公网检查,但值必须来自 buildEnv,不能从 commit 再截取。
3.2 生产 preflight
CANDIDATE_COMMIT
-> deriveCandidateBuildEnv
-> remote command env assignments
-> production-preflight-remote.sh
-> 格式 + 前缀 + compose config 消费校验
远端 helper 的校验不是第二个来源:它不派生值,只验证接收到的值符合共享合同。这一层用于防止命令组装、环境传输或未来调用方漂移。
4. Harness 设计
继续使用 deployment-safety-contract.test.js 的临时目录:
- 假
ssh捕获命令、按 mode 输出 marker/error 并返回指定状态; - 假
docker只识别明确 allowlist 的 compose/ps/inspect/exec 调用; - 所有数据库、origin、migration 和 SHA 均为 synthetic;
- 测试进程不得解析真实 SSH config、调用真实 Docker 或读取仓库外 secret。
4.1 Orchestrator 失败矩阵
| SSH 退出 | Prisma marker | stable code | 预期 |
|---|---|---|---|
| 非零 | 缺失 | 有 | 传播 stable code;summary/report 先落地 |
| 非零 | 任意 | 无 | PRODUCTION_PREFLIGHT_REMOTE_FAILED |
| 零 | 缺失 | 无 | PRISMA_STATUS_OUTPUT_MISSING |
| 零 | 存在 | 无 | 进入现有 status/reconciliation 成功路径 |
纯函数四组合可保留,但四个象限还必须全部通过真实 node production-preflight.mjs + fake SSH 子进程验证,防止 main 中的证据顺序或 exit handling 漂移。测试必须对真实缺陷敏感:将远端状态判断与 marker 判断次序调回错误实现时至少一个用例变红;去掉共享对象中的任一远端赋值时,成功/缺失合同用例变红。
4.2 Remote helper 失败矩阵
| 条件 | 预期码 | 必须早于 |
|---|---|---|
BUILD_SHA 缺失 |
BUILD_SHA_MISSING |
Compose / Prisma |
| 完整 SHA 非法 | PROD_TARGET_BUILD_SHA_INVALID |
Compose / Prisma |
| 12 位 SHA 非法 | PROD_TARGET_VITE_BUILD_SHA_INVALID |
Compose / Prisma |
| 前缀不一致 | PROD_TARGET_BUILD_SHA_MISMATCH |
Compose / Prisma |
| Compose config 非零 | PROD_TARGET_COMPOSE_CONFIG_INVALID |
runtime/Prisma |
假 Docker 对意外调用返回固定失败码,使测试能证明早停,而不是仅匹配最终 stderr。
5. 兼容性与停止条件
- provenance JSON 保留既有顶层字段;新增
buildEnv是向后兼容扩展。 - production preflight 的外部 env、报告文件、稳定错误码和远端脚本输入语义不变。
- 若实现需要让 preflight import 会触发 provenance
main()、执行 Git/SSH,必须停止并修正模块边界;导入必须无副作用。 - 若共享 helper 迫使 production preflight 接受 unpublished HEAD、减少远端校验或把 secret 写入报告,停止并回到规划。
- 本任务不在生产验证。上线收益通过本地合同和 reviewer 证明,下一次获批部署自然消费该改动。
6. Rollback
本任务只改本地 tooling。回滚为恢复三个调用点及测试到前一提交;不涉及 schema、生产配置或数据。若共享合同在本地门禁中暴露兼容问题,提交前直接修正,不以生产试跑验证。