139 行
16 KiB
Markdown
139 行
16 KiB
Markdown
# 生产部署执行与验收:实施清单
|
||
|
||
## 0. 规划与启动门禁
|
||
|
||
- [x] 已向用户呈现本 task 的最终规划摘要,并取得对该摘要的最新明确批准。
|
||
- [x] 已解决候选发布是否可进入上游的外部授权;未获授权不得使用 unpublished override。
|
||
- [x] 任务从 `planning` 切换到 `in_progress` 前,确认本清单、PRD、design 与 Open Questions 已收敛。
|
||
- [x] **规划修订复核:**确认唯一公网环境拓扑、精确身份匹配和数据库名只读引导的修订摘要,并重新批准后再改 tooling/连接生产。
|
||
|
||
## 1. 候选与本地证据
|
||
|
||
- [x] 提交本 task 的规划 artifacts,确认工作区 clean。
|
||
- [x] 记录候选完整 commit、短 SHA、分支和上游包含关系;不把连接串、SSH target 或环境值写入文档。
|
||
- [x] 运行 `node deploy/trialrun/check-source-provenance.mjs`,要求 `published=true`、`remoteVerified=true`。
|
||
- [x] 运行既有本地合同门禁:
|
||
- [x] `node deploy/trialrun/validate-env-contract.js`
|
||
- [x] 相关部署 shell `bash -n`
|
||
- [x] `node --check deploy/trialrun/production-preflight.mjs`
|
||
- [x] 聚焦 `deployment-safety-contract.test.js`(既有提交证据为 13/13,本轮未重复触发生产动作)
|
||
|
||
## 1.1 拓扑校准与 tooling 修订(生产前)
|
||
|
||
- [x] **刻意次序调整:**本轮 target gate 不再是第一条生产命令;历史身份恢复、refresh exact probe、systemd contract/公网 origin 核对、远端 `POSTGRES_DB` 只读引导四步探测排在其之前。四步全程只读、逐步 fail-closed,任一失败均不得进入 target gate 或 Prisma status。
|
||
- [x] 从 `34181e3` 只读恢复历史 `DEPLOY_SERVER`,从 `5e2d03893826` 恢复首次显式冻结的 `COMPOSE_PROJECT_NAME`;确认历史 `REMOTE_DIR` 只是未验证 fallback,不作为身份基线。值仅保存在当前进程,不写入 task、日志或对话。
|
||
- [x] 无回显探测 `DEPLOY_REFRESH_SERVER`,要求 exact forced-command `probe` 唯一 PASS;多个候选或零候选均 PAUSED。
|
||
- [x] 修改 production preflight:取消对合法 `trialrun` 命名的单独拒绝,增加部署目标、远端目录、Compose project、systemd contract、公网 origin 的精确身份对账;保留回环/零地址/local regression/staging/shadow/placeholder 防线。
|
||
- [x] 明确 `DEPLOY_SERVER` 验证责任:真实来源在上游历史身份解析;引导器向 preflight 同时传 actual/expected 只用于防进程内漂移,不构成第二个独立身份来源。若重构上游,必须保留独立 target 来源校验,不能把下游恒等比较当作替代。
|
||
- [x] 增加只读数据库身份 bootstrap:身份组匹配后读取远端 `.env` 的 `POSTGRES_DB`,在远端转换为 SHA-256 比较基线后仅在内存中传给 target gate;数据库名明文禁止离开远端、回显或落盘,读取失败或身份组不一致时不得进入 Prisma status。
|
||
- [x] 增加 synthetic fixture:合法 `hyb-oa-trialrun` 身份通过;错误目录/project/host/db、回环、staging、占位符和多 refresh 候选 fail-closed;断言 bootstrap 不泄露值且顺序早于 status。
|
||
- [x] 增加 `PRODUCTION_READ_ONLY_PREFLIGHT=1` 停止点:完成 target/pre-status 与回滚窗口后、进入 `deploy.sh` 前退出;只读证据复核通过前不得运行写入路径。
|
||
- [x] 增加 `PRODUCTION_IDENTITY_ONLY=1` 停止点:以 contract 定位远端 `.env`/容器并完成 origin 双取样后,冻结 contract `REMOTE_DIR` 为进程内精确基线并立即退出;不得读取数据库名、运行 13 项体检或 Prisma。
|
||
- [x] 重新运行部署安全测试、shell/Node syntax、task/governance/sensitive/diff 门禁,提交并推送新的候选后重新通过 provenance。
|
||
|
||
## 2. 生产 preflight(全部只读)
|
||
|
||
- [x] 在同一进程内加载现行 OPS7 origin、历史身份恢复结果、exact refresh identity、只读 DB bootstrap 结果和 `EXPECTED_PENDING_MIGRATIONS`;不把任何值写入仓库或对话。
|
||
- [x] 先运行 `check-existing-deployment.sh`,记录 13 项真实 PASS/FAIL 数字;任何 FAIL 停止。
|
||
- [ ] 运行 `deploy-existing.sh` 内置的 source/target/preflight,或按同一 wrapper 的只读阶段执行;人工阅读 target gate 原始输出和 Prisma status marker 原文。
|
||
- [ ] 核对 candidate migration manifest、`_prisma_migrations` applied/异常/pending 集合和批准 allowlist;未知 pending、failed、rolled-back、unfinished、diverged 或目标身份不确定均 `PAUSED`。
|
||
- [ ] 同一只读窗口查询 `terminated` 行数,记录 `rollbackWindow=OPEN|CLOSED`、实际 count 和读取时间;确认这是部署前快照。
|
||
- [ ] 确认 preflight 到 deploy 之间有配置/数据库变更冻结;无法保证则停止。
|
||
|
||
## 3. 获批发布(唯一写入阶段)
|
||
|
||
- [ ] 再次确认 preflight 所有门禁仍为 PASS,且没有新的远端配置/候选变化。
|
||
- [ ] 仅调用 `deploy/trialrun/deploy-existing.sh`,固定 `SYNC_ENV=0`、`DEPLOY_DATA_MODE=existing`、`DEPLOY_STATUS_OUTPUT_MODE=quiet`。
|
||
- [ ] 允许的 schema 写入仅为候选 migration;不得执行 `migrate dev`、`reset`、`db push`、`resolve`、手工 DDL、seed 或业务 API 写入。
|
||
- [ ] 若 deploy/migrate/init 中途失败,保留远端现场并停止;不自行重试、回滚或清理。
|
||
|
||
## 4. 发布后只读验收
|
||
|
||
- [ ] 保存 post-status 原始输出(仅受控现场)及脱敏副本;确认全部候选 migration applied / schema up to date。
|
||
- [ ] 核对 `/ready`、完整 build SHA、公开短 SHA 与候选 commit。
|
||
- [ ] 运行基础 smoke、external deps smoke、runtime smoke 和公开 bundle 扫描,记录真实数字和输出摘要。
|
||
- [ ] 在任何真实终止写入前完成未登录、无权限、详情不存在/无权等权限负向路径及合同详情只读检查;缺凭据项标 `PAUSED/SKIP`。
|
||
- [ ] 检查备份合同 refresh;失败记 `DEPLOYED_BUT_CONTRACT_REFRESH_FAILED`,不重复发布应用。
|
||
|
||
## 5. 失败分流、review 与收口
|
||
|
||
- [ ] 将每个失败归入 target/migration、应用健康、refresh、public/live/permission 之一;不得把迁移失败与产品回归混为一类。
|
||
- [ ] 记录真实业务写入计数为 0(本 task 不主动写入 `terminated` 或其他业务数据)。
|
||
- [ ] 对照部署前窗口快照决定兼容回退或 roll-forward;`CLOSED` 时不得回退到不识别 `terminated` 的旧应用,不 drop 三列。
|
||
- [ ] 启动只读 reviewer,确认门禁顺序、原始证据可追溯、脱敏副本无敏感信息、失败后没有继续推进。
|
||
- [ ] 运行最终 Trellis/process/docs/governance/sensitive/diff 门禁;通过后提交中文 commit 并引用 `08-08-production-deployment-execution`。
|
||
- [ ] 只有生产、公网和必要真机全部获批并通过时才可告知用户可以测试;否则保留 `PAUSED`。
|
||
- [ ] 归档 task 并记录会话日志,报告中保留 pre/post status、target gate、窗口判定和所有 `PAUSED/SKIP` 原因。
|
||
|
||
## Rollback Points
|
||
|
||
1. 来源或 preflight 失败:尚未写入,停止并修正授权/输入后重新检查。
|
||
2. `migrate deploy`/init 失败:保留现场,禁止 reset/resolve/drop,等待明确处置。
|
||
3. `/ready`/smoke 失败:窗口 OPEN 可按既有合同回退兼容应用;窗口 CLOSED 只 roll-forward。
|
||
4. refresh 失败:应用已部署但合同刷新失败,不重复发布应用,只走合同修复流程。
|
||
|
||
## Evidence Notes
|
||
|
||
- 原始 target gate 和 Prisma status stdout/stderr 不进 Git;只在受控执行现场留存。
|
||
- 任务 artifacts 只保存脱敏副本、commit、状态码、migration ID、计数、窗口状态和证据引用。
|
||
- 不保存生产 origin、数据库名、SSH target、用户名、绝对远端路径、连接串、凭据、业务正文或原始 payload。
|
||
|
||
## Execution Evidence (2026-08-08)
|
||
|
||
- 规划提交:`4596ed0`;暂停证据提交:`73f1467`;当前候选已推送到配置的 `origin/main`,`check-source-provenance.mjs` 返回 `published=true`、`remoteVerified=true`。
|
||
- 本地门禁:env contract、shell/Node syntax、task validate、process contract、docs audit(0 errors,保留仓库既有 warning)、Trellis governance(0 errors/0 warnings)、sensitive scan(0 findings)均通过。
|
||
- 生产输入存在性检查:`EXPECTED_PRODUCTION_ORIGIN`、`EXPECTED_PRODUCTION_DB_NAME`、`EXPECTED_PENDING_MIGRATIONS`、`DEPLOY_SERVER`、`DEPLOY_REFRESH_SERVER` 五个进程输入均未注入;受控 contract 路径按设计应在连接目标后由 systemd unit 读取,未把它们误当作本地输入缺失。
|
||
- 生产动作:未执行 SSH、target gate、`prisma migrate status`、`migrate deploy`、数据库写入、refresh、公网 smoke 或真机验证;AC1 的生产体检及 AC2–AC7 保持未验收并标记 PAUSED。
|
||
- 失败分流:停止在生产输入门禁,未出现“门禁失败但继续推进”。后续必须在同一受控执行环境注入输入后,从 target gate 重新开始。
|
||
|
||
## Input Traceback Evidence (2026-08-08)
|
||
|
||
- 当前 OPS7 运维交接 Runbook 仍提供公网 origin 作为只读检查基准;它没有提供生产数据库名或 SSH 身份。
|
||
- 仓库外的三份验收 env 文件仍存在且为受控用户、`0600` 权限;它们只包含 live smoke、SMTP 或一次性账号键,不包含生产部署身份/数据库输入,未被本 task 读取或 source。
|
||
- Git 历史没有 `deploy/trialrun/.env`、`deploy.env` 或上述验收 env 文件的删除记录;`.gitignore` 从始终将 `.env` 排除在版本库之外。
|
||
- shell 历史没有五个部署变量的字面赋值记录。结论:部署输入不是被本 task 删除,而是按运维合同设计为每次执行时临时注入。
|
||
|
||
## Planning Revision Evidence (2026-08-08)
|
||
|
||
- 历史提交 `34181e3` 的旧 `deploy.sh` 确有默认部署 target/目录,但当时尚未显式设置 Compose project;`5e2d03893826` 首次冻结 project 且沿用同一远端目录。两份证据共同证明该遗留命名与公网 origin 属于同一唯一运行环境,不能因 `trialrun` 字样单独拒绝。
|
||
- 现行 gate 尚未对 `DEPLOY_SERVER`、`REMOTE_DIR`、`COMPOSE_PROJECT_NAME` 与独立预期身份做精确对账;本节修订只允许先改部署/QA tooling,不改业务代码或生产数据。
|
||
- 修订后的第一条远端动作仍是只读身份 bootstrap;数据库名读取排在 exact identity 匹配之后,任何 bootstrap 或 target gate FAIL 都不得继续。
|
||
|
||
## Read-only Identity Bootstrap Evidence (2026-08-08)
|
||
|
||
- tooling 提交 `f11e2f2` 已进入 `origin/main`;执行前 provenance 为 `published=true`、`remoteVerified=true`,工作区 clean。
|
||
- 使用 `PRODUCTION_READ_ONLY_PREFLIGHT=1` 启动只读身份引导。历史 target/目录与首次显式 project 记录解析成功;refresh forced-command `probe` 恰好一个候选精确 PASS,候选身份未回显。
|
||
- systemd deployment contract 读取成功且六项结构校验通过,但当前 `REMOTE_DIR` 与已批准历史精确基线不一致;稳定停止码为 `SYSTEMD_REMOTE_DIR_MISMATCH`。
|
||
- 门禁在数据库身份引导前停止:未读取或生成 `POSTGRES_DB` 比较基线,未运行 13 项聚合体检、target gate、`prisma migrate status`、`_prisma_migrations` 对账或 `terminated` 行数查询,因此 rollback window 仍为 `UNKNOWN`,不得推断 OPEN/CLOSED。
|
||
- 未调用 `deploy-existing.sh` 的 preflight/deploy 阶段,未进入 `deploy.sh`、rsync、`migrate deploy`、应用切换、refresh 或公网 smoke;生产 schema 写入与业务写入均为 0。
|
||
- 失败后未改用当前 contract 自述覆盖历史预期、未跳过目录精确比较、未继续推进。后续必须先独立确认当前 contract 目录变更的来源与公网环境归属,再修订批准基线或恢复正确 contract。
|
||
|
||
## Origin-first Identity Recalibration Evidence (2026-08-08)
|
||
|
||
- 修订提交 `bf2631c` 已进入 `origin/main`;执行前 provenance 为 `published=true`、`remoteVerified=true`,工作区 clean。
|
||
- Git 全历史复核确认 `REMOTE_DIR="${REMOTE_DIR:-...}"` 始终是可被运维显式输入覆盖的 fallback,未形成其曾在生产生效的证据;本轮不再把该默认值作为目录权威,也未修改线上 contract。
|
||
- 使用 `PRODUCTION_IDENTITY_ONLY=1` 重新执行:历史 SSH target 与首次显式 Compose project 基线解析成功,refresh forced-command `probe` 仍恰好一个候选精确 PASS,systemd contract 六项结构和 contract-relative env/Compose 约束通过。
|
||
- 远端 `.env` 的 `APP_ORIGIN` 与运行中 server 容器的 `APP_ORIGIN` 分别独立取样,二者均与 OPS7 当前 HTTPS 公网基准精确匹配;稳定结果为 `origin_verified_remote_dir_baseline=systemd_contract`。
|
||
- 只有上述 origin 双取样通过后,当前 systemd contract 的 `REMOTE_DIR` 才被冻结为本进程 `EXPECTED_REMOTE_DIR`;目录字面值未回显、未写入 task、日志或证据文件。
|
||
- identity-only 在目录基线冻结后立即退出:未读取 `POSTGRES_DB`、未生成 DB hash、未运行 13 项聚合体检、target gate、`prisma migrate status`、迁移表对账或 `terminated` 行数查询,rollback window 仍为 `UNKNOWN`。
|
||
- 未调用 `deploy-existing.sh`、`deploy.sh`、rsync、`migrate deploy`、应用切换、refresh 或公网 smoke;生产 schema 写入与业务写入均为 0。进入数据库身份和 pre-status 前仍需用户复核本节证据。
|
||
|
||
## Read-only Pre-status Attempt Evidence (2026-08-08)
|
||
|
||
- 责任边界记录提交 `bf23664` 已进入 `origin/main`;执行前 provenance 为 `published=true`、`remoteVerified=true`,工作区 clean。
|
||
- 使用 `PRODUCTION_READ_ONLY_PREFLIGHT=1` 执行。历史 target/project、refresh exact probe、origin 双取样、contract 目录冻结和远端 DB hash 引导通过,稳定输出 `exact_identity_group`;数据库名、目标、路径均未回显。
|
||
- `check-existing-deployment.sh` 的 13 项全部真实 PASS:`PASS=13 FAIL=0`,包括部署身份、六项 contract、仓库/环境/数据目录、唯一 runtime、build、storage/PGDATA mount、backup build 和 refresh program。
|
||
- production preflight 在 Prisma status marker 产生前停止,外层稳定码为 `PRISMA_STATUS_OUTPUT_MISSING`;脱敏 `preflight-output.txt` 为空,未生成 `prisma-migrate-status.txt`。因此没有可审查的 status 原文,不能判定 pending、applied、failed、diverged 或 schema up to date。
|
||
- 代码复核确认 `production-preflight.mjs` 先在 `rawStatus == null` 时抛 `PRISMA_STATUS_OUTPUT_MISSING`,之后才在 `result.status !== 0` 分支解析远端 stderr 安全码;本次真实远端停止码被该顺序遮蔽,不能从现存 evidence 恢复,也不得猜测。
|
||
- DB hash 引导成功只证明远端 `.env` 数据库名已形成比较基线,不证明后续 `.env` / `current_database()` / runtime `DATABASE_URL` 三方一致性;远端 preflight 未输出 `target_identity_and_database_identity` PASS,故该验收项保持未通过。
|
||
- 未获得 migration reconciliation、pending allowlist 对账或 `terminated` count;rollback window 仍为 `UNKNOWN`,不得写作 OPEN/CLOSED。
|
||
- `PRODUCTION_READ_ONLY_PREFLIGHT=1` 未进入 `deploy.sh`;未执行 rsync、`migrate deploy`、应用切换、contract refresh 或业务 API,生产 schema 写入与业务写入均为 0。失败后未重跑、未跳过门禁。
|
||
|
||
## Pre-status Diagnostic Wrapper Repair Evidence (2026-08-08)
|
||
|
||
- 已确认外层 `production-preflight.mjs` 在远端非零退出且 Prisma marker 缺失时,先抛出 `PRISMA_STATUS_OUTPUT_MISSING`,遮蔽了远端 helper 已输出的稳定安全码;该结论来自源码顺序与既有脱敏 evidence,不反推或猜测真实远端原因。
|
||
- 最小修复保持稳定摘要与 `reportRef` 在失败判断前输出,并把远端非零退出判断提前:可解析 `code=...` 时传播原码,不可解析时固定失败为 `PRODUCTION_PREFLIGHT_REMOTE_FAILED`;只有远端退出 0 且 marker 缺失时才返回 `PRISMA_STATUS_OUTPUT_MISSING`。
|
||
- 聚焦回归覆盖四种组合:非零/有安全码/marker 缺失,非零/有安全码/marker 存在,非零/无可解析码/marker 缺失,以及退出 0/marker 缺失;`deployment-safety-contract.test.js` 为 19/19 PASS。
|
||
- 本地 Node/shell syntax、env contract、task validate、process contract、docs audit、Trellis governance、sensitive scan 与 `git diff --check` 均通过;docs audit 仅保留仓库既有的未注册文档 warning。
|
||
- 本节修复阶段未连接生产、未运行 target/status、未执行 rsync、migration、应用切换或业务 API;生产 schema 写入与业务写入仍为 0。候选提交进入上游且 provenance 重新通过后,才允许重跑只读 pre-status;取得真实远端错误码后必须立即停止并复核原因。
|