部署(arm-public-health-monitor-controlled-rollout): 完成 ARM 公网健康监控升级

这个提交包含在:
2026-08-23 12:49:17 +08:00
父节点 42bbbdae22
当前提交 c4604f3fb1
共修改 9 个文件,包含 308 行新增和 2 行删除
@@ -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. timer, application-health alert states or the shared WeCom group-alert helper.
- Purpose: detect an unavailable OA host, edge/TLS path, application or database - Purpose: detect an unavailable OA host, edge/TLS path, application or database
readiness signal without adding a time-series platform or relying on traffic. 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 ### 2. Signatures
@@ -1442,6 +1446,9 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ...
install|enable|uninstall`. install|enable|uninstall`.
- Units: `hyb-oa-public-app-health.service` and - Units: `hyb-oa-public-app-health.service` and
`hyb-oa-public-app-health.timer`; the timer uses `OnCalendar=*:0/5`. `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`. - Local contract: `bash scripts/qa/run-app-health-monitor-contract.sh`.
- Application statuses: `FAIL_APP_HEALTH`, `PASS_APP_HEALTH_READY` and - Application statuses: `FAIL_APP_HEALTH`, `PASS_APP_HEALTH_READY` and
`FAIL_APP_HEALTH_FLAPPING`. `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. - 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`. 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 - Classify DNS resolution and TCP connection failures separately before the
shared fallback catches `OSError`; keep TLS, timeout, HTTP, response-size and shared fallback catches `OSError`; keep TLS, timeout, HTTP, response-size and
response-contract categories stable. Count any stable failure category toward 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. is incomplete even when the timer is healthy.
- ARM itself or its network/robot path unavailable -> the monitor can be silent; - 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. 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 ### 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. 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 - 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. 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 ### 6. Tests Required
@@ -1553,6 +1569,10 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ...
helper allowlist or behavior changes. helper allowlist or behavior changes.
- ARM install, enabled/active timer status and real failure/recovery messages are - ARM install, enabled/active timer status and real failure/recovery messages are
external evidence and may not be inferred from the local contract. 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 ### 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. # alternating alert/recovery messages during a flapping link.
bash scripts/qa/run-app-health-monitor-contract.sh bash scripts/qa/run-app-health-monitor-contract.sh
bash deploy/trialrun/install-offhost-app-health-monitor.sh enable bash deploy/trialrun/install-offhost-app-health-monitor.sh enable
# Wrong target classification: the off-host monitor is not DEPLOY_SERVER.
DEPLOY_SERVER=<arm-monitor-target> bash deploy/trialrun/deploy-existing.sh
``` ```
#### Correct #### Correct
@@ -1576,6 +1598,8 @@ bash scripts/qa/run-automatic-backup-contract.sh
# enable/real-message/drill approval before claiming the monitor is active. # enable/real-message/drill approval before claiming the monitor is active.
<explicit-controlled-paths> \ <explicit-controlled-paths> \
bash deploy/trialrun/install-offhost-app-health-monitor.sh install bash deploy/trialrun/install-offhost-app-health-monitor.sh install
# OA application deployment keeps its separately approved Tencent Cloud target.
DEPLOY_SERVER=<tencent-oa-production-target> bash deploy/trialrun/deploy-existing.sh
``` ```
## Scenario: Existing Deployment Preflight And Cache Stability ## Scenario: Existing Deployment Preflight And Cache Stability
@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. 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."}
@@ -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,而是确实连续运行。
@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. 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."}
@@ -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 修改、故障注入、真实企微测试消息、业务数据写入、备份配置修改或历史材料清理。
@@ -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。
@@ -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": {}
}
+3 -1
查看文件
@@ -376,10 +376,12 @@ RESTORE_SCOPE=shadow \
## 1.6 ARM 公网应用健康监控(已启用) ## 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-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 ```bash
+3 -1
查看文件
@@ -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 已删除。 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
bash scripts/qa/run-app-health-monitor-contract.sh 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 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。 增强版受控演练必须证明:第一次失败仅进入 pending;第二次持续失败只发一条;重复失败降噪;第一次健康不恢复、第二次连续健康只恢复一条;60 分钟内同类复发只产生一条抖动提醒;连续健康 30 分钟后静默退出。群消息只允许状态和稳定类别,不粘贴地址、路径、响应、凭证或 journal 原文。ARM 自身宕机仍会令该 timer 失声,首版保留为人工 timer 巡检风险,不据此宣称具备第三方 dead-man。
发布候选进入公网或小范围试运行前,先按 [`docs/trialrun/发布试运行准备清单.md`](trialrun/发布试运行准备清单.md) 完成证据整理、权限直连审计、部署预检、live smoke 和试运行分级。 发布候选进入公网或小范围试运行前,先按 [`docs/trialrun/发布试运行准备清单.md`](trialrun/发布试运行准备清单.md) 完成证据整理、权限直连审计、部署预检、live smoke 和试运行分级。