文件
hyb-oa/.trellis/tasks/archive/2026-07/07-26-internal-ops-recovery-baseline/implement.md
T
wangsli 0c00bf119e
ci-e2e / e2e (push) Waiting to run
ci-minimal / check-minimal (push) Waiting to run
归档内部OA运行恢复任务(07-26-internal-ops-recovery-baseline)
2026-07-27 18:47:34 +08:00

14 KiB
原始文件 Blame 文件历史

内部 OA 运行与恢复底线执行计划

实施步骤

  • 审计现有备份/恢复脚本、部署卷、runbook 和 checklist,冻结现有兼容入口与风险点。
  • 增加 DB + 附件成对备份入口、统一批次号、完整性检查、SHA-256 和脱敏 manifest。
  • 收紧 DB 恢复:实际数据库名探测、影子模式和精确确认必须在破坏性命令前通过。
  • 收紧附件恢复:显式目标、空目录门禁和 tar 路径安全检查。
  • 增加隔离合成数据演练,覆盖成功往返及关键负向场景。
  • 更新 runbook/checklist 和部署规约,区分普通备份、影子演练和真实事故恢复。
  • 运行任务测试计划和 Trellis 治理门禁;按实际结果记录本地 RTO,不伪造 /ready 或异机证据。
  • 在单独授权后完成真实运行来源、职责分离、异机副本和 /ready 的只读核查,并如实记录 NO_GO 缺口。
  • 经明确授权生成并复制过 DB+附件+manifest 批次;后续发现附件来自非活动目录,已将该批次降级为无效恢复证据并保留审计。
  • 经后续明确授权,从活动 DB 与活动 server 附件挂载源重新生成正确批次并完成异机复制与目标端复验。
  • 经后续明确授权,使用正确异机批次完成真实备份格式的 DB+附件隔离影子恢复,并逐项复验迁移数、关键表计数和附件数量。
  • 经后续明确授权完成真实职责分配与部署/迁移,并在部署环境复验应用 /ready、构建标识和数据连续性。
  • 修复企微 HR 双 Secret 分工:通讯录 token 只列 userid,自建应用 token 读取详情、部门和 HR 信息。
  • 补充单元测试并运行后端语法、聚焦测试、Prisma 与 Trellis 门禁。
  • 在真实环境执行两名目标成员的脱敏 dry-run;两人均唯一、不同身份且 active,但批量链路均缺手机和邮箱,已按门禁停止真实写入。
  • 复用既有 HR 同步与角色语义写入 employee + finance、employee + ceo,复核会话失效、审计和 maker-checker;角色阶段未附带部署或迁移。
  • 增加默认关闭的一次性企微敏感资料授权入口,保持普通登录静默;实现 user_ticket -> getuserdetail、active/字段/唯一性门禁和仅 employee 自助开通。
  • 补齐 OAuth 路由、服务、配置契约和单元测试,证明票据/原始敏感响应不进入日志、Cookie、数据库或审计。
  • 修复部署脚本的现场端口解析,确定唯一部署目录,并在活动 DB/附件挂载、环境摘要和旧镜像回滚点全部确认后执行获批切换。
  • 完成本地 Compose/备份加固:移除固定容器名和 DB 宿主端口,参数化数据目录,deploy/timer 显式 project,备份来源缺失硬失败,远端构建标识改由容器内 Node 核验。
  • 增加隐式附件源、隐式 DB 容器、DB 端口与固定容器名回退的负向契约演练;未部署或启用新 Compose。
  • 收紧正式 deploy 数据路径:显式绝对路径、existing|initialize 模式、既有 PGDATA 标记和禁止 Docker 静默建空目录。
  • 让成对 manifest 尊重显式 BUILD_SHA 并支持活动镜像 digest;补 Node/Python 等价与非法来源标识负向测试。
  • 把旧 Compose project 实测、镜像 digest、58 项迁移与关键表计数、影子逐表/附件计数验收、停机后复制并保留旧目录写入 runbook/checklist/spec。
  • 部署后验证唯一 Compose 来源、构建标识、迁移状态、Caddy 公网 /ready 和前端 marker;不因服务可访问而忽略来源漂移。
  • 本轮不适用/延后:不启用企微敏感资料 OAuth 开关,不要求两名目标点击一次性授权;入口保持默认关闭,未来仅用于本人补资料。
  • 从管理员通讯录在内存中筛选两名目标,先执行生产脱敏 dry-run;其余四人不进入输入、不创建账号,另轮处理。
  • dry-run 零冲突后另行批准 apply,确认两人账号/企微绑定唯一且初始角色严格为 employee,不持久化通讯录文件。
  • 记录两人原角色、活跃会话、角色待办和审计基线,再分别写入 employee + finance / employee + ceo;明确 finance 含薪资/银行资料权限且不含 asset.transfer,不授予 finance_mgr。
  • 复核角色接口递增 token version、撤销会话和 SYSTEM_USER_ROLES_SET 审计;以合成测试证明付款批次 maker-checker,不在生产创建测试付款数据,也不把结论扩大为费用审批完全分离。
  • 回滚合同固定为只通过相同角色接口恢复两人原角色集合并复核会话/审计,不恢复整库;本次写入和验证均成功,未触发回滚。CEO 既有角色待办可见性变化及本人无主管报销继续阻断已记录。
  • 将 Employee.phone 改为 nullable unique,并同步员工创建/批量导入、企微 HR master、本人授权、登录查询和前端空值合同;不执行生产 migration。
  • 增加企微通讯录 XLSX/stdin 默认 dry-run 入口,复用 HR master 写入语义,apply 使用独立双门且本阶段不执行。
  • 用完全合成的通讯录覆盖“5 个手机号 + 1 个缺失”、重复账号/手机号/邮箱、说明行/中文表头、既有手机号不被空来源清除和报告隐私门禁。

推荐文件边界

  • 复用并按需修改:scripts/backup-db.sh、scripts/backup-storage.sh、scripts/restore-db.sh、scripts/restore-storage.sh。
  • 最多新增两个小脚本:一个成对备份入口、一个 QA-only 隔离演练入口;不创建通用备份框架。
  • 更新现有 deploy/trialrun/runbook.md、deploy/trialrun/checklist.md 和 .trellis/spec/hyb-oa/deployment-trialrun.md,不新建常驻平行业务文档。
  • 优先修改 server/src/routes/wecomAuth.js 并抽取小型企微本人授权/员工开通服务;不把 HR 批同步服务改成通用身份平台。
  • 更新现有 docs/企微API能力目录.md 和 .trellis/spec/hyb-oa/wecom-boundary.md,记录批量读取与本人 OAuth 的稳定边界。

验证命令

  • bash -n scripts/backup-db.sh scripts/backup-storage.sh scripts/restore-db.sh scripts/restore-storage.sh scripts/backup-all.sh scripts/qa/run-backup-restore-drill.sh
  • bash scripts/qa/run-backup-restore-drill.sh
  • node deploy/trialrun/validate-env-contract.js
  • python3 ./.trellis/scripts/task.py validate .trellis/tasks/07-26-internal-ops-recovery-baseline
  • node scripts/qa/check-trellis-governance.mjs
  • node scripts/qa/check-sensitive-content.mjs
  • git diff --check
  • cd server && node --check src/services/integrations/wecomHrMaster.js
  • cd server && npm test -- --run tests/unit/wecomHrMaster.service.test.js
  • cd server && npm run prisma:validate
  • cd server && npm test -- --run tests/unit/routes/wecomAuth.test.js tests/unit/wecomHrMaster.service.test.js
  • cd server && npm test -- --run tests/unit/routes/wecomAuth.test.js tests/unit/wecomHrMaster.service.test.js tests/unit/wecomOAuthOnboarding.service.test.js
  • cd server && npm test -- --run tests/unit/routes/users.import.test.js tests/unit/wecomHrMaster.service.test.js tests/unit/wecomOAuthOnboarding.service.test.js tests/unit/scripts/import-wecom-directory-export.test.js
  • bash -n deploy/trialrun/deploy.sh
  • bash -n deploy/trialrun/install-warch3-ops-timer.sh

本轮本地验证证据(2026-07-26)

  • 后端全量 Vitest:162 个测试文件、1000 个测试通过;安全补修后企微聚焦回归为 3 个文件、30 个测试通过。
  • prisma validate、四个企微改动文件 node --check、部署环境契约和部署脚本语法均通过。
  • 本地实现没有开启 WECOM_OAUTH_ONBOARDING_ENABLED,没有部署、迁移、写真实员工/角色或修改企微后台权限。

本地部署加固证据(2026-07-27)

  • Shell 语法、部署环境契约、Compose 示例配置解析、Trellis task/governance、敏感扫描、文档注册、流程合同、Prisma 和 git diff --check 通过。
  • 合成备份恢复在 Node 路径和移除 Node 的 Python 3 回退路径均通过,最近两次本地参考 RTO 均为 6 秒;负向覆盖隐式附件源、隐式 DB 容器、DB 宿主端口、固定容器名和 deploy 缺失 project name。
  • 本阶段授权仅覆盖本地文件、测试、规约和提交,不包含生产备份、停机、迁移、部署、timer 安装或企微写入。
  • 已确认旧异机批次混用了活动 DB 与非活动附件目录,保留审计但不再作为活动实例成对恢复证据;正确批次须另行批准重做。
  • 复核补修后,正式 deploy 的相对/重叠路径负向门禁、显式来源标识、Node 路径以及无 Node/无 Git 的 Python 3 + digest-only 路径均通过;最近两次合成 RTO 均为 7 秒。
  • 已从活动 DB 容器与活动 server 附件挂载生成正确批次并复制到 ARM 备份机;DB catalog、manifest、源/目标产物 SHA-256、附件 tar 与 0 个普通文件计数均通过,且未伪造旧实例 build SHA。ARM 只承担异机备份与恢复演练职责,不运行 OA 服务。
  • 已在 ARM 备份机用不发布端口的一次性 PostgreSQL 16 容器恢复正确批次:58 项成功迁移、12 张关键表计数和 0 个附件普通文件均与冻结基线一致,包含镜像拉取的实测 RTO 为 33 秒。演练后容器、临时附件目录和本轮新增镜像均已删除,未运行 OA server;应用 /ready 留待生产部署环境验证。

手机号可空与通讯录导入本地证据(2026-07-27)

  • 后端全量 Vitest:163 个测试文件、1016 个测试通过;补充双 apply 门断言后,通讯录导入聚焦 8 项再次通过。新增覆盖普通用户创建/显式清空、CSV 空手机号、HR 空来源保留既有值、OAuth 无手机号建档、通讯录说明行/中文表头、企业邮箱门禁、非法手机号、重复字段、apply 双门及脱敏状态。
  • prisma validate、四个后端改动文件语法、前端 typecheck/build、Trellis task/governance、敏感扫描、流程合同、文档注册审计和 git diff --check 通过。
  • 管理员提供的真实通讯录仅执行解析级只读检查:6 名 active、5 个手机号、1 个缺失、6 个企业邮箱、0 个不完整;未连接数据库、未执行 apply、未分配角色、未发送企微消息,文件保持 Git 排除。
  • 最终只读复核确认 migration 仅删除手机号 NOT NULL、唯一索引保留;导入及本人开通只创建 employee,不自动授予 finance、ceo、admin 或 system_admin;空来源更新省略 phone 字段,真实文件名、完整路径和个人字段未进入差异。
  • 获批生产脱敏 dry-run 只接收内存筛选的两人子集,结果为输入 2、active 2、不完整 0、计划创建 2、更新 0、冲突/跳过/失败均为 0;两名目标均有手机号和企业邮箱。dry-run 未写库、未创建账号、未分配角色,目标外四人未进入输入。
  • 生产 Node 对 Promise 版 readFile(0) 返回 ERR_INVALID_ARG_TYPE,正式 CLI 在解析前安全失败;本地改为 fs.readFileSync(0) 并增加 fd 读取回归。生产证据先由同一解析、同步和报告逻辑的 fd 兼容只读入口取得;修复随 4886f9b 部署后,正式 CLI 再次得到相同结果,本阶段未执行 apply。

生产部署与 timer 收口证据(2026-07-27)

  • 已在获批停机窗口把生产切换到唯一 Compose project;活动 DB 与附件从停机冻结副本进入新的独立目录,旧容器保持停止,旧数据目录原位保留作回滚点。
  • 生产已应用 61 项 migration;12 张关键表计数与冻结基线一致,活动附件普通文件数仍为 0。server 仅回环发布,DB 不发布宿主端口。
  • 容器内与公网 /ready、前端 marker 均返回批准提交的同一 12 位构建标识;runtime smoke、external-deps smoke 和公网 bundle/marker 检查通过。
  • 运维 timer 安装器已要求显式绑定 Compose project、活动 PGDATA、活动附件目录、完整后端 SHA 和 12 位前端 SHA。生产 timer 已重新安装并保持 enabled/active,daily service 未被手工触发;unit 环境与活动挂载/构建标识一致,同环境 Compose config 与 server exec 解析通过。
  • timer 首次收口时发现从 deploy 复制的旧路径正则会误拒绝所有绝对路径;安装在写 unit 前安全停止。现已与 deploy 的根目录、尾随斜杠、双斜杠及点路径段门禁保持一致,并由环境契约阻止旧正则回退。
  • 本轮没有启动真实告警任务,没有修改员工、角色、付款、企微后台或企微开通开关;职责分离与两人本人授权继续保持未完成。
  • 4886f9b 已通过正式部署入口发布:来源 published/remoteVerified,62 项 migration 无待应用项,容器与公网 /ready、external deps smoke、runtime smoke、公网前端构建 marker 和资源扫描通过;生产环境文件未覆盖。部署后的通讯录正式 CLI dry-run 为输入 2、计划创建 2、冲突/跳过/失败 0,未写员工、绑定或角色。
  • 写入前自动备份、ARM dead-man 和管理员 actor 门禁通过。两人 apply 创建 2、成功 2;写后为 2 名 active、2 个不同企微绑定、初始角色均仅 employee。角色接口写入后 token version 合计递增 2、活动会话 0、SYSTEM_USER_ROLES_SET 审计新增 2、CEO 待办 0→0、付款批次数量变化 0。
  • 最终生产只读权限核对通过;本地 permissions 与 paymentBatches.reimbursement 聚焦回归共 40 项通过,maker-checker 只由合成测试验证,未产生生产测试付款。目标外四人未进入本轮输入;本次未触发角色回滚。

回滚点

  • 成对入口失败:保留四个底层脚本,不写完整 manifest。
  • DB/附件安全门禁与现有操作冲突:先修 runbook 和调用方,不放宽默认门禁。
  • 动态演练环境不可用:记录缺失依赖并停止,不使用真实数据替代。
  • 任何命令解析到生产、远程或含真实数据的目标:立即停止并请求明确授权。
  • 真实 dry-run 任一目标非唯一、身份相同、字段缺失或存在唯一约束冲突:停止 apply,不尝试猜测身份。
  • 员工同步后角色写入失败:不删除真实员工或企微绑定;记录脱敏结果并停止,待修复后幂等重试角色阶段。
  • 现场 Compose 解析出第二套 DB/附件目标、意外容器名或非活动端口:停止部署,不创建或迁移数据。