部署(arm-public-health-monitor-controlled-rollout): 完成 ARM 公网健康监控升级
这个提交包含在:
@@ -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": {}
|
||||||
|
}
|
||||||
@@ -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 和试运行分级。
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户