文件
hyb-oa/.trellis/tasks/08-08-production-deployment-validation/design.md
T

6.5 KiB
原始文件 Blame 文件历史

生产部署验证与迁移门禁:设计说明

1. 边界与目标

本任务是一次受控生产发布与验证合同,不改变合同业务实现。部署 tooling 只在必要时增加生产 target/migration preflight 及静态测试;应用代码、生产 .env、真实业务数据和企业微信不在本任务改动范围。

核心状态序列:

candidate/source
  -> production target identity (read-only)
  -> existing deployment aggregate preflight (read-only)
  -> candidate migration manifest + pre-status (read-only)
  -> terminated row count / rollback window snapshot (read-only)
  -> approved deploy-existing (schema/app write)
  -> post-status applied (read-only)
  -> /ready + build + smoke + permission-negative (read-only)
  -> closeout / PAUSED classification

任何箭头左侧门禁失败都不得进入右侧动作。尤其 migrate deploy 之前不得 seed、切换应用或执行业务写入。

2. 生产目标识别

2.1 输入

  • EXPECTED_PRODUCTION_ORIGIN:执行时提供的完整 HTTPS origin。
  • EXPECTED_PRODUCTION_DB_NAME:执行时提供的预期生产数据库名;仅用于比较,不输出。
  • Existing deployment contract:由 deployment-contract-lib.sh 从受控 systemd unit 读取六个 allowlist 参数。
  • 本任务 wrapper 不接受未发布提交 override;灾备/远端故障恢复保持为另一条需单独批准的流程。

2.2 只读判据

远端 helper 读取 .env 的键名和值只在内存中比较:

  • NODE_ENV=production、COOKIE_SECURE=true。
  • APP_ORIGIN 与 EXPECTED_PRODUCTION_ORIGIN 完全一致,scheme 为 HTTPS,host 不是 localhost、127.0.0.1、::1,也不是示例/测试/暂存 origin。
  • POSTGRES_DB 与 EXPECTED_PRODUCTION_DB_NAME 一致;数据库 URL 的 database 部分一致,host 不得是回环地址或本地回归库标识。
  • 生产目标的 compose/path 名称不能单独作为身份依据;trialrun 只描述部署脚本族,不能被误当作生产身份或排除条件。生产/非生产判定以显式 origin + DB identity 为准。

失败只输出稳定 code,例如 PROD_TARGET_ORIGIN_MISMATCH、PROD_TARGET_DB_MISMATCH,不输出实际值。

3. 迁移 preflight 设计

3.1 Candidate manifest

从候选 commit 的 server/prisma/migrations/* 生成排序后的 migration ID 清单。ID 只允许 Prisma migration 目录安全字符。EXPECTED_PENDING_MIGRATIONS 是执行时的显式 allowlist;本轮预期是合同 termination migration,若已提前应用则 pending 为空。

3.2 Production read-only comparison

在当前生产 Compose 数据库容器上只读查询 _prisma_migrations:

  • 已应用集合:finished_at IS NOT NULL AND rolled_back_at IS NULL。
  • 异常集合:rolled_back_at IS NOT NULL、失败日志/未完成行或 applied ID 不在 candidate manifest。
  • pending 集合:candidate manifest − applied 集合。
  • 输出仅为计数、migration ID 和状态,不输出 DATABASE_URL、密码或原始日志。

同时运行 npx prisma migrate status。原始 stdout/stderr 只保留在受控执行现场;任务 artifacts 写入去除 datasource、数据库 URL、目标 origin/DB 值的脱敏副本,人工核对副本是否与集合比较一致。退出码不能替代原始输出。

3.3 Gate rules

  • 异常集合非空 -> PAUSED。
  • pending 集合不是 EXPECTED_PENDING_MIGRATIONS 的精确集合 -> PAUSED。
  • candidate manifest 无法读取、status 输出无法人工解释或数据库连接目标不确定 -> PAUSED。
  • 只读查询不得调用 migrate deploy、seed、reset、resolve、db push 或手工 SQL DDL。

4. 回滚窗口

预部署只读查询:

SELECT count(*) FROM contract_registry WHERE status = 'terminated';
  • count = 0:rollbackWindow=OPEN;部署失败可在不 drop schema 的前提下回退到兼容应用。
  • count > 0:rollbackWindow=CLOSED;旧应用回退被禁止,只允许 roll-forward/兼容 hotfix。
  • 窗口关闭事件是第一条已提交 terminated 记录产生的瞬间,而非发布时间、迁移时间或人工计时。
  • 本任务不执行终止写入,因此不会主动把窗口从 OPEN 变为 CLOSED。

5. 发布与只读验收

  • 只用 deploy-existing.sh,固定 SYNC_ENV=0 与 DEPLOY_DATA_MODE=existing。
  • wrapper 调用既有 deploy.sh 时设置 DEPLOY_STATUS_OUTPUT_MODE=quiet,避免其历史 status 检查把 datasource 原文打到部署终端;详细 pre/post 证据由受控 helper 生成。
  • 部署脚本内部 migrate deploy 是唯一允许的 schema 写入;其后必须在受控现场保留 post-status 原始输出,并生成脱敏证据副本,确认全部 applied。
  • /ready build SHA、容器 build、公开短 SHA和候选 commit 一致。
  • 基础 smoke、external deps、runtime smoke、公开资源扫描及权限负向路径均只读;登录态/企微/真实 OCR 缺少批准凭据时记录 PAUSED/SKIP。
  • 权限负向路径(未登录、不具备合同管理权限、详情不存在/无权)必须排在任何未来真实终止写入之前;当前任务没有该写入。

6. 失败分流与证据

阶段 失败处理 是否可重复部署
target/preflight/status 停止,不同步/不写 DB 修正输入后重新预检
migrate deploy/init 保留现场,禁止 reset/resolve/drop;按批准决定兼容回退或 roll-forward 未确认现场前不可重复
/ready/runtime smoke 记录应用失败;窗口 OPEN 时按既有发布合同回退,否则 roll-forward 需复核窗口状态
backup refresh 标记 DEPLOYED_BUT_CONTRACT_REFRESH_FAILED,不重复发布应用 只修复合同
public/live/permission negative 不宣称可测,记录 PAUSED/FAIL 不自动重跑业务写入

Preflight 与 deploy.sh 之间要求远端配置/数据库身份变更冻结;若无法保证该窗口不可变,停止在 preflight 阶段。post-status 只能确认结果,不能补救并发期间写入错误目标的风险。

7. 证据与隐私

  • 任务只保存 commit、状态码、计数、migration ID、报告引用和脱敏原因。
  • 每次 pre/post 运行开始先清理报告目录中两个已知 evidence 文件,避免重试复用目录时旧 PASS 证据残留;不做目录级递归删除。
  • 不保存 SSH target、用户名、绝对远端路径、数据库 URL、凭据、业务合同正文、终止原因或真实响应 payload。
  • 生产 target gate 和 pre/post status 的原始输出若包含环境敏感内容,先做脱敏副本;原始日志留在受控执行环境,不进 Git。