From c4604f3fb15fe240801759042a3bff79a701889c Mon Sep 17 00:00:00 2001 From: shunli Date: Sun, 23 Aug 2026 12:49:17 +0800 Subject: [PATCH] =?UTF-8?q?=E9=83=A8=E7=BD=B2(arm-public-health-monitor-co?= =?UTF-8?q?ntrolled-rollout):=20=E5=AE=8C=E6=88=90=20ARM=20=E5=85=AC?= =?UTF-8?q?=E7=BD=91=E5=81=A5=E5=BA=B7=E7=9B=91=E6=8E=A7=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .trellis/spec/hyb-oa/deployment-trialrun.md | 24 ++++ .../check.jsonl | 1 + .../design.md | 59 ++++++++++ .../implement.jsonl | 1 + .../implement.md | 75 ++++++++++++ .../prd.md | 107 ++++++++++++++++++ .../task.json | 35 ++++++ deploy/trialrun/runbook.md | 4 +- docs/试运行与自动化验证手册.md | 4 +- 9 files changed, 308 insertions(+), 2 deletions(-) create mode 100644 .trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/check.jsonl create mode 100644 .trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/design.md create mode 100644 .trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/implement.jsonl create mode 100644 .trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/implement.md create mode 100644 .trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/prd.md create mode 100644 .trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/task.json diff --git a/.trellis/spec/hyb-oa/deployment-trialrun.md b/.trellis/spec/hyb-oa/deployment-trialrun.md index 8c39bfdd..39bef31d 100644 --- a/.trellis/spec/hyb-oa/deployment-trialrun.md +++ b/.trellis/spec/hyb-oa/deployment-trialrun.md @@ -1432,6 +1432,10 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ... timer, application-health alert states or the shared WeCom group-alert helper. - Purpose: detect an unavailable OA host, edge/TLS path, application or database readiness signal without adding a time-series platform or relying on traffic. +- Topology boundary: the Tencent Cloud server is the OA production host; ARM is + the off-host backup and external-health-monitor node and does not run OA. + Changing the ARM probe is an operations-monitor rollout, not an OA application + deployment. ### 2. Signatures @@ -1442,6 +1446,9 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ... install|enable|uninstall`. - Units: `hyb-oa-public-app-health.service` and `hyb-oa-public-app-health.timer`; the timer uses `OnCalendar=*:0/5`. +- Runtime direction: `ARM monitor -> public HTTPS /ready -> Tencent Cloud OA`. + `DEPLOY_SERVER` continues to identify the OA production host and must never be + inferred from the ARM monitoring alias. - Local contract: `bash scripts/qa/run-app-health-monitor-contract.sh`. - Application statuses: `FAIL_APP_HEALTH`, `PASS_APP_HEALTH_READY` and `FAIL_APP_HEALTH_FLAPPING`. @@ -1452,6 +1459,10 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ... - Run the probe from the existing ARM host against an exact HTTPS `/ready` URL. Success requires trusted TLS, HTTP 2xx, bounded JSON and `data.ok === true`. +- Classify the remote role before any write. ARM may receive only the fixed + probe/helper/monitor units and its independent state; OA application, + database, Caddy, Compose and migrations remain on the Tencent Cloud production + host and follow their separate deployment workflow. - Classify DNS resolution and TCP connection failures separately before the shared fallback catches `OSError`; keep TLS, timeout, HTTP, response-size and response-contract categories stable. Count any stable failure category toward @@ -1520,6 +1531,9 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ... is incomplete even when the timer is healthy. - ARM itself or its network/robot path unavailable -> the monitor can be silent; do not report this design as having an independent third-party dead-man. +- Treating ARM as the OA production server, or selecting it as `DEPLOY_SERVER` + for an application rollout -> stop before upload or mutation and correct the + topology classification in the active task. ### 5. Good/Base/Bad Cases @@ -1530,6 +1544,8 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ... as ready for an approved rollout, not as an active monitor. - Bad: run the timer only on the OA host, send raw `/ready` errors, install and enable in one unapproved step, or deploy the probe without its helper revision. +- Bad: describe ARM as the OA production host or deploy OA application artifacts + there because the monitor itself is production-facing. ### 6. Tests Required @@ -1553,6 +1569,10 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ... helper allowlist or behavior changes. - ARM install, enabled/active timer status and real failure/recovery messages are external evidence and may not be inferred from the local contract. +- The rollout task and evidence must name the two roles without addresses or + accounts: Tencent Cloud = OA production; ARM = off-host monitoring/backup. + Assert that the ARM command set contains no OA deploy, Compose, migration or + database mutation entrypoint. ### 7. Wrong vs Correct @@ -1563,6 +1583,8 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ... # alternating alert/recovery messages during a flapping link. bash scripts/qa/run-app-health-monitor-contract.sh bash deploy/trialrun/install-offhost-app-health-monitor.sh enable +# Wrong target classification: the off-host monitor is not DEPLOY_SERVER. +DEPLOY_SERVER= bash deploy/trialrun/deploy-existing.sh ``` #### Correct @@ -1576,6 +1598,8 @@ bash scripts/qa/run-automatic-backup-contract.sh # enable/real-message/drill approval before claiming the monitor is active. \ bash deploy/trialrun/install-offhost-app-health-monitor.sh install +# OA application deployment keeps its separately approved Tencent Cloud target. +DEPLOY_SERVER= bash deploy/trialrun/deploy-existing.sh ``` ## Scenario: Existing Deployment Preflight And Cache Stability diff --git a/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/check.jsonl b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/check.jsonl new file mode 100644 index 00000000..9dd3234a --- /dev/null +++ b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/check.jsonl @@ -0,0 +1 @@ +{"_example": "Fill with {\"file\": \"\", \"reason\": \"\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."} diff --git a/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/design.md b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/design.md new file mode 100644 index 00000000..2b69a6cd --- /dev/null +++ b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/design.md @@ -0,0 +1,59 @@ +# ARM 公网健康监控受控部署设计 + +## 1. Boundary + +腾讯云服务器是 OA 真实生产主机;ARM 是不运行 OA 服务的独立异机备份与外部健康探测节点。本次只升级 ARM 上已有的应用健康探测器、共享企微 helper 和两个应用健康 systemd units。状态目录、应用健康 alert state、root-only webhook、备份 receiver/dead-man 和归档均保留。部署不修改腾讯云 OA 主机、DNS、网络策略或业务数据。 + +## 2. Source and Identity + +- 候选来源固定为工作提交 `a0f0483`,部署前以 Git 对象或干净工作树核验三个部署源。 +- 通过既有受控 SSH alias 操作;不把主机、用户名或密钥信息写入任务证据。 +- root 操作必须由 `sudo -n` 或既有等价受控入口完成。任何口令提示都在写入前停止,不在聊天中索取或传递口令。 +- webhook 路径只在远端 root shell 内从既有受控事实源解析并校验;正文永不读取。 + +## 3. Upgrade Data Flow + +```text +local contracts + committed-source hashes + -> ARM read-only baseline + -> same-host rollback copies of exact managed artifacts + -> upload committed candidate to one temporary directory + -> installer install (stops timer, preserves state, remains disabled) + -> hash/permission/unit/state checks + -> formal systemd oneshot against real /ready + -> installer enable + -> observe two scheduled windows + -> verify dead-man baseline and clean temporary material +``` + +`install` 是 ARM 运维变更分界点。此前失败只清理临时上传;此后失败按升级前快照回滚。`enable` 不是测试消息入口,只恢复对腾讯云 OA 公网 `/ready` 的 5 分钟外部监控。 + +## 4. Existing State Compatibility + +旧版 probe schema v1 由新版保守迁移至 schema v2,不补发通知。升级前只记录允许字段及校验结果,不输出原始 JSON。disabled oneshot 后必须验证 v2 phase 合法、权限仍为 `0600`,并确认 helper alert state 未产生非预期变化。 + +若回滚到旧版且活动状态已是 v2,旧版无法读取时不得修改字段伪造 v1。先停 timer、保留精确状态副本,再把精确活动状态文件移到同一受控文件系统的回滚位置,由旧版在真实健康样本上建立基线。 + +## 5. Shared Helper Compatibility + +helper 同时服务应用健康和备份/dead-man,因此必须随 probe 一起升级,并以完整自动备份合同作为写前门禁。远端升级后只核对 dead-man 的 enabled/active 和既有文件属性,不主动触发 dead-man,也不改变其状态文件。 + +## 6. Rollback Matrix + +| 阶段 | 失败处理 | +| --- | --- | +| 写入前 | 停止;不创建远端变更,只清理本次临时目录 | +| disabled 安装后 | timer 保持停用,恢复升级前 probe/helper/units,daemon-reload,验证状态与 dead-man 基线 | +| oneshot 后、enable 前 | 同上;若状态已迁移,按状态兼容流程保留/移出精确文件 | +| enable 后 | 先 disable/stop,恢复文件与 units;确认真实健康和状态可读后按升级前基线决定是否重启旧 timer | +| 自然告警已发出且恢复失败 | timer 保持停用,保留证据并报告告警未闭环;不伪造恢复消息 | + +## 7. Evidence and Privacy + +允许记录:候选短提交号、检查 PASS/FAIL、哈希相等布尔值、固定 mode、schema/phase、timer/service enabled/active、稳定状态类别和观察时间。禁止记录:主机/IP、用户名、完整远端配置路径、webhook/Secret、原始状态、响应正文、journal 或企微 payload。 + +## 8. Trade-offs + +- 不做真实故障演练,避免人为制造正式企微运维消息;代价是本轮只验证升级后的真实健康运行和本地完整状态机合同,不重复证明机器人故障/恢复收件链。 +- 保留并迁移现有状态,能维持事件连续性;代价是回滚必须处理旧版不识别 v2 的兼容边界。 +- 观察两个调度窗口会延长完成时间约 10 分钟,但能证明 timer 不只是 enabled,而是确实连续运行。 diff --git a/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/implement.jsonl b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/implement.jsonl new file mode 100644 index 00000000..9dd3234a --- /dev/null +++ b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/implement.jsonl @@ -0,0 +1 @@ +{"_example": "Fill with {\"file\": \"\", \"reason\": \"\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."} diff --git a/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/implement.md b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/implement.md new file mode 100644 index 00000000..c9daa170 --- /dev/null +++ b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/implement.md @@ -0,0 +1,75 @@ +# ARM 公网健康监控受控部署实施计划 + +## 1. Local Quality Gate + +1. 确认当前 HEAD 包含 `a0f0483`,并从该提交核验探测器、helper、安装器来源。 +2. 确认本任务之外的报销工作区改动不进入部署源、暂存或提交。 +3. 运行应用健康合同、自动备份合同、安装器语法和必要治理门禁。 +4. 记录三个部署源 SHA-256 的匹配证据,不输出无关路径或内容。 + +## 2. ARM Read-only Preflight + +1. 通过既有受控 alias 连接,核对身份与非交互 root 入口。 +2. 只读检查 Python/systemd、公网 `/ready`、应用健康 service/timer、备份 dead-man service/timer。 +3. 在远端内部解析 webhook 路径,只返回 regular-file/root/0600 布尔结果。 +4. 严格校验现有 probe/alert state 的允许字段、schema/phase 和 mode,不打印原始 JSON。 +5. 记录升级前探测器/helper/units 的哈希与 timer enabled/active 基线。 +6. 任一门禁异常时停止;不上传、不写 systemd、不调整权限。 + +## 3. Rollback Preparation and Disabled Install + +1. 在 ARM 同一受控文件系统创建本次唯一回滚目录,复制精确的受管 probe/helper/units 和允许的状态证据;逐项核对普通文件、owner/mode 和哈希。 +2. 创建本次唯一临时上传目录,传输提交版本的探测器、helper、安装器并核对 SHA-256。 +3. 使用远端内部 webhook 路径运行安装器 `install`。 +4. 验证 timer disabled/inactive、service inactive、固定 ExecStart/5 分钟合同、owner/mode、已安装文件哈希和状态目录隔离。 +5. 如失败,按设计矩阵恢复升级前文件并停在 disabled 状态。 + +## 4. Disabled Health Verification + +1. timer 保持 disabled,启动一次正式 systemd service 对真实公网 `/ready` 探测。 +2. 验证 service 成功、probe state schema v2/phase 合法、状态文件 `0600`,且未出现非预期通知状态变化。 +3. 再次核对备份 dead-man 基线不变。 +4. 只有全部通过才进入 enable。 + +## 5. Controlled Enable and Observation + +1. 运行安装器 `enable`,确认 timer enabled/active 和 5 分钟调度合同。 +2. 不制造故障、不变更 URL/DNS、不直接调用机器人。 +3. 观察至少两个连续 timer 窗口,核对两次 service 成功、状态合法、无重复消息异常。 +4. 核对备份 dead-man enabled/active 与升级前一致。 + +## 6. Cleanup and Closeout + +1. 精确删除本次临时上传目录;回滚材料在完成观察和最终确认前保留,后续清理由独立授权处理。 +2. 若使用临时 sudoers,精确删除并验证原权限基线恢复。 +3. 更新当前 task 的脱敏执行证据与 AC;不新建无必要文档。 +4. 运行 task validate、Trellis governance、敏感扫描和 `git diff --check`。 +5. 只提交当前 task 必要的执行记录;不纳入并行报销任务改动。 + +## Validation Commands + +```bash +bash scripts/qa/run-app-health-monitor-contract.sh +bash scripts/qa/run-automatic-backup-contract.sh +bash -n deploy/trialrun/install-offhost-app-health-monitor.sh +node scripts/qa/check-process-contract.mjs --baseline --json +node scripts/qa/check-trellis-governance.mjs +python3 ./.trellis/scripts/task.py validate 08-23-arm-public-health-monitor-controlled-rollout +git diff --check +``` + +远端命令通过受控 alias 和远端内部变量执行;任务文档不固化主机、用户名、完整路径、webhook 或原始输出。 + +## Risky Targets and Stop Points + +- 共用 helper:部署前必须通过自动备份共享合同;远端不得触发 dead-man。 +- probe state:v1→v2 后旧版不能直接回读;回滚必须保留并移出精确 v2 状态,不能手改伪造。 +- installer `install`:会先停 timer 并覆盖受管文件;调用前必须已有可验证的同机回滚副本。 +- `enable`:会恢复 ARM 对腾讯云 OA 的真实公网监控,真实异常可能自然触发群消息;disabled oneshot 未通过不得执行。 +- 任何密码提示、状态不一致、哈希漂移、真实 `/ready` 异常或 dead-man 基线变化:立即停止并按阶段回滚。 + +## Approval Boundary + +本计划覆盖:ARM 受管文件/systemd 写入、disabled 安装、正式 `/ready` oneshot、受控启用和两个调度窗口观察。 + +本计划不覆盖:DNS 修改、故障注入、真实企微测试消息、业务数据写入、备份配置修改或历史材料清理。 diff --git a/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/prd.md b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/prd.md new file mode 100644 index 00000000..a9c9511c --- /dev/null +++ b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/prd.md @@ -0,0 +1,107 @@ +# ARM 公网健康监控受控部署 + +## Goal + +把提交 `a0f0483` 中已通过本地合同的公网健康诊断与防抖增强,安全升级到现有 ARM 异机监控;保留已有脱敏状态和备份 dead-man 能力,先安装为 disabled 并完成只读核验,再受控启用 5 分钟 timer。部署后只以真实公网 `/ready` 的自然结果运行,不制造故障、不发送专门测试消息。 + +## Background and Confirmed Facts + +- `08-23-wecom-public-health-alert-diagnostics-and-debounce` 已完成本地实现:DNS/TCP 分类分离、连续 2 次健康恢复、60 分钟同类复发抖动提醒、连续健康 30 分钟静默退出,以及“OA 公网健康”专用标题。 +- 本地应用健康合同 36 项、自动备份共享合同 74 项均通过;候选工作提交为 `a0f0483`,归档提交为 `42bbbda`。 +- 腾讯云服务器是 OA 真实生产主机,运行 OA 应用、数据库及公网入口;ARM 是独立异机备份与外部健康探测节点,不运行 OA 服务。应用健康探测器部署在 ARM,并从外部访问腾讯云 OA 的公网 `/ready`。 +- 2026-07-27 已在 ARM 安装并启用旧版监控,现有应用健康探测器、两个 systemd units、独立状态目录及共用企微 helper 均可能存在;本次是原位升级,不适用首次安装时的“必须不存在”前提。 +- 现有安装器 `install` 会先停用应用健康 timer,再覆盖固定的探测器、helper 和 units,并保留状态目录;`enable` 会重新安装后启用 timer。 +- 用户已同意为本次 ARM 监控节点 rollout 建立 Trellis task,并允许按“默认禁用安装 → 只读检查 → 受控启用”规划;该授权不包含腾讯云 OA 应用部署或配置变更。 + +## Requirements + +### R1 — 本地与来源门禁 + +- 部署源必须来自已提交的 `a0f0483`,且探测器、helper、安装器相对该提交无漂移。 +- 远端写入前复跑应用健康合同和自动备份共享合同;任一失败即停止。 +- 不使用工作区中未提交的报销任务文件,不把当前 Trellis 文档作为远端部署源。 + +### R2 — ARM 只读预检 + +- 写入前通过既有受控 SSH 入口核对身份、`sudo -n`、Python、systemd、当前应用健康 timer/service、备份 dead-man 基线和公网 `/ready`。 +- 只在 ARM 内解析并验证现有 root-owned `0600` webhook 文件路径;不得读取、传输或回显正文。 +- 记录现有探测器/helper/unit 的哈希匹配结果、允许的状态 schema/phase、timer enabled/active 和 dead-man 基线;证据只包含布尔值、稳定 token、短提交号和哈希是否匹配。 +- `sudo -n` 需要密码、现有对象为符号链接/权限异常、状态无法解析、真实 `/ready` 不健康或备份 dead-man 基线异常时,停止在写入前并报告。 + +### R3 — Disabled 原位升级 + +- 只上传已提交的探测器、共用 helper 和安装器到本次唯一临时目录,并核对源/上传件 SHA-256。 +- 运行安装器 `install`,只覆盖固定的应用健康探测器、共用 helper 和两个应用健康 units;保留现有应用健康状态、alert state、webhook、备份 receiver/dead-man、归档和其他 systemd 对象。 +- 安装后 timer 必须为 disabled/inactive;探测器/helper 为 root:root `0755`,units 为 `0644`,状态目录为 root:root `0700`,已有状态文件为 `0600`。 +- 已安装探测器/helper 必须与 `a0f0483` 的候选哈希一致,unit 仍固定正式 HTTPS `/ready`、失败阈值 2、5 分钟周期和安全目标路径。 + +### R4 — Disabled 状态核验 + +- 在 timer disabled 时只运行正式 systemd oneshot 对真实公网 `/ready` 做一次健康检查,不改 URL、DNS,也不人工编辑状态内容。 +- oneshot 必须成功,状态 schema 必须为 v2 且只包含允许字段;健康基线不得产生故障或恢复消息。 +- 如旧状态迁移后自然形成一个通知候选,立即停止启用并报告,不以删除或伪造状态来压制消息。 + +### R5 — 受控启用与观察 + +- R1–R4 全部通过后,才运行安装器 `enable`;不执行不可达端口、停服务、改 DNS 等故障注入。 +- timer 最终必须 enabled/active,调度周期仍为 5 分钟,最近一次 service 成功,下一次计划时间符合 timer 合同。 +- 启用后至少观察两个连续调度窗口,并核对状态 schema/phase、service 结果和消息去重状态;允许真实健康异常自然触发生产运维消息,但不发送专门测试消息。 +- 备份 dead-man 的 unit/timer 状态和共用标题合同必须保持不变。 + +### R6 — 停止与回滚 + +- 任一步出现身份、权限、哈希、unit、状态、真实健康或备份基线不一致时,停止扩大变更并保留脱敏证据。 +- disabled 安装后、enable 前失败:恢复升级前探测器/helper/units 的同机备份,保留状态目录,再核对 timer 回到升级前状态;不得删除共用 webhook、备份组件或归档。 +- enable 后失败:先 disable/stop 应用健康 timer,恢复升级前文件和 units,执行 daemon-reload,并按升级前 enabled/active 基线恢复 timer;只有确认真实 `/ready` 健康和旧版可读取状态后才重新启用。 +- 若新版已写入旧版不能读取的 schema v2,回滚时先保留精确状态文件副本,再将精确状态文件移出活动目录,让旧版建立新健康基线;不得伪造恢复状态。 +- 若正式健康告警已经自然发出但无法闭环恢复,保持 timer 停用并明确报告“告警未闭环”,不发送人工伪造的恢复消息。 + +### R7 — 隐私、清理与报告 + +- 不在聊天、Trellis、日志摘要或提交中保存主机地址、用户名、完整远端路径、webhook、Secret、原始响应、journal 或企微 payload。 +- 删除本次精确临时上传目录和临时权限入口;若使用临时 sudoers,必须在同一受控 root 流程中校验后删除,并证明原非交互权限已恢复到基线。 +- 未完成远端检查前不得报告“已部署”;未观察两个调度窗口前不得报告“运行稳定”。 + +## Acceptance Criteria + +- [x] **AC1 / R1**:候选来源固定为 `a0f0483`,本地 36 项应用健康合同和 74 项自动备份合同再次通过,部署源无漂移。 +- [x] **AC2 / R2**:ARM 写入前预检通过,且证据不含凭证、地址、完整路径、原始响应或 payload。 +- [x] **AC3 / R2**:记录升级前应用健康与备份 dead-man 的脱敏基线;现有状态可严格解析,回滚材料已在 ARM 同机受控保存。 +- [x] **AC4 / R3**:disabled 安装后 timer 明确 disabled/inactive,受管文件、units、权限、固定目标和 SHA-256 全部符合合同。 +- [x] **AC5 / R4**:timer disabled 时正式 oneshot 对公网 `/ready` 成功,状态安全迁移至 schema v2,未产生测试或恢复噪声。 +- [x] **AC6 / R5**:受控启用后 timer enabled/active,连续两个调度窗口成功且状态/消息去重无异常。 +- [x] **AC7 / R5**:备份 receiver/dead-man、归档和共享非应用健康标题均未改变。 +- [x] **AC8 / R6**:每个阶段都有可执行停止/回滚点;本轮未触发回滚,最终 timer 状态、真实健康和备份基线均完成复核。 +- [x] **AC9 / R7**:临时上传与临时权限已精确清理,最终证据仅包含允许的脱敏字段。 + +## Scope + +- 从提交 `a0f0483` 取得并复核探测器、企微 helper 与既有安装器。 +- 对现有 ARM 应用健康监控执行只读预检、同机回滚准备、disabled 原位升级和正式 `/ready` oneshot。 +- 前置门禁全部通过后启用 5 分钟 timer,并观察两个连续调度窗口。 +- 核对应用健康独立状态、共享 helper 兼容和备份 dead-man 基线,完成临时材料清理及脱敏记录。 + +## Out of Scope + +- 修改 DNS、resolver、Caddy、TLS 证书、OA 应用、数据库、Compose 或业务数据。 +- 故意制造失败、停止真实服务、使用不可达端口或发送企微测试消息。 +- 修改机器人配置、webhook 内容、备份 receiver/dead-man 配置、归档或保留策略。 +- 清理历史状态、历史告警、旧候选文件或其他并行任务改动。 +- 宣称 ARM 监控具备第三方 dead-man 能力。 + +## Test Plan + +- 本地:应用健康合同、自动备份合同、安装器 Shell 语法、process baseline、Trellis governance、task validate、敏感扫描和 `git diff --check`。 +- ARM 写前:连接/权限、当前版本/哈希、应用健康和 dead-man timer/service、状态 schema、webhook 文件属性、公网 `/ready` 的脱敏布尔检查。 +- ARM 写后 disabled:哈希、owner/mode、unit 固定合同、timer disabled/inactive、正式 oneshot 和 schema v2。 +- ARM enable 后:enabled/active、两个连续调度窗口、最近 service 成功、状态/去重 token、dead-man 基线不变、临时材料清理。 + +## Execution Evidence + +- 2026-08-23:候选提交门禁、安装器 Shell 语法、应用健康合同 36 项、自动备份共享合同 74 项和 process baseline 均通过;测试 capture 未访问真实企微。 +- 2026-08-23:既有 ARM SSH alias 可非交互连接,但首个写前门禁 `sudo -n true` 返回需要密码;流程在任何 root 检查、上传或远端写入前停止。 +- 2026-08-23:用户在 ARM 侧建立临时非交互 sudo 运维入口后,完整只读预检通过:旧应用健康 timer 和备份 dead-man 均 enabled/active,probe state 为有效 v1,webhook 文件合同与腾讯云 OA 公网 `/ready` 均通过。 +- 2026-08-23:候选上传哈希、同机回滚副本、disabled 原位安装、受管文件权限和固定 unit 合同均通过;正式 oneshot 成功把 probe state 从 v1 保守迁移为 v2/healthy,alert state 未变化,未产生恢复噪声。 +- 2026-08-23:timer 受控启用后连续两个自然调度窗口成功,probe 保持 v2/healthy,未出现非预期企微消息,备份 dead-man 基线未变化。腾讯云 OA 应用、数据库、DNS 和业务数据均未修改。 +- 2026-08-23:三个临时上传文件和空目录已精确删除;临时 sudoers 已删除、sudoers 全量语法通过,`sudo -n` 恢复为不可用。ARM 同机回滚副本按计划保留,后续清理需另行授权。 +- 2026-08-23:收尾 task validate、Trellis governance、process baseline、敏感扫描和 `git diff --check` 均通过;文档审计 errors=0,仅保留既有未登记文件 warning。 diff --git a/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/task.json b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/task.json new file mode 100644 index 00000000..4c8b7d6a --- /dev/null +++ b/.trellis/tasks/08-23-arm-public-health-monitor-controlled-rollout/task.json @@ -0,0 +1,35 @@ +{ + "id": "arm-public-health-monitor-controlled-rollout", + "name": "arm-public-health-monitor-controlled-rollout", + "title": "ARM 公网健康监控受控部署", + "description": "将已通过本地合同的公网健康诊断与防抖增强受控升级到 ARM 异机监控节点,继续从外部探测腾讯云 OA 生产主机,并按 disabled 安装、核验、启用顺序完成 rollout。", + "status": "in_progress", + "dev_type": null, + "scope": "operations", + "package": null, + "priority": "P2", + "creator": "shunli", + "assignee": "shunli", + "createdAt": "2026-08-23", + "completedAt": null, + "branch": null, + "base_branch": "main", + "worktree_path": null, + "commit": null, + "pr_url": null, + "subtasks": [], + "children": [], + "parent": null, + "relatedFiles": [ + "scripts/check-public-app-health.py", + "scripts/send-wecom-group-alert.py", + "deploy/trialrun/install-offhost-app-health-monitor.sh", + "scripts/qa/run-app-health-monitor-contract.sh", + "scripts/qa/run-automatic-backup-contract.sh", + ".trellis/spec/hyb-oa/deployment-trialrun.md", + "docs/试运行与自动化验证手册.md", + "deploy/trialrun/runbook.md" + ], + "notes": "ARM 外部健康监控已从提交 a0f0483 受控升级并启用;连续两个自然调度窗口为 v2/healthy,无非预期企微消息,备份 dead-man 不变。临时上传和 sudoers 已清理,回滚副本保留;腾讯云 OA、DNS 和业务数据未修改。", + "meta": {} +} diff --git a/deploy/trialrun/runbook.md b/deploy/trialrun/runbook.md index 24a5b800..80a53472 100644 --- a/deploy/trialrun/runbook.md +++ b/deploy/trialrun/runbook.md @@ -376,10 +376,12 @@ RESTORE_SCOPE=shadow \ ## 1.6 ARM 公网应用健康监控(已启用) -应用健康监控与自动备份 dead-man 共用受控企微群机器人入口,但使用独立探测器、systemd units、probe state 和 alert state。它从 ARM 每 5 分钟访问公网 HTTPS `/ready`;连续两次失败才告警,一次成功即恢复。不得把它并入备份 receiver 的安装/卸载生命周期,也不得以本地测试通过代替 ARM 已启用证据。 +应用健康监控与自动备份 dead-man 共用受控企微群机器人入口,但使用独立探测器、systemd units、probe state 和 alert state。腾讯云服务器是 OA 真实生产主机,ARM 是不运行 OA 服务的异机备份与外部健康探测节点。ARM 每 5 分钟访问公网 HTTPS `/ready`;连续两次失败才告警,告警后连续两次健康才恢复;恢复后 60 分钟内同类故障再次达到阈值时只提醒一次链路抖动,连续健康 30 分钟后静默退出抖动。不得把它并入备份 receiver 的安装/卸载生命周期,也不得以本地测试通过代替 ARM 已启用证据。 2026-07-27 已完成 ARM disabled 安装、手工公网健康基线、timer 启用及不影响 OA 的真实故障/降噪/恢复演练;自动链路显示一条故障和一条恢复发送成功,用户确认群内实际收到两条消息。timer 最终 enabled/active、最近 service 成功,备份 dead-man 状态未变,临时上传和临时 sudoers 已删除。 +2026-08-23 已把提交 `a0f0483` 的诊断与防抖增强受控升级到 ARM:本地应用健康 36 项和备份共享 74 项合同通过;disabled 安装后正式 oneshot 将 probe state 从 v1 保守迁移为 v2/healthy,且未发送恢复噪声;启用后连续两个自然调度窗口成功、无非预期企微消息、备份 dead-man 基线不变。临时上传和 sudoers 已删除,同机回滚副本按批准边界保留;本轮未修改腾讯云 OA、DNS 或业务数据,也未执行故障注入或测试消息。 + 先在仓库运行无真实消息合同: ```bash diff --git a/docs/试运行与自动化验证手册.md b/docs/试运行与自动化验证手册.md index 5fd3aa7b..65f7b1af 100644 --- a/docs/试运行与自动化验证手册.md +++ b/docs/试运行与自动化验证手册.md @@ -158,7 +158,7 @@ cd client && E2E_BASE_URL=https://oa.hyinda.com npx playwright test tests/e2e/dg 2026-07-27 已完成 ARM 安装、启用和真实故障/恢复演练:timer 为 enabled/active,首次失败 pending、第二次发送、重复失败降噪、正式恢复发送、重复健康降噪,用户确认群内实际收到一条故障与一条恢复通知;备份 dead-man 未受影响,临时上传和临时 sudoers 已删除。 -`08-23-wecom-public-health-alert-diagnostics-and-debounce` 已完成本地候选增强:DNS 与 TCP 分类分离;应用消息标题明确为“OA 公网健康”;恢复改为连续 2 次健康确认;正常恢复后 60 分钟内同类故障再次达到 2 次失败时只发送一次链路反复抖动提醒,后续切换只保留脱敏计数,连续健康 30 分钟后静默退出。该结论目前只代表本地合同通过,尚未部署到 ARM,不能据此声称群消息已经改变。ARM rollout、真实消息和 DNS 修改仍需分别批准。先运行本地无真实消息合同: +`08-23-wecom-public-health-alert-diagnostics-and-debounce` 已完成诊断与防抖增强:DNS 与 TCP 分类分离;应用消息标题明确为“OA 公网健康”;恢复改为连续 2 次健康确认;正常恢复后 60 分钟内同类故障再次达到 2 次失败时只发送一次链路反复抖动提醒,后续切换只保留脱敏计数,连续健康 30 分钟后静默退出。先运行本地无真实消息合同: ```bash bash scripts/qa/run-app-health-monitor-contract.sh @@ -173,6 +173,8 @@ systemctl list-timers hyb-oa-public-app-health.timer --no-pager systemctl status hyb-oa-public-app-health.service --no-pager ``` +2026-08-23,`08-23-arm-public-health-monitor-controlled-rollout` 已把提交 `a0f0483` 的增强版受控升级到 ARM 外部健康监控节点;腾讯云服务器仍是 OA 真实生产主机,ARM 不运行 OA 服务。部署依次通过本地 36 项应用健康合同、74 项备份共享合同、ARM 只读预检、disabled 安装和正式 `/ready` oneshot;probe state 从 v1 保守迁移为 v2/healthy,未产生恢复噪声。timer 启用后连续两个自然调度窗口成功且无非预期企微消息,备份 dead-man 基线不变。临时上传和 sudoers 已清理,回滚副本按批准边界保留;本轮未修改腾讯云 OA、DNS、业务数据或企微配置,也未执行故障注入或测试消息。 + 增强版受控演练必须证明:第一次失败仅进入 pending;第二次持续失败只发一条;重复失败降噪;第一次健康不恢复、第二次连续健康只恢复一条;60 分钟内同类复发只产生一条抖动提醒;连续健康 30 分钟后静默退出。群消息只允许状态和稳定类别,不粘贴地址、路径、响应、凭证或 journal 原文。ARM 自身宕机仍会令该 timer 失声,首版保留为人工 timer 巡检风险,不据此宣称具备第三方 dead-man。 发布候选进入公网或小范围试运行前,先按 [`docs/trialrun/发布试运行准备清单.md`](trialrun/发布试运行准备清单.md) 完成证据整理、权限直连审计、部署预检、live smoke 和试运行分级。