Files
Nexus/docs/audit/2026-06-08-beijing-time-recovery-telegram.md
T
Nexus Agent abeab9d3e4 Fix recovery Telegram dedup and unify Beijing time display.
Store alert metrics without per-value Redis members to stop duplicate recovery pushes; format all operator-facing timestamps in Asia/Shanghai across Web UI and Telegram.
2026-06-08 23:18:56 +08:00

5.0 KiB
Raw Blame History

审计 — 北京时间展示统一 + 资源恢复 Telegram 去重(2026-06-08

Changelog:

  • docs/changelog/2026-06-08-beijing-time-display-unified.md
  • docs/changelog/2026-06-08-telegram-recovery-dedup-timezone.md

触发原因: Bug 修复(恢复通知秒级重复、Telegram/UI 时间非北京时间)+ 展示层时区统一

审计范围

文件 行数 状态
server/utils/display_time.py 27 ☑ 已审
server/infrastructure/telegram/__init__.py ~320 ☑ 已审(_now_cn 段)
server/background/ip_allowlist_refresh.py ~100 ☑ 已审(刷新时间)
server/api/settings.py ~1570 ☑ 已审(Telegram 测试消息)
server/api/agent.py ~385 ☑ 已审(恢复去重)
frontend/src/utils/datetime.ts 85 ☑ 已审
frontend/src/utils/status.ts 36 ☑ 已审
frontend/src/composables/push/labels.ts 68 ☑ 已审
frontend/src/composables/useWebSocket.ts ~190 ☑ 已审
frontend/src/pages/AuditPage.vue ~196 ☑ 已审
frontend/src/pages/AlertsPage.vue ~190 ☑ 已审
frontend/src/pages/CommandsPage.vue ~393 ☑ 已审
frontend/src/pages/RetriesPage.vue ~180 ☑ 已审
frontend/src/pages/SchedulesPage.vue ~533 ☑ 已审
frontend/src/pages/ScriptsPage.vue ~1315 ☑ 已审(时间列)
frontend/src/pages/ScriptRunsPage.vue ~681 ☑ 已审
frontend/src/pages/ServersPage.vue ~1400 ☑ 已审(导出文件名)
frontend/src/components/credentials/CredentialsManager.vue ~436 ☑ 已审
frontend/src/components/servers/ServerInlineDetail.vue ~158 ☑ 已审
tests/test_display_time.py 18 ☑ 已审
tests/test_telegram_time_format.py 20 ☑ 已审
tests/test_agent_recovery_dedup.py 42 ☑ 已审

审计8步结果

Step 1: 登记

两项用户反馈:① Telegram 恢复时间显示 UTC;② 同一指标 1 秒内连发多条恢复通知。

Step 2: 全文 Read

上述文件全文走读;broadcast_recovery / websocket.py 交叉确认恢复无 Telegram cooldown 设计意图(恢复应即时推送,根因在 Redis 成员重复)。

Step 3: 规则扫描 H

ID 规则 命中点 初判
H1 静默吞错 agent.py Redis 告警跟踪 except: debug SAFE — 已有模式,告警主路径仍广播
H2 时区一致性 parseApiDateTime 假定 naive = UTC SAFE — 与 sync_log_repo、ORM _utcnow 一致
H3 去重完整性 Redis legacy mem:92 多条 SAFE — _detect_recovery 按 metric 去重 + srem 全清
H4 XSS / 注入 前端 formatDateTimeBeijing 仅格式化 SAFE — Vue 文本插值,无 v-html
H5 密钥泄露 display_time / datetime.ts SAFE — 无凭据
H6 CUD 审计 无新 CUD 路径 N/A
H7 多 worker 恢复 Telegram 仍无 Redis 锁 LOW — 单心跳内重复已根治;跨 worker 同毫秒双 POST 概率极低,接受

Step 4: Closure表

H 判定 依据
H1 SAFE 跟踪失败不影响 broadcast_alert;日志可见
H2 SAFE DB/API 约定 UTC;文档与 changelog 已说明
H3 SAFE 单测 test_detect_recovery_dedupes_legacy_metric_value_entries
H4 SAFE 展示层数值格式化
H5 SAFE
H6 N/A
H7 ACCEPT 根因修复;若后续再现可加 recovery_sent:{id}:{metric} SETNX

Step 5: 入口表

入口 变更
POST /api/agent/heartbeat Redis alerts:{id} 成员格式、恢复检测
Telegram 出站 _now_cnformat_beijing_now
POST .../telegram/test 测试消息时间
前端各列表页 只读展示,无新 API

Step 6: 输入→Sink

  • Agent system_info → 阈值比较 → Redis set / broadcast_recovery → Telegram:无新 sink;去重降低 Telegram 频率。
  • API created_at 字符串 → parseApiDateTimeIntl 北京时间:只读展示。

Step 7: 归类

display_time.py          27行  2H  0 FINDING
agent.py (recovery)      ~50行  3H  0 FINDING
datetime.ts              85行  2H  0 FINDING
前端 10 文件             ~40行  1H  0 FINDING
测试 3 文件              80行  0H  0 FINDING
──────────────────────────────────────────
总计                     8H   0 FINDING1 ACCEPT

Step 8: DoD

  • 恢复通知同一指标单次心跳最多 1 条 Telegram
  • Telegram / 审计页 / 告警页等绝对时间为北京时间
  • DB 仍存 UTC,未改调度/漂移计算
  • pytest 7 项通过(test_display_time / test_telegram_time_format / test_agent_recovery_dedup
  • npm run type-check 通过
  • 生产部署与浏览器终验(待用户批准 deploy)

FINDING 列表

无。H7 为风险接受项,非 FINDING。

结论

审计通过,0 FINDING,可进入部署门控(需 commit + pre_deploy_check.sh + 前端 build