跳轉到

Guidant AI v1.18.0 Release Note

項目 內容
版本 1.18.0(功能版號;主軸=系統設定頁全面可用——四頁存檔連環修 + 全新安全政策設定頁把登入政策從「請原廠下 SQL」變成畫面上的開關)
發布日期 2026-08-29
上一版本 1.17.0(2026-08-27)
涵蓋區間 2026-08-27 ~ 2026-08-29(9e3b763b..4d873065
涵蓋需求 CM-1423 安全政策設定頁(MFA 開關進 UI,含開啟前防鎖死守門)+ 系統設定存檔五連環修(CM-1331 追修/CM-1418 ×3)+ CM-1425 檢測執行紀錄可刪除失敗項+逾時收斂CM-1420 缺失證據分組CM-1421 覆核輪審閱標記 resetCM-1419 落地版寄信吐翻譯 keyCM-1417 installer 補產 REDIS_SECRET + FR-063/FR-065 落地版工具鏈續修
規模 BE 21 commits(feat 7/fix 13/chore 1);FE 4 commits(feat 3/fix 1);DB migration 2 支
適用部署 188 STG + 189 POC(皆為安裝版 docker stack,走 install.sh --upgrade
部署性質 含 2 支 DB migrationenvs=*,由 init image 的 migrate 模式套用)。兩台皆為既有資料升級——只走升級模式、不重建庫。FE image 本版有異動必須重 build,不可 retag不走正式簽章(維持 --skip-prod-key-check,決策者裁示)。

0. 發版前回歸 gate

本版未執行 site-regression 自動 Core gate,理由與 v1.16.0/v1.17.0 同:落地版 stack 形態的 E2E 套件尚未補齊。放行依據為 DEV 上各卡的 BE 實跑驗收(各 commit message 內逐項列出)+ 188 STG 升級後功能抽驗189 POC 升級後的舊資料筆數對照(見 §6)。自動化 gate 待落地版 E2E 套件補齊後於後續版本恢復。


1. 概述

v1.17.0 把「系統自己的紀錄」送進了客戶的 log 平台。v1.18.0 處理的是更前面一步的問題:那些系統設定頁,客戶到底改不改得動。

答案在本版開工時是「幾乎都不行」。SMTP、LDAP、Discord、Telegram 四頁的存檔按鈕,在落地版上按下去只會拿到 403、400 或 404——五顆彼此獨立的缺陷疊在同一條路徑上,一顆修掉才露出下一顆(詳見 §3)。而登入政策(要不要強制兩階段驗證、密碼多久過期、連續失敗幾次鎖帳號)連頁面都沒有,客戶要改只能請原廠連進資料庫下 SQL。

本版把這條線補完:

  • 四頁存檔全通——五連環修完,共用設定(SMTP/LDAP)的讀寫落點統一到 ROOT 租戶,四支 RLS policy 對稱化。
  • 新增安全政策設定頁——登入政策五項進 UI,其中「強制 MFA」帶一道防鎖死守門:開錯就沒有人進得來,故開啟前會檢查驗證碼寄得出去的前置條件。
  • 落地版的兩顆靜默雷——寄出去的信是翻譯 key 不是中文(CM-1419)、installer 沒產 jedi-mfa 要的 Redis 設定導致「開了 MFA 全員登不進來」(CM-1417)。兩顆都是「服務全綠、log 乾淨、就是行為錯」的類型。

另外三項與稽核業務直接相關:檢測執行紀錄終於刪得掉失敗項並且不再卡在 running(CM-1425)、缺失改善的證據 tab 按控制項分組不再看起來像系統重複(CM-1420)、發起覆核後不再帶著母輪的已審閱勾勾(CM-1421)。


2. 重點新功能

2.1 安全政策設定頁(CM-1423,BE d8c8061d + FE 48cca59

登入政策自 FR-063.1g 起就存在資料庫、登入流程每次即時讀取,但沒有任何管理介面。本版補上讀寫端點、授權與選單登記——多半是接線不是新做:設定值、讀取器、ROOT 讀寫器都沿用既有的,沒有新表。

項目 說明
端點 GETPUT /api/1.0/system/security-policy(group 粒度,一次讀寫整組)
位置 系統設定 → 安全政策(介於「郵件伺服器」與「LDAP」之間)
能力點 security-policy.{read,update}(租戶層,授予對象=既有持有 smtp-config.update 的角色)
可調項目 強制兩階段驗證、登入失敗鎖定次數與時間、密碼有效期、閒置帳號停用天數、JWT 效期

🔴 防鎖死守門是這頁的主要風險控制。強制 MFA 是唯一一個開錯就沒有人進得來的設定:驗證碼靠寄信送達,SMTP 沒設好等於含操作者自己在內全員卡在登入第二關,且無法從畫面救回。因此:

  • 讀取時一併回 otp_readiness(檢查 ROOT 的 SMTP 設定存在且 host/port/寄件人齊全)。
  • 「從關到開」且通道未就緒 → 回 412(SECURITY_POLICY_412001),要帶 confirm_risk=true 明示確認才放行。不硬性禁止——客戶可能用 TOTP,或明知風險而為之。
  • 只擋「開啟」方向:關閉 MFA 是解除鎖死的動作,任何情況都不能被擋住。
  • 檢查的是「設定齊全」不是「寄得出去」(真試寄要收件人且有延遲,不適合擋在存檔路徑),故畫面文案一律措辭為「可能寄不出」,不誇大這道檢查的效力。

其他行為細節:數值超出合理範圍拋 400 而非靜默夾成邊界值;改動 JWT 效期會回 restart_required(該值由 flask_jwt_extended 啟動時讀取,改資料庫要重啟才生效,如實回報不讓使用者誤以為即時生效);每次修改寫稽核事件 SECURITY_POLICY_UPDATED(6110)——改登入政策等於改全站登入強度,要留痕。

2.2 檢測執行紀錄可刪除失敗項 + 逾時收斂(CM-1425,BE 9a0623db + FE fefe226

檢測工具的執行紀錄過去無法從畫面刪除,失敗紀錄(agent 缺工具、連線失敗、設定錯)只會一直累積。本版補上單筆與整組刪除,並依決策者擴充範圍一併做執行逾時收斂。

只准刪 failed,這是刻意的:succeeded 掛著報告檔與證據,刪了證據鏈就斷;runningscheduled 還在跑,要刪得先取消(既有端點已有);cancelled 是使用者自己按的、屬有意義的軌跡。整組刪看的是該組每一筆(含重跑歷史)——夾著一筆成功就代表這組留有報告,不該整組消失。單筆刪不重算整組彙總:刪掉一筆失敗紀錄不代表這次執行變成功了。

逾時收斂runningscheduled 超過閾值且 agent 始終沒回報 → 判 failed 並寫明原因)採排程而非「有人開抽屜才算」:卡住的掃描恰恰是最沒人盯的那些,且卡在 running 的組會擋掉同任務的下一次執行。閾值 DETECTION_EXECUTION_TIMEOUT_HOURS 預設 4 小時可調——訂太短會誤殺正常的長掃描(逐台登入型工具一次派 256 台是十幾小時的量級)。

2.3 缺失改善證據按控制項分組(CM-1420,BE 2521b013 + FE 5a73754

缺失改善側欄的「證據」tab 原本把一筆缺失底下所有觀察的證據攤平成單一清單,同一份檔案被多個查核項各自引用時會連著排好幾列,看起來像系統重複。BE 端在觀察記錄回傳中加上來源 target_id(如 AC.L1-b.1.iv),FE 據此按控制項/查核項分組收合,組內同名檔去重。純加欄位、無 migration、無新端點。


3. 重要修補

3.1 系統設定四頁存檔的五連環(CM-1331 追修 + CM-1418 ×3)

這五顆彼此獨立、依序遮蔽,是本版最耗時的一段。按露出順序:

# commit 症狀 根因
1 7b9b363a SMTP/LDAP 存檔永遠 403 by-uid 端點的守門前置查詢只走一般租戶查詢,而共用設定的實體在 ROOT 租戶、業務租戶因 RLS 看不到 → 查無 → 能力點對照 fallback 成誰都沒有的 system_config.*
2 b4340bd1 存檔 400「缺少 value」 共用設定寫入路徑期待 {"value": {...}},但這條 by-group-key 端點從來就是扁平契約(前端送的、舊路徑收的都是扁平)
3 b4340bd1 存檔會弄丟既有密碼 changePwd=false 時沿用既有 secret 的邏輯在舊路徑的 domain 層,新路徑繞開 domain 直接寫 ROOT,這段整個漏了
4 b4340bd1 SMTP 頁點不開也存不了(一律 404) SMTP 走 by-uid 端點,而清單端點回給前端的正是 ROOT 那列的 uid,業務租戶拿它去讀寫受 RLS 看不到
5 c96d3d5f 新裝機器第一次存 LDAP 必炸 400 system_configs 四支 RLS policy 只有 INSERT 不認 super_admin(SELECT/UPDATE/DELETE 走 USING 吃得到,INSERT 走 WITH CHECK 不看)

第 5 顆特別值得記:DEV 上 15 項驗收全綠卻測不出來,因為寫入是「先 UPDATE、影響 0 列才 INSERT」,而 DEV 的 ROOT LDAP 列一直存在(歷史資料)永遠走 UPDATE 分支。出貨基線刻意不帶 LDAP 列(由客戶自行設定),所以每一台新裝的客戶機器第一次設 LDAP 都必踩。這是「開發環境有歷史資料掩蓋出貨情境」的典型案例。

修法一律往共用處收:繞 RLS 的 ROOT 讀取只留一份實作、by-uid 的 PUT 拆成扁平後與 by-group-key 共用同一條寫入路徑(changePwd 邏輯不寫第二份)。RLS 只修 system_configs 一張——實查發現多張表的 INSERT policy 也有同樣不對稱,但那些表沒有「跨租戶寫 ROOT」的使用情境,一起放寬等於平白擴大攻擊面。

3.2 落地版寄出的信是翻譯 key 不是中文(CM-1419,2446fc2e

189 落地版寄出的帳號建立通知信,主旨與內文都是原始翻譯 key(account_created_subject),開發環境正常。根因是 jedi_auth 被 Nuitka 整包編成機器碼,而 Nuitka 只收 .py——套件自帶的 translations/**/*.mo 不會進產物,gettext 的 fallback 靜默回 msgid 本身:信照發、HTTP 200、log 乾淨

與 CM-1416(googleapiclient 的 discovery JSON)同型但更陰——那顆至少會拋例外,這顆全程無聲。修法是把套件資料目錄複製進產物(先在 188 用最小 Nuitka 專案實測確認編譯後的路徑推導仍會命中該落點),並新增 smoke 探針⑦:實際從產物落點載入 .mo 並 gettext 兩個真實 key,斷言回傳不等於 key 且含中文。這型缺陷全是靜默的,只靠 build 期的檔案存在斷言不夠。

3.3 installer 沒產 REDIS_SECRET,一開 MFA 全員登不進來(CM-1417,02ce7fd8

jedi-mfa(驗證碼暫存)自帶的 Redis client 只讀舊 JSON 格式的 REDIS_SECRET,不認 installer 產的平鋪 REDIS_HOSTREDIS_USERREDIS_PASSWORD。缺了這個鍵,它拿到的帳密是 None——服務六顆全綠、平常登入正常,一旦開啟 MFA 就全員登不進來(發驗證碼時才第一次連 Redis)。DEV 測不出來:DEV 的 Redis 允許免帳密,落地版的有密碼必炸。

本版由 installer 補產(決策者裁示的方案 A;治本=改 jedi-mfa 認新格式,另案)。升級路徑一併顧到:既有安裝的設定檔沒這行,--upgrade 時偵測缺就補寫,既有內容一律不動(比照物件儲存憑證的補齊模式)。

3.4 發起覆核後帶著母輪的已審閱勾勾(CM-1421,274e0813

覆核輪的控制項與查核項仍顯示母輪已審閱的勾勾,覆核者會誤以為本輪已審過。根因是審閱標記掛專案不掛輪次(FR-014 的刻意設計,非漏設計),加上快照時 catalog 不重複複製、控制 id 跨輪穩定,勾勾就「穿透」到覆核輪。

採最小改:發起覆核時清掉收斂範圍內控制(及其底下查核項)的審閱標記,不動 schema。不加輪次維度的理由是那等於改變既有設計語意,要一併改寫入/讀取/計數四處且需 backfill 既有標記的輪次歸屬(無從推導);而「保留母輪歷史」的價值有限——母輪已結案,該控制在覆核輪重查過,舊勾勾反而是誤導,真正的歷史留痕在 AR findings 與 POA&M。

3.5 順帶修掉一個全專案的地雷:背景排程呼叫翻譯函式必炸(9a0623db 內)

select_locale 直接讀 request,但背景排程在自己的執行緒跑、只有 app context 沒有 request context → 任何在背景 job 裡產生文案的程式碼都會整輪掛掉。因為 tick 都包在 try/except 裡,症狀是「排程靜悄悄什麼都沒做」而非明顯報錯。改成沒有 request context 時退回預設語系。不是單一功能獨有——任何未來的背景 job 只要碰文案都會踩到。

3.6 落地版工具鏈續修(FR-063/FR-065)

commit 內容
b7ba5223 Google Drive 授權炸 UnknownApiNameOrVersion——googleapiclient 改不編譯原樣附帶
dae47169 image 憑證斷言改認「標頭+金鑰本體」,文件裡的空範例不再誤判成私鑰
6884da4d 補 config 漏定義的 DRIVE_WEBHOOK_PUBLIC_BASE_URL(授權註冊 webhook 頻道時炸 NoneType)
e872d5d9 維運指令抽成系統層 guidant CLI + restart 設定變更守門
6a1e8449 新增測試用 dev image(直接跑源碼、容器內 git pull 換版)
e0a8fd62 build/smoke 加 DB 前置斷言——連錯庫從三個 Traceback 變一句人話
1617dd01 雲端空間整合下放 Tenant Admin——root 旗標守門改能力點(FE 8680bfb 對應)

4. Breaking Changes

無。本版無 API 契約破壞性變更。

一項行為澄清:系統設定 by-group-key 端點的 payload 一律是扁平形狀(設定本體本身,不包 value)。這是回歸既有契約而非變更——前端與舊路徑本來就是扁平,v1.17.0 期間新增的共用設定路徑形狀寫錯,本版修正。


5. DB Migration

2 支,皆 envs=*(三環境都適用),由 init image 的 migrate 模式套用:

檔案 內容
2026-08-28-cm1418-system-configs-insert-rls-super-admin.sql system_configs 的 INSERT policy 補 super_admin 逃生口(四支 policy 對稱)
2026-08-29-cm1423-security-policy-page.sql security-policy.{read,update} 能力點 + 授予 + ui_routes 選單登記(sort=15)

🔴 出貨基線產物同步更新:第二支是 seed 型 migration(能力點與選單列),全新安裝必須帶到,否則客戶裝出來沒有安全政策設定頁。故基線庫已補套本波兩支並重跑三支產生器(gen_schema_sql.shgen_seed_sql.shgen_stamp_sql.sh),產物隨本版一併提交。

一則過程紀錄4d873065):CM-1423 的 migration 檔曾漏登記 manifest.tsv。manifest 是套用清單的唯一來源,不在裡面的 SQL 檔對 migrate 而言不存在——後果是全新安裝少那支、升級的乾跑清單也不列它而一路回報成功。由 scripts/check_migration_manifest.sh 在打包前抓到並補登。這正是 v1.17.0(CM-1407)那類「沒有錯誤訊息、退出碼 0」失敗型態的同族,值得作為往後每次出包前必跑該檢查的依據。


6. 部署順序

  1. 基線庫補套 + 重跑三支產生器 + 提交產物(已於本版完成,見 §5)
  2. BE buildbuild_all.sh --all,含 Nuitka 編譯與 smoke 全綠守門,新增探針⑦)
  3. FE build——本版必須重 build,不可 retag(CM-1420/CM-1423/CM-1425 皆有 FE 異動)
  4. init image build(帶新的 manifest 與基線產物)
  5. 封包build_bundle.sh
  6. 188 STG install.sh --upgrade → 乾跑清單應列出本波 2 支 → 「資料庫已與本版對齊(待套 0 支)」斷言出現 → 六容器 healthy
  7. 189 POC install.sh --upgrade(同上;既有資料升級,不重建庫

升級後必驗:guidant.env 內存在 REDIS_SECRET 且 JSON 可解析、舊資料筆數對照無損、SMTP 設定頁存檔不再 403、寄出的信是中文不是翻譯 key、安全政策頁打得開、檢測執行紀錄的失敗項有垃圾桶。


7. 相依套件版本

套件 版本 變更
jedi-system-config 0.0.14 → 0.0.15 CM-1418 changePwd 防呆(既有列沒有 secret 時不硬抄)

其餘 jedi-* 套件版本不變。


8. 已知 follow-up

  • REDIS_SECRET 治本:改 jedi-mfa 認平鋪格式的 Redis 設定,讓落地版不必維護兩份同值的憑證。本版走 installer 補產(方案 A),治本另案。
  • 其餘表的 INSERT policy 不對稱bulletinsdevicesprojectssurveysworkflow_* 等多張表有與 system_configs 相同的 policy 不對稱,本版刻意不一起改(那些表沒有跨租戶寫 ROOT 的使用情境)。日後若有表需要該情境,比照本版逐張評估。
  • 落地版 E2E 套件:site-regression 尚未覆蓋 stack 形態,自動 gate 仍暫停,待補齊後恢復。
  • 輪次層審閱標記:CM-1421 採最小改保留專案層語意。日後若真要輪次層審閱,需另案評估(本版的修法不擋那條路)。

9. 完整 commit 索引

BE9e3b763b..4d873065,21 支)

commit 內容
9e3b763b v1.17.0 進版
c84d4591 出貨基線產物補齊 FR-068
1617dd01 雲端空間整合下放 Tenant Admin
b7ba5223 落地版 Google Drive 授權炸 UnknownApiNameOrVersion
dae47169 image 憑證斷言改認「標頭+金鑰本體」
e872d5d9 維運指令抽成系統層 guidant CLI + restart 守門
6884da4d 補 config 漏定義的 DRIVE_WEBHOOK_PUBLIC_BASE_URL
6a1e8449 新增測試用 dev image
e0a8fd62 build/smoke 加 DB 前置斷言
7b9b363a SMTP/LDAP 存檔永遠 403(by-uid 守門補 ROOT fallback)
b4340bd1 設定存檔契約形狀錯/密碼保留漏失/by-uid 404
41bdb99f jedi-system-config 0.0.14 → 0.0.15
c96d3d5f system_configs INSERT policy 漏 super_admin
2446fc2e 落地版寄信吐翻譯 key + smoke 探針⑦
2521b013 POA&M 觀察記錄回傳 target_id
274e0813 發起覆核後清審閱標記
d8c8061d 安全政策設定頁 BE(MFA 開關 + 防鎖死守門)
9a0623db 檢測執行紀錄可刪除失敗項 + 逾時收斂 + 背景排程 _() 修復
02ce7fd8 installer 補產 REDIS_SECRET + 備份檔權限收緊
4d873065 cm1423 migration 補登記 manifest

FE0a47f5b..,4 支)

commit 內容
8680bfb 雲端整合頁按鈕顯示條件改綁能力點
5a73754 缺失改善證據 tab 按控制項/查核項分組收合
48cca59 安全政策設定頁 UI(含防鎖死警告)
fefe226 執行紀錄失敗項刪除鈕(單筆 + 整組)

10. 相關文件索引

  • 系統設定頁 spec:docs/specs/current/(系統設定群)
  • 落地版 build/出包:scripts/build/README.md(canonical)
  • 出貨基線產物:scripts/init/README.md(含 regenerate 鐵則)
  • Installer:scripts/installer/install.sh
  • 前版 release note:docs/release_notes/v1.17.0.md