完成 ARM 应用健康监控上线(07-27-arm-app-health-rollout)
这个提交包含在:
@@ -1135,6 +1135,12 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ...
|
||||
- `install` writes only the exact managed probe/helper/state/unit targets and
|
||||
leaves the timer disabled. `enable`, ARM writes, real robot messages and a
|
||||
controlled failure/recovery drill remain separately approved operations.
|
||||
- Before any remote write, prove the selected SSH identity can run `sudo -n`
|
||||
and that no application-health artifact already exists. A password prompt is
|
||||
a stop condition, not permission to request or transmit a password in chat.
|
||||
If the operator creates a temporary privilege rule, remove its exact file at
|
||||
the end, validate sudoers in the same root invocation, invalidate the sudo
|
||||
timestamp and prove the original non-interactive access is gone.
|
||||
- `uninstall` removes only the exact application-health units and probe. It
|
||||
retains the shared helper, webhook, state evidence and all backup components.
|
||||
|
||||
@@ -1149,6 +1155,11 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ...
|
||||
- A first isolated failure followed by health -> no failure or recovery message.
|
||||
- Any overridden managed target or service name -> installer stops before
|
||||
`systemctl`, file replacement or removal.
|
||||
- SSH succeeds but `sudo -n` requests a password -> stop before upload or
|
||||
systemd mutation; resume only after an operator establishes a separately
|
||||
approved, non-chat root path and rerun the complete preflight.
|
||||
- Temporary privilege rule remains after final health verification -> rollout
|
||||
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.
|
||||
|
||||
@@ -1169,6 +1180,10 @@ PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ...
|
||||
corrupt private state, URL rejection and absence of sensitive output.
|
||||
- Run Python compile and shell syntax checks, validate the five-minute calendar,
|
||||
and assert disabled-by-default plus exact managed targets and retained state.
|
||||
- For a remote rollout, record boolean evidence for pre-write `sudo -n`, exact
|
||||
temporary-upload removal, temporary privilege removal and post-removal
|
||||
non-interactive-sudo failure; never record the password, host address or rule
|
||||
contents.
|
||||
- Re-run `bash scripts/qa/run-automatic-backup-contract.sh` whenever the shared
|
||||
helper allowlist or behavior changes.
|
||||
- ARM install, enabled/active timer status and real failure/recovery messages are
|
||||
|
||||
@@ -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,57 @@
|
||||
# ARM 应用健康监控上线设计
|
||||
|
||||
## 1. Safety Boundary
|
||||
|
||||
上线只改变 ARM 上的应用健康探测器、两个 systemd units 和独立状态目录;共用 helper 会更新为仓库已通过备份回归的版本,但不修改 webhook、备份 receiver、dead-man、归档或 OA 主机。所有远端写操作通过非交互 sudo 执行;若预检不满足,任务停在只读阶段。
|
||||
|
||||
## 2. Source and Secret Provenance
|
||||
|
||||
部署源固定为工作提交 `bb5113c` 中的探测器、helper 和安装器。先确认三个部署源相对 `HEAD` 无未提交改动并复跑专项/备份合同;当前 Trellis 任务记录可按正常流程保持未提交。安装前后比较 SHA-256;不使用远端旧仓库或聊天中的粘贴内容。
|
||||
|
||||
webhook 文件路径从既有 `hyb-oa-offhost-deadman.service` 的 `ExecStart` 参数在 ARM 内解析。解析结果必须是绝对路径、普通非符号文件、root-owned、mode `0600`;流程从不读取文件正文,也不把路径打印到会话证据。
|
||||
|
||||
## 3. Rollout Sequence
|
||||
|
||||
```text
|
||||
local contracts
|
||||
-> ARM read-only preflight
|
||||
-> reject pre-existing app-health artifacts
|
||||
-> upload committed sources to temporary directory
|
||||
-> sudo installer install (disabled)
|
||||
-> verify hashes/permissions/units
|
||||
-> manual real /ready baseline
|
||||
-> sudo installer enable
|
||||
-> verify timer
|
||||
-> stop only app-health timer
|
||||
-> direct probe #1 against localhost unreachable HTTPS (pending)
|
||||
-> direct probe #2 (one real failure alert)
|
||||
-> direct probe #3 (deduplicated)
|
||||
-> start formal service against public /ready (one recovery)
|
||||
-> start timer and verify final state
|
||||
-> remove temporary directory
|
||||
```
|
||||
|
||||
失败命令预期非零时必须显式捕获退出码,不能让 shell 把受控故障误判为 rollout 脚本崩溃。状态验证只读取允许字段:schema version、连续失败计数、稳定类别、告警状态和 helper 的 `sent=true|false`。
|
||||
|
||||
## 4. Drill Isolation
|
||||
|
||||
演练不改 unit、不改 DNS、不停止公网服务。timer 暂停后,以 root 直接执行已安装探测器,目标为 ARM 本机一个预先确认未监听的低风险 TCP 端口,超时 1 秒;其余参数使用正式状态目录、helper 和 webhook。这样覆盖真实 TLS/连接分类、失败阈值、helper、机器人和恢复链,同时不会影响 OA 用户。
|
||||
|
||||
正式恢复必须通过 systemd service 执行真实公网 `/ready`,从而同时验证已安装 unit。成功后恢复 timer,并再观察至少一次定时健康执行或核对最近成功时间。
|
||||
|
||||
## 5. Rollback and Alert Closure
|
||||
|
||||
- 安装前失败:无远端写入,仅清理临时目录。
|
||||
- 安装后、真实告警前失败:disable/stop 并运行安装器 `uninstall`,保留独立状态证据和共用文件。
|
||||
- 真实告警后失败:先移除故障输入并运行正式 service 争取发送恢复通知;成功后可决定保留或卸载。若恢复仍失败,timer 保持停用,明确报告群内告警未闭环,不伪造恢复。
|
||||
- 任一路径都不删除共用 helper、webhook、备份 dead-man、receiver 或归档。
|
||||
|
||||
## 6. Evidence and Privacy
|
||||
|
||||
证据记录提交短哈希、布尔预检、文件哈希比对结果、固定权限、systemd enabled/active、稳定故障类别、连续次数和 helper 发送布尔值。不得保存 SSH 地址、IP、用户名、webhook、完整远端路径、原始 `/ready` 响应、journal 或企微 payload。
|
||||
|
||||
人工收件确认与自动链路证据分开:脚本显示发送成功不等于用户已经看到消息,最终 AC9 需用户确认。
|
||||
|
||||
## 7. Compatibility
|
||||
|
||||
安装器会更新共用 helper,因此上线前必须复跑 73 项自动备份合同。上线后只检查既有 dead-man unit/timer 仍存在且状态未变,不主动运行 dead-man,避免归档异常时产生额外真实告警。
|
||||
@@ -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. Local Gates
|
||||
|
||||
- [x] 确认 `HEAD` 包含工作提交 `bb5113c`,三个部署源相对 `HEAD` 无未提交改动;允许当前 Trellis 任务记录保持未提交。
|
||||
- [x] 运行应用健康专项 22 项和自动备份兼容回归 73 项。
|
||||
- [x] 记录三个部署源文件的 SHA-256,不输出其他本地路径或配置。
|
||||
|
||||
## 2. Read-only ARM Preflight
|
||||
|
||||
- [x] 通过受控 alias 连接,确认非交互命令可用;首次 sudo 门禁停止,用户建立临时入口后复检通过。
|
||||
- [x] 确认 Python 3、systemd、既有 off-host dead-man service/timer 和共用 helper 存在。
|
||||
- [x] 在 ARM 内从 dead-man unit 解析 webhook 文件路径,并只返回 owner/mode/regular-file 布尔结果。
|
||||
- [x] 确认公网 `/ready` 从 ARM 可达,且应用健康 unit、探测器和状态目录尚不存在;若存在则停止人工审查。
|
||||
- [x] 记录既有 dead-man timer enabled/active 基线,后续只做对比,不主动执行。
|
||||
|
||||
## 3. Disabled Installation
|
||||
|
||||
- [x] 在 ARM 创建本次唯一临时目录,以 SCP 传输探测器、helper 和安装器并核对 SHA-256。
|
||||
- [x] 用 root 运行安装器 `install`,webhook 路径只在远端 shell 变量中传递。
|
||||
- [x] 确认 timer disabled/inactive、service inactive,unit 为 5 分钟、状态目录 0700、受管文件 root:root 0755。
|
||||
- [x] 比较已安装探测器/helper 与提交源哈希一致。
|
||||
- [x] 手工启动正式 service,确认健康、probe/alert state 为 0600 且没有发送恢复噪声。
|
||||
|
||||
## 4. Enable and Real Drill
|
||||
|
||||
- [x] 用同一提交源执行安装器 `enable`,确认 timer enabled/active。
|
||||
- [x] 停止应用健康 timer;确认不影响备份 dead-man timer。
|
||||
- [x] 确认选定 localhost 演练端口未监听。
|
||||
- [x] 第一次直接失败探测:预期非零、`consecutiveFailures=1`、alert pending。
|
||||
- [x] 第二次直接失败探测:预期非零、helper `sent=true`、alert state 为 `FAIL_APP_HEALTH`。
|
||||
- [x] 第三次直接失败探测:预期非零、helper `sent=false`,证明相同类别降噪。
|
||||
- [x] 运行正式 systemd service 恢复:预期成功、helper `sent=true`、alert state 为 `PASS_APP_HEALTH_READY`。
|
||||
- [x] 再运行一次健康探测或等待 timer:预期 helper `sent=false`。
|
||||
- [x] 重新启动 timer,确认 enabled/active、最近成功和下一次不超过 5 分钟。
|
||||
|
||||
## 5. Final Evidence and Cleanup
|
||||
|
||||
- [x] 确认既有备份 receiver/dead-man 文件和 timer 状态未改变。
|
||||
- [x] 删除本次 ARM 临时传输目录和临时 sudoers 规则,不删除状态、helper、webhook 或备份能力。
|
||||
- [x] 仅记录脱敏状态、类别、计数、哈希匹配和 timer 布尔证据。
|
||||
- [x] 用户已确认群内实际收到一条故障告警和一条恢复通知。
|
||||
- [ ] 更新 PRD 验收项、运行 task validate、治理检查和 `git diff --check`。
|
||||
|
||||
## 6. Rollback Points
|
||||
|
||||
- [x] 首次 sudo 预检失败时未进入写阶段;用户建立受控临时入口后重新从完整预检开始。
|
||||
- [ ] 安装后、故障告警前失败:disable/stop 后 `uninstall`,保留状态和共用能力。
|
||||
- [ ] 故障告警后失败:优先正式健康探测关闭告警;无法恢复则保持 timer 停用并明确报告未闭环。
|
||||
- [ ] 回滚后复核备份 dead-man timer 与归档仍在,不主动触发 dead-man。
|
||||
|
||||
## 7. Commands to Validate
|
||||
|
||||
- `bash scripts/qa/run-app-health-monitor-contract.sh`
|
||||
- `bash scripts/qa/run-automatic-backup-contract.sh`
|
||||
- `python3 ./.trellis/scripts/task.py validate 07-27-arm-app-health-rollout`
|
||||
- `node scripts/qa/check-trellis-governance.mjs`
|
||||
- `node scripts/qa/check-sensitive-content.mjs`
|
||||
- `git diff --check`
|
||||
@@ -0,0 +1,81 @@
|
||||
# ARM 应用健康监控上线
|
||||
|
||||
## Goal
|
||||
|
||||
把已通过本地契约的公网 `/ready` 健康监控安全部署到现有 ARM 异机,启用 5 分钟 timer,并通过一次不影响 OA 用户的真实告警/恢复演练证明“持续故障能发现、重复故障会降噪、恢复会通知”。
|
||||
|
||||
## Scope
|
||||
|
||||
- 通过现有受控 SSH alias 连接 ARM;先做只读身份、sudo、systemd、既有备份 dead-man 和 webhook/helper 合同预检。
|
||||
- 只向临时目录传输已提交版本的探测器、共用告警 helper 和独立安装器;校验源/目标哈希,不传输 webhook 正文。
|
||||
- 复用既有 dead-man unit 中已经配置的 root-owned `0600` webhook 文件路径;路径只在 ARM 内解析和校验,不回显其内容。
|
||||
- 先执行 `install` 安装 disabled units,核对精确受管目标、权限和 unit 合同,再手工运行一次真实公网健康探测。
|
||||
- 健康基线通过后启用 5 分钟 timer;演练期间暂时停止 timer,使用同一已安装探测器、helper、webhook 和生产状态目录对本机不可达 HTTPS 端口连续执行三次:第一次 pending、第二次发送真实故障告警、第三次验证降噪。
|
||||
- 随后通过正式 systemd service 探测真实公网 `/ready`,发送一次恢复通知,再恢复 timer 并核对 enabled/active、最近结果和下一次计划时间。
|
||||
- 将输出压缩为脱敏状态、类别、计数、布尔检查和提交哈希;不记录 webhook、地址、原始响应、完整 journal 或远端绝对配置路径。
|
||||
|
||||
## Confirmed Facts
|
||||
|
||||
- 仓库提交 `bb5113c` 已实现并通过应用健康专项 22 项、自动备份兼容回归 73 项、后端 1018 项及前端构建。
|
||||
- 安装器固定受管探测器、helper、状态目录和 systemd unit 名;`install` 默认 disabled,`uninstall` 保留共用 helper、webhook 和状态证据。
|
||||
- ARM 已有 SSH alias,但当前 alias 不是 root;上线前必须证明非交互 sudo 可用,否则停止,不尝试口令或变更账户。
|
||||
- webhook 不在仓库;既有 off-host dead-man service 是复用其路径的唯一事实源。
|
||||
- 本任务已获用户确认:允许 ARM 安装、timer 启用、真实企微故障/恢复演练,并在失败时回滚应用健康组件。
|
||||
|
||||
## Requirements
|
||||
|
||||
- R1:任何写入前先完成只读预检;SSH 身份、`sudo -n`、既有 dead-man unit、root-owned `0600` webhook、Python/systemd 和公网 `/ready` 任一不满足即停止。
|
||||
- R2:不得读取、打印或复制 webhook 正文;只允许把 ARM 内部已验证的 webhook 文件路径传给 root 安装器。
|
||||
- R3:只安装提交版本的三个文件,并以 SHA-256 比对证明传输和受管目标一致;三个部署源相对 `HEAD` 必须无未提交改动,Trellis 任务记录可按正常流程保持未提交;不得从远端旧副本部署。
|
||||
- R4:首次安装发现应用健康 unit、探测器或状态已存在时停止并报告,不覆盖未知运行状态;只有确认是本任务中刚创建的对象后才继续。
|
||||
- R5:手工健康探测必须在启用 timer 前成功,且只保留稳定状态字段;不得用本地成功代替 ARM 公网链路成功。
|
||||
- R6:真实故障演练不得停止 OA、Caddy、数据库、备份 receiver 或 dead-man;只使用 ARM 本机确定不可达的 HTTPS 端口,并在演练期间停止应用健康 timer 避免竞态。
|
||||
- R7:第一次失败不得发送,第二次发送一条,第三次 helper 返回降噪;正式 service 恢复后发送一次恢复通知。
|
||||
- R8:最终 timer 必须 enabled/active,最近一次 service 为成功,下一次计划不超过 5 分钟;备份 dead-man timer 仍保持原状态。
|
||||
- R9:任一步失败时停止继续扩大变更。若尚未发送故障告警,卸载本任务组件;若已经发送故障告警,优先恢复正式探测并发送恢复通知,失败则保持 timer 停用并明确报告未闭环告警。
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [x] AC1:只读预检证明受控 alias 可连接、`sudo -n` 可用、既有 dead-man/webhook/helper 合同成立,且未输出秘密或完整配置路径。
|
||||
- [x] AC2:ARM 上安装的探测器和共用 helper 与提交版本哈希一致;unit/状态目录权限符合合同,install 后 timer 明确 disabled/inactive。
|
||||
- [x] AC3:ARM 手工正式 `/ready` 探测成功,probe state 为健康且输出无地址、路径、payload 或原始异常。
|
||||
- [x] AC4:timer 启用后为 enabled/active,调度周期为 5 分钟且最近正式执行成功。
|
||||
- [x] AC5:受控演练证据显示第一次 pending、第二次 sent=true、第三次 sent=false;群内只产生一条脱敏故障告警。
|
||||
- [x] AC6:正式 service 恢复成功且 sent=true,后续健康执行 sent=false;群内只产生一条恢复通知。
|
||||
- [x] AC7:备份 receiver、dead-man unit/timer、归档与状态均未被卸载或覆盖;备份兼容合同在上线前仍通过。
|
||||
- [x] AC8:临时传输目录已清理;最终只保留已批准受管文件、独立状态和 units,工作树与审计记录不含秘密。
|
||||
- [x] AC9:用户确认实际收到一条故障告警和一条恢复通知;在此确认前只报告“自动链路证据通过,人工收件待确认”。
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 修改 OA、Caddy、数据库、DNS、证书、Compose 或公网部署。
|
||||
- 停止真实服务来制造故障。
|
||||
- 修改备份 receiver/dead-man 配置、归档、timer 或 webhook 内容。
|
||||
- 新建机器人、变更企业微信配置、发送业务数据或原始日志。
|
||||
- 增加证书到期预警、业务登录/审批合成监控或第三方 dead-man。
|
||||
|
||||
## Test Plan
|
||||
|
||||
- 上线前复跑 `bash scripts/qa/run-app-health-monitor-contract.sh` 与 `bash scripts/qa/run-automatic-backup-contract.sh`。
|
||||
- ARM 只读预检、源/目标哈希、权限、unit 内容和 state schema 检查均返回有限布尔/状态 token。
|
||||
- 先 disabled 安装和健康手工执行,再 enable;演练用同一正式状态链完成 pending/send/dedup/recovery。
|
||||
- 结束后检查 timer、service、备份 dead-man 保持情况、临时目录清理、Trellis/task 治理和 `git diff --check`。
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- 使用“不影响 OA 的本机不可达端口”制造监控输入故障,不停止任何真实服务。
|
||||
- 复用正式状态目录做一次完整状态机演练,timer 在演练窗口暂停,避免健康执行插入失败序列。
|
||||
- webhook 路径从既有 dead-man unit 在 ARM 内解析,正文始终不读取、不传输、不回显。
|
||||
- 用户已批准操作范围,但 Trellis 仍要求本规划摘要之后再明确批准实施。
|
||||
|
||||
## Execution Evidence
|
||||
|
||||
- 2026-07-27:本地应用健康专项 22 项、自动备份兼容回归 73 项通过;三个部署源相对 `HEAD` 无未提交改动,SHA-256 已记录为脱敏技术证据。
|
||||
- 2026-07-27:受控 SSH alias 可连接,但首个 `sudo -n true` 预检返回“需要密码”;流程按 R1 在任何远端写入前停止。
|
||||
- 未创建 ARM 临时目录、未上传文件、未修改 systemd、未读取 webhook、未发送真实企微消息。
|
||||
- 本地 SSH 配置中未发现指向同一 ARM 的 root alias。继续执行需要用户在 ARM 侧提供非交互 root 运维入口;不得在聊天中发送 sudo/root 密码。
|
||||
- 2026-07-27:用户在自己的终端建立临时 sudoers 入口后,完整只读预检通过;disabled 安装、提交哈希、权限和 ARM 公网健康基线均通过,健康基线未发送消息。
|
||||
- 2026-07-27:timer 已启用;隔离演练依次得到 pending、`sent=true`、`sent=false`,正式 systemd service 恢复成功并更新为 `PASS_APP_HEALTH_READY`,重复健康为 `sent=false`。
|
||||
- 2026-07-27:最终 timer enabled/active、下一次运行在 5 分钟内、最近 service 成功;备份 dead-man enabled/active 未变。临时上传目录和临时 sudoers 规则均已删除。
|
||||
- 自动链路已证明一条故障和一条恢复发送成功;随后由用户完成实际群内收件确认。
|
||||
- 2026-07-27:用户确认企微群实际收到一条“内部 OA 运维告警”和一条“内部 OA 运维恢复通知”,真实收件闭环完成。
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "arm-app-health-rollout",
|
||||
"name": "arm-app-health-rollout",
|
||||
"title": "ARM 应用健康监控上线",
|
||||
"description": "在现有 ARM 异机安全安装并启用公网 /ready 健康监控,通过不影响 OA 用户的真实企微故障、降噪和恢复演练完成上线验收。",
|
||||
"status": "in_progress",
|
||||
"dev_type": "operations",
|
||||
"scope": "deployment",
|
||||
"package": "hyb-oa",
|
||||
"priority": "P2",
|
||||
"creator": "shunli",
|
||||
"assignee": "shunli",
|
||||
"createdAt": "2026-07-27",
|
||||
"completedAt": null,
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [],
|
||||
"notes": "本地 22+73 项合同通过;首次 sudo 预检安全停止。用户建立临时入口后完成 ARM disabled 安装、启用、真实故障/降噪/恢复演练及最终健康核对,临时上传和 sudoers 已删除;用户确认实际收到一条故障和一条恢复通知。",
|
||||
"meta": {}
|
||||
}
|
||||
@@ -57,14 +57,14 @@
|
||||
- [ ] **EXTERNAL_GATED**:已真正停止一次源端 timer 或故意破坏一次传输,ARM dead-man 仅产生一条脱敏企微告警;恢复 finalize 后收到一次恢复通知,同一失败重复运行已降噪
|
||||
- [ ] 若调整过 `BACKUP_RUN_AT`,已人工确认调整后的次日 UTC 分桶和 26 小时窗口,未把一次预期空窗误判为长期故障
|
||||
- [ ] 本季度已由第二名内部人员按 runbook 首部恢复卡在 ARM 隔离目标完成影子恢复走查;timer 未自动恢复生产
|
||||
- [ ] ARM 公网应用健康监控(未完成远端门禁前保持未勾选):
|
||||
- [ ] 本地 `bash scripts/qa/run-app-health-monitor-contract.sh` 通过,且自动备份告警契约回归通过
|
||||
- [ ] **EXTERNAL_GATED**:已批准 ARM systemd 写入,并确认复用 root-owned `0600` webhook;安装的是已通过自动备份回归的共用 helper 修订,不复制或输出 webhook 正文
|
||||
- [ ] `install-offhost-app-health-monitor.sh install` 只安装 disabled units;应用健康 state/alert state 与备份 dead-man 完全独立
|
||||
- [ ] 手工 oneshot 健康执行通过,输出不含地址、路径、响应 payload、凭证或原始异常
|
||||
- [ ] **EXTERNAL_GATED**:另获批准后执行 `enable`,timer 为 enabled/active,oneshot service 平时 inactive,下一次运行不超过 5 分钟
|
||||
- [ ] **EXTERNAL_GATED**:持续失败演练中第一次仅 pending、第二次只发一条、重复失败降噪、恢复只通知一次;未用“机器人能发消息”替代故障链路
|
||||
- [ ] 已记录剩余风险:ARM 自身失效会使探测失声,首版没有第三方 dead-man
|
||||
- [x] ARM 公网应用健康监控(2026-07-27 自动链路与群内收件验收通过):
|
||||
- [x] 本地 `bash scripts/qa/run-app-health-monitor-contract.sh` 通过,且自动备份告警契约回归通过
|
||||
- [x] 已批准 ARM systemd 写入,并确认复用 root-owned `0600` webhook;安装的是已通过自动备份回归的共用 helper 修订,未复制或输出 webhook 正文
|
||||
- [x] `install-offhost-app-health-monitor.sh install` 只安装 disabled units;应用健康 state/alert state 与备份 dead-man 完全独立
|
||||
- [x] 手工 oneshot 健康执行通过,输出不含地址、路径、响应 payload、凭证或原始异常
|
||||
- [x] 已执行 `enable`,timer 为 enabled/active,oneshot 最近执行成功,下一次运行不超过 5 分钟
|
||||
- [x] 持续失败演练中第一次仅 pending、第二次发送、重复失败降噪、正式恢复发送、重复健康降噪;用户确认群内收到一条故障和一条恢复通知
|
||||
- [x] 已记录剩余风险:ARM 自身失效会使探测失声,首版没有第三方 dead-man
|
||||
- [ ] 停机复制方案已冻结:旧 PostgreSQL 完全停止后复制到空新目录并保留所有权/权限/链接/扩展属性;旧目录原位保留且观察期内不再写入
|
||||
|
||||
## B. 发布(Deploy)
|
||||
|
||||
@@ -340,10 +340,12 @@ RESTORE_SCOPE=shadow \
|
||||
- 确认完整批次已经复制到异机/异盘,而不是仍只保存在应用主机。
|
||||
- 准备独立 smoke 账号,避免使用老板、管理员或真实员工账号跑自动化。
|
||||
|
||||
## 1.6 ARM 公网应用健康监控(启用仍为 EXTERNAL_GATED)
|
||||
## 1.6 ARM 公网应用健康监控(已启用)
|
||||
|
||||
应用健康监控与自动备份 dead-man 共用受控企微群机器人入口,但使用独立探测器、systemd units、probe state 和 alert state。它从 ARM 每 5 分钟访问公网 HTTPS `/ready`;连续两次失败才告警,一次成功即恢复。不得把它并入备份 receiver 的安装/卸载生命周期,也不得以本地测试通过代替 ARM 已启用证据。
|
||||
|
||||
2026-07-27 已完成 ARM disabled 安装、手工公网健康基线、timer 启用及不影响 OA 的真实故障/降噪/恢复演练;自动链路显示一条故障和一条恢复发送成功,用户确认群内实际收到两条消息。timer 最终 enabled/active、最近 service 成功,备份 dead-man 状态未变,临时上传和临时 sudoers 已删除。
|
||||
|
||||
先在仓库运行无真实消息合同:
|
||||
|
||||
```bash
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ cd client && E2E_BASE_URL=https://oa.hyinda.com npx playwright test tests/e2e/dg
|
||||
|
||||
`07-27-app-health-monitoring` 为公网 `/ready` 增加轻量异机探测:ARM 每 5 分钟经标准 HTTPS 校验访问一次;连续两次失败才发送一条脱敏企微群机器人告警,相同类别持续失败不重复发送,恢复后只通知一次。它覆盖 OA 应用、数据库就绪、OA 主机不可达、DNS/Caddy/TLS 已失效等基础故障,不替代登录、审批或报销等业务 smoke,也不执行自动重启或恢复。
|
||||
|
||||
当前仓库代码和本地契约通过,不等于 ARM 已安装或监控已生效。远端 `install`、`enable`、真实消息和故障/恢复演练均为 `EXTERNAL_GATED`,需分别取得批准。先运行本地无真实消息合同:
|
||||
2026-07-27 已完成 ARM 安装、启用和真实故障/恢复演练:timer 为 enabled/active,首次失败 pending、第二次发送、重复失败降噪、正式恢复发送、重复健康降噪,用户确认群内实际收到一条故障与一条恢复通知;备份 dead-man 未受影响,临时上传和临时 sudoers 已删除。后续重装、真实消息或再次演练仍需单独批准。先运行本地无真实消息合同:
|
||||
|
||||
```bash
|
||||
bash scripts/qa/run-app-health-monitor-contract.sh
|
||||
|
||||
在新工单中引用
屏蔽一个用户