FR-172 · 定版交付

定版交付:主系統與 Agent 各自更新

現況:主系統 1.28.3、Agent 1.5.5(內部測試包,測試章簽);正式版跟 FR-173 出 1.29

主系統與 Agent 是兩個安裝包、兩條版本線、各自升級。Agent 不連外網,包一律經主系統轉手;主系統更新中心、Agent 主控台、離線上傳三種方式都能發動 Agent 更新,進度當下回報。給 PM 的問答看 for-pm-qa.md;每一步跑哪支程式看 upgrade-flow-guide.md。

主系統 1.28.3 Agent 1.5.5 190 實測通過 正式版跟 FR-173

一句話

主系統與 Agent 分開出包、分開上更新站、分開升級。按「更新到 X」不必先預先下載:主系統手上沒有最新包就自己先下載再推。Agent 升級中自動進入維護模式,主控台整頁鎖住只顯示進度,完成自動恢復。


1. 交付物現況

項目 主系統 Agent
版號(pyproject.toml) 1.28.3 1.5.5
安裝包 guidant-ai-<版>.tar.gz(約 3.5 GB,不含 agent/)+ops 小檔 guidant-agent-compose-<版>.tar.gz(約 1.7 GB)
更新站版本線 product=host,R2 v1/<版>/ product=agent,R2 agent/v1/<版>/
發布清單的章型別 release_manifest agent_release_manifest
最低相容 min_agent_version(主系統要求 Agent 至少幾版) min_host_version(Agent 要求主系統至少幾版,目前 1.28.0)
更新站上(測試章) 1.28.1、1.28.2、1.28.3 1.5.1~1.5.5
190 測試機 1.28.3 1.5.5
189 POC 1.27.x(未升) 1.4.x(未升)

2. 更新怎麼跑

2.1 主系統自己升級

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
  autonumber
  participant P as 管理員(更新中心)
  participant M as 主系統 api/worker
  participant U as 更新站+R2
  participant H as 主機 systemd
  P->>M: 立即檢查(另有每日排程)
  M->>U: /v1/check product=host
  U-->>M: 新版、簽好的清單、三段說明
  P->>M: 更新到 X
  Note over P: 全頁遮罩,只顯示進度
  M->>U: /v1/download-url(15 分鐘預簽網址)
  M->>U: 下載包與 ops 小檔(背景工作、可續傳)
  M->>M: 用本機公鑰驗章、比對雜湊
  M->>H: 寫更新單 upgrade/orders/<job>.json
  H->>H: guidant-upgrade-order.path 撿單 → 重驗包與章
  H->>H: 0 換維運指令 → 1 預檢 → 2 等工作做完 → 3 複製資料庫
  H->>H: 4 在複本套新版 → 5 健康檢查 → 6 換成新版 → 7 清理
  Note over H: 2~6 前門顯示維護頁;任一步失敗自動退回
  H-->>M: 進度檔每步更新
  M-->>P: 八步進度;完成後回更新中心
圖 1 — 主系統升級:主系統容器只寫單,主機的 systemd 單元撿單跑八步。

2.2 主系統發動 Agent 更新

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
  autonumber
  participant P as 管理員(更新中心 Agent 區)
  participant M as 主系統
  participant U as 更新站+R2
  participant A as Agent 容器
  participant H as Agent 主機 systemd
  P->>M: 勾選 N 台,更新選取的 N 台到 X
  alt 手上的包不是最新(沒有包,或比更新站查到的舊)
    M->>U: 下載 Agent X(背景工作,畫面有進度、可取消)
    M->>M: 驗 agent_release_manifest 章、雜湊,存 agent-bundles/X/
    Note over M: 下載中再有人按,併入待推清單
  end
  M->>M: 建推送列:先 1 台,成功再推其餘
  M->>A: 直推 POST /update {版號, sha256, 大小}(mTLS+60 秒 JWT)
  Note over A: 進入維護模式:停收新工作
  A->>M: GET /agents/update/bundle 下載包(可續傳)
  A-->>M: 事件 update_download
  A->>A: 核大小與雜湊,寫升級單 agent-upgrade-order.json
  H->>H: guidant-agent-upgrade-order.path 撿單
  H->>H: 用舊版 Agent 驗新版程式樹的章 → 跑升級步驟
  A-->>M: 事件 update_step(每步)
  H->>H: 換新容器、健康檢查
  A-->>M: 事件 update_result+上傳升級紀錄
  M-->>P: 每台八步進度與結果;成功清用不到的包
圖 2 — 主系統發動 Agent 更新:手上沒有最新包就先下載,下載完自動推;不走心跳。

Agent 當時離線,主系統會在它下次心跳回來時補推一次。心跳本身不帶任何指令。

2.3 Agent 主控台發動更新

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
  autonumber
  participant O as 操作者(Agent 主控台 8444)
  participant A as Agent
  participant M as 主系統
  participant U as 更新站
  O->>A: 立即檢查
  A->>M: POST /agents/update/check(通行證+DPoP)
  M->>U: 查 Agent 線(全機 5 分鐘節流)
  A->>M: GET /agents/update/available
  M-->>A: 有新版 X(手上沒包也照報)
  O->>A: 更新到 X
  Note over O: 按下當下整頁鎖住
  A->>M: POST /agents/update/request(操作者名稱)
  M->>M: 手上不是最新 → 排下載,記「agent-console:操作者」
  M->>A: 下載完直推 POST /update(之後同圖 2 第 7 步起)
圖 3 — Agent 主控台按「更新到 X」:請主系統替這一台做圖 2 的事。

2.4 離線上傳

Agent 主控台「離線上傳更新包」:上傳 .offline.tar.gz,Agent 依序驗章(用現行版的公鑰,不用包裡的)、雜湊、版本、磁碟,過了就寫升級單,主機照圖 2 第 11 步起跑。主系統斷線時主控台只提供這條路。

2.5 Agent 什麼時候算「升級中」、什麼時候鎖畫面

狀態 怎麼判 影響
升級中(維護模式) Agent 在下載主系統推來的包、在等進行中的工作做完、或升級單已寫好主機還在跑 停收新工作;主控台狀態回 in_progress
主控台鎖畫面 主控台問狀態時拿到 in_progress 整頁鎖住,每 3 秒更新進度
解鎖 in_progress 消失 版本換了就整頁重新載入回原頁;沒換(失敗退回)就解鎖顯示結果

主控台平常每 30 秒問一次狀態,所以由主系統發動時開著的主控台最慢 30 秒才鎖;在主控台自己按的當下就鎖。


3. 測試機同版重套

已是最新版時,把目前這一版照正式流程重跑一次。只給測試機用,正式環境沒有這兩個鍵就不會出現按鈕。

開關 放哪 誰讀
PRODUCT_UPDATE_ALLOW_SAME_VERSION=1 /srv/guidant-ai/guidant.env 主系統 api(出按鈕、驗章放行同版)、主機升級腳本 upgrade_order.sh(放行同版單)
AGENT_UPDATE_ALLOW_SAME_VERSION=1 Agent 安裝目錄 .env(compose 轉進容器) Agent 容器(接同版推送、離線上傳同版)、Agent 主機升級腳本 upgrade_order.sh(放行同版單)
按鈕 在哪 需要哪個開關
重新套用目前版本 主系統更新中心 主系統
重新套用目前 Agent 版本 更新中心 Agent 區 主系統+Agent
重新套用 X Agent 主控台更新頁 主系統+Agent

改完開關要讓容器重讀:主系統 sudo guidantai start、Agent sudo guidant-agent-compose start(restart 不會重讀設定)。降版、跨主版號不論開關一律擋。目前只開在 190。


4. 程式在哪

4.1 主系統(compliance-manager-be)

用途 檔案
更新中心 API 路由 api/product_update/__init__.py、routes/product_update_route.py
更新中心總入口 app/product_update/service/product_update_app_service.py
主系統自己升級(檢查、下載、寫單) product_update_flow.py、update_site_client.py、package_downloader.py、package_verifier.py、upgrade_order.py
Agent 版本線(檢查、下載、判斷手上是否最新) agent_release_service.py
Agent 推送(分批、暫停、重推、同版重套) agent_rollout_service.py、agent_rollout_views.py
Agent 升級事件 agent_update_event_handlers.py
同版重套 same_version.py
直推 /update 給 Agent core/plugins/_agent_commands.py(push_update_soon)
Agent 下載包端點 core/plugins/_agent_update.py、api/remote_agent/routes/agent_update_bundle_route.py
Agent 主控台請主系統查、報、更新 core/plugins/_agent_console_update.py、api/remote_agent/routes/agent_update_request_route.py
Agent 事件與升級紀錄上傳 api/remote_agent/routes/agent_events_route.py、agent_update_log_route.py
主機升級腳本 scripts/installer/lib/upgrade_order.sh(撿單)、upgrade_runner.sh(跑八步)、upgrade_preflight.sh、upgrade_drain.sh、upgrade_db_copy.sh、upgrade_apply_on_copy.sh、upgrade_health.sh、upgrade_switch.sh、upgrade_cleanup.sh、upgrade_rollback.sh;systemd 單元 scripts/installer/systemd/guidant-upgrade-order.path/.service
出包 scripts/build/build_all.sh、build_bundle.sh、sbom.sh、release_json.sh、smoke_auto.sh

4.2 Agent(evidence-agent)

用途 檔案
收 /update 指令 guidant_agent/sync/api/cmd_update.py
下載包、寫升級單、判斷升級中、同版開關 guidant_agent/sync/app/update_sync.py
升級事件、升級紀錄上傳 guidant_agent/sync/app/update_events.py、update_log_upload.py
主控台更新頁 API guidant_agent/console/api/update_routes.py、console/app/update_console.py
主控台 8444 伺服器(白名單、TLS 握手) guidant_agent/identity/app/allow_cidr.py
主機升級腳本(隨 Agent 映像出貨,主機每次從映像讀出來跑) scripts/install/lib/upgrade_order.sh、upgrade_runner.sh、upgrade_guard.sh、progress.sh;systemd 單元 scripts/install/lib/systemd/
主機維運指令 guidant-agent-compose deploy/install.sh 安裝
compose 與開關轉傳 deploy/docker-compose.yml
出包 scripts/build/build_all.sh、build_agent_release.sh、build_agent_bundle.sh、build_compose_bundle.sh
版本說明(出包時讀進 notes.json) RELEASE_NOTES.md

4.3 前端(compliance-manager-fe)

用途 檔案
主系統更新中心 src/views/product-update/UpdateCenter.vue、UpdateConfirmDialog.vue、UpdateHistory.vue、productUpdateState.js;src/composables/useProductUpdate.js
更新中心 Agent 區 src/views/product-update/AgentRolloutPanel.vue、agentRolloutState.js;src/composables/useAgentRollout.js
Agent 主控台更新頁 console/views/Update.vue、console/update.js、console/updateApi.js、console/useUpdateStatus.js(輪詢與鎖定)、console/components/UpdateLockMask.vue、OfflineUpdateUpload.vue

4.4 更新站(update-center)

用途 檔案
兩條版本線、R2 路徑 src/releases.ts(r2Key() 是 R2 路徑唯一拼法)
客戶端三支端點、後台 src/routes/client.ts、src/routes/admin.ts
正式發布 CLI cli/guidant-release.ts

5. 這一輪做的優化

優化 效果
Agent 區一步更新 不必先按「預先下載」;手上沒有或只有舊包都會自動下載最新版再推
升級中維護模式 升級時不再收新工作;主控台鎖畫面、換容器後不必重新登入
主控台立即檢查真的查 新版發布後主控台立刻看得到
更新包自動清理 整批推完清 Agent 舊包;主系統升級成功只留清單,各省約 1.7~3.5 GB
SeaweedFS 殭屍行程 不再每 3 小時要重啟
8444 強制重新整理不再掉 CSS 一條卡住的連線不影響其他連線
同版重套 測試機重看升級流程不必再出一版
出包:測試包略過 SBOM+弱點掃描 Agent 包 19 分 30 秒 → 15 分 52 秒;主系統約省 5 分
出包:主系統封包多核壓縮 預估省約 4 分(188 有 24 核)
出包:釘版第三方 image 匯出檔快取 主系統 5 顆(約 3 GB)、Agent 1 顆不再每版重匯

主系統完整出包約 51 分鐘:Nuitka 編譯約 19 分、封包壓縮約 13 分、SBOM+弱點掃描約 9 分、其他約 10 分。Nuitka 在 188 本來就沒開 LTO,--lto=no 不會更快。


6. 這一輪沒做完的

事 白話說明 誰接
正式版出版 目前上站的都是測試章簽的內部測試包;正式章/Vault 簽的第一版是 1.29 FR-173
189 POC 升級 仍 1.27.x;升 1.28.x 時 Agent 要手動升一次(1.4.x 沒有 /update) 待決策者裁時機
release note 1.27.x~1.28.x 還沒寫 待決策者裁
主控台背景輪詢寫稽核 主控台每次問更新狀態都記一筆「看過更新頁」,數量不實 未開卡
主系統發動時主控台最慢 30 秒才鎖 平常輪詢間隔 決策者裁先這樣
只改主機腳本也得出版 主機每次從現行 Agent 映像讀升級腳本,不能只換 .sh 未開卡,另議
守衛測試 8 條紅 乾淨 HEAD 一樣紅,非本案造成 未開卡

7. 延伸出去的 FR

FR 在做什麼 為什麼會長出來 狀態
FR-171 主系統直推指令給 Agent、事件端點,心跳不再帶訊息 172 的「叫 Agent 升級」「回報進度」要用這條通道 結案
FR-173 BE/Agent/FE 各一條 CI,蓋章改用自架 Vault 172 把出包分家後,出版要自動化、私鑰不放在個人電腦 開卡未派
FR-174 網址型檢測基準匯入時存成檔案 原 172 的 H-5 卡範圍太大,移出 結案

閱讀順序:先看本頁 → FR-171 FINAL-SPEC(通道)→ FR-173(出版自動化)。


8. 這份文件的定位

你想知道 看哪份
現在長什麼樣、程式在哪 本頁
PM 常問的問題 for-pm-qa.md
每一步誰在跑、跑哪支(循序圖+逐步表) upgrade-flow-guide.md;FR-175 機制問答 · 線上升級執行流程
為什麼這樣設計 design.md(v1.0)→ design-v1.1.md(190 實測後的異動)
190 實測回饋原文 handoff/190-test-feedback.md
哪一棒做了什麼 handoff/FR-172-LOG.md
怎麼手動出版 FR-167 release-runbook.md