Agent 獨立更新與心跳改造(需求紀錄)

Agent 獨立更新與心跳改造:需求紀錄

下一階段要討論並開始做。這份只記決策者的需求原話、目前的做法、這次實際踩到的問題, 與每一條會碰到的地方;方案取捨留到討論時做,這裡不先定。

§1

決策者的五點需求(2026-11-01 原話整理)

  1. 主系統跟 Agent 要分開來,不要像現在都包在同一包裡面。
  2. 要可以各別分開更新。
  3. Agent 那邊也要有更新中心,可以做離線更新,或是跟主系統發動更新需求。
  4. R2 上面的安裝包要分開來。
  5. 不要再用心跳帶資料,有滿多地方要重寫。(已列為 FR-167 STATE 已定裁示)
§2

為什麼現在要做

2026-11-01 為了修 Agent 的兩個問題(容器版 Office 證據預覽失敗、主控台 Profile 不能選),實際走過一次的流程:

步驟 花的時間 問題
出 Agent 1.4.8 約 20 分 本身沒問題
為了把 Agent 帶出去,連主系統也出一包 1.27.10 約 36 分 主系統本身只有一個套件改動,卻要整包重出
客戶先升主系統(停機約 7 分) 7 分 只為了修 Agent,主系統卻要停機
主系統升完才能推 Agent — 推送跟著主系統版本走
推送後等心跳才開始、升完等心跳才回結果 每段最多 5 分 121 升級 12:31:39 已成功,主系統 12:36:30 才知道
升級途中 8 格進度一直停在第 1 格 — 欄位對不上(待辦 60),再加上進度靠輪詢

結論:Agent 的修正速度被主系統的發版節奏與心跳間隔綁住。

§3

目前的做法(要改掉的部分)

包

  • Agent compose 包(約 1.8 GB)在主系統出包時被放進 guidant-ai-<主系統版>.tar.gz 的 agent/ 底下,一起簽、一起上 R2(v1/<主系統版>/)。
  • 客戶主機升級後,包解在 upgrade/bundles/guidant-ai-<主系統版>/agent/,更新中心 Agent 區只能推「這一版主系統附的那個 Agent」。
  • 發布清單(release.json)只有主系統一條版本線,min_agent_version 是主系統要求 Agent 至少幾版。
  • 離線單一檔也只有主系統一種。

更新中心

  • 只有主系統有更新中心;Agent 區是主系統更新中心裡的一塊,只能「推送這版附的 Agent」。
  • Agent 主控台沒有更新入口。Agent 1.4.2 以前沒有遠端更新能力,只能 sudo guidant-agent-compose upgrade <包> 手動升。

心跳承載的東西

主系統每次心跳回應夾帶(core/plugins/remote_agent.py 的 heartbeat_extras 與 update_extra):

夾帶內容 主系統這邊在哪 Agent 讀的鍵
升級指令(要不要升、目標版、sha) _agent_update.py update
弱點資料庫版本 _agent_vulndb.py vulndb
工具參數表版本 _agent_tool_schemas.py tool_schemas_version
LDAP 設定 _agent_ldap_config.py —
授權掃描目標名稱 allowed_target_names_heartbeat_extra names/hosts/networks
離線登入天數 _agent_offline_login_policy.py —
檢測 Profile 清單 _agent_profile_sync.py profiles/profiles_check
檔案保護設定 _agent_file_protect.py —

Agent 每次心跳上報夾帶(guidant_agent/sync/app/enroll.py 的 heartbeat_fields):Profile 同步狀態、升級結果(upgrade_result)、弱點資料庫狀態、outbox 數量、重啟原因、LDAP 來源等。主系統用 heartbeat_payload_observers(record_profile_states、record_upgrade_result)處理。

主系統主動找 Agent 的通道已經有:FR-039 資料面(mTLS+短效 JWT,https://<agent>:8443),POST /update/notify、GET /update/progress 是這條。

§4

每一條需求會碰到的地方

1、2、4 包分開、各別更新、R2 分開

  • 出包:BE scripts/build/build_bundle.sh 不再把 Agent compose 包放進主系統包;Agent 獨立出包+簽章+上 R2(新路徑,例如 agent/v1/<Agent 版>/)。
  • 更新站:多一條成品類型(主系統/Agent),product_releases 或另開表、register-draft/publish/withdraw CLI、後台版本頁、/v1/check//v1/download-url 要能問 Agent 的新版。
  • 簽章清單:payload 要區分成品類型,防止拿 Agent 的章冒充主系統(或反之);主機端與 Agent 端驗章各自只認自己那一類。
  • 相容性:現在只有一向(主系統要求 Agent 最低版)。分開後要兩向:Agent 新版要求主系統最低版、主系統新版要求 Agent 最低版;不相容時更新中心要擋或提示。
  • 主系統更新中心 Agent 區:改成可以自己「檢查 Agent 新版/下載 Agent 包」,不用先升主系統;upgrade/bundles/<主系統版>/agent/ 改成獨立的 Agent 包存放處。
  • 離線:要能單出 Agent 離線檔。
  • 清理:主系統升級第 7 步現在會保留本版 bundles/<版>/agent/,分開後這段邏輯要拿掉或改。

3 Agent 自己的更新中心

  • Agent 主控台新增「更新」頁:看現行版本、看有沒有新版、離線上傳更新包、發動更新。
  • 「跟主系統發動更新需求」要定義清楚:是 Agent 請主系統把包給它(主系統當中繼,Agent 不直接連外網,現行原則 update_sync.py 檔頭),還是 Agent 主控台發一張單給主系統更新中心排程。
  • Agent 不連外網、不連更新站,是現行的安全前提(客戶內網掃描機),要不要改,討論時要明確裁。
  • 權限:Agent 主控台的誰可以按更新(local-admin?離線操作者?),沿用 CONSOLE_SCOPES 還是新增。
  • 升級本身已有主機層程式(scripts/install/lib/upgrade_order.sh+systemd path 單元),可沿用,只換「單從哪來」。

5 不再用心跳帶資料

  • 已定原則:心跳只表示存活;Agent→主系統事件走專用端點、當下送、送不到進 outbox;主系統→Agent 指令走資料面 8443。
  • 上表 8 種心跳回應夾帶、Agent 上報那幾種,逐一決定新通道:
    • 「主系統有新設定要給 Agent」類(LDAP、檔案保護、離線登入天數、授權目標、工具參數、Profile 清單、弱點庫版本):主系統在設定變更當下打 Agent 資料面通知,Agent 收到後自己來拉;或 Agent 定期拉一支版本號端點,有變才拉內容。
    • 「Agent 有事要告訴主系統」類(升級結果、升級進度、Profile 同步狀態):Agent 當下打主系統專用端點。
    • 升級進度:Agent 主動推,或主系統畫面打開時才拉(現在是拉,但欄位對不上,見 FR-167 待辦 60)。
  • 跨網段:121、60.167 屬不同網段,主系統打 Agent 8443 今天實測可通;但不能假設所有客戶網路都讓主系統主動連 Agent,要保留 Agent 主動連主系統的退路。
  • 舊版相容:已部署的 Agent 只懂心跳,改造期間主系統要兩套並存一段時間;決定哪一版之後停掉心跳夾帶。
§5

這次順帶記下、討論時要一併看的

  • FR-167 待辦 60:Agent 區 8 格欄位對不上(BE item.progress/FE rollout.progress),升級結果晚 5 分鐘回。
  • FR-167 待辦 58:Agent 主控台檔案頁把預覽 PDF 快取列成證據。
  • 60.167 升級失敗:主機升級單第 0 步 docker create --network none guidant-ai-agent:1.4.8 失敗(「無法讀取新映像」),121 同包同步驟過;疑該機 docker/核心問題,決策者在該機查。失敗原因主系統只拿到一句話,看不到主機細節,Agent 更新中心設計時要讓失敗細節回得來。
  • Agent 升級的 journal:Agent 主機升級的逐行輸出在 systemd journal,Agent 主控台與診斷包都看不到。
§6

下一步

  • 決策者排時間討論:先過這份需求,再照 big-feature-workflow 出討論稿與雛形(Agent 主控台更新頁、主系統 Agent 區改版)。
  • 新 FR 編號開立時把本檔搬到 docs/features/FR-<號>-<YYMM>-agent-independent-update/。