FR-114 資安修正:合回主線前的整理(給決策者)

首腦第 4 棒整理,材料來自 BOARD/STATE/LOG/各工作區 commit,未逐行核 diff;決策依據以 Notion 各卡「首腦驗收」段為準。

母卡:CM-2019。這份只寫「現在是什麼狀態、合回要怎麼做、要測什麼、要你裁什麼」,每棒怎麼走到這裡的沿革在 FR-114-LOG.md。


1. 一句話現況

53 張卡做完 50 張,程式面第 1~5 批全部驗收過(Done)。 所有改動都還放在四個工作區(worktree,也就是跟主線隔開的副本資料夾)的 fix/security-b1 分支上:

工作區 相對主線多了幾筆 commit
BE compliance-manager-be/.claude/worktrees/wt-fix-security 63
套件 monorepo jedi-python-package/.claude/worktrees/jedi-wt-fix-security 41
FE compliance-manager-fe/.claude/worktrees/wt-fix-security 9
代理程式 evidence-agent/.claude/worktrees/wt-fix-security 2

還沒合回主線、套件還沒發新版、任何環境(含 DEV 的服務本身)都還沒部署這批程式。 DEV 資料庫已套過本批六支 migration(資料庫結構異動腳本),首腦 09-23 深夜實查 schema_migrations 六支全在(最晚一支 09-23 12:50);這是開發期正常狀態。

剩下沒做的 3 張:

  • CM-2061(5B-5):等舊版證據分類退場(CM-1849)做完,才能確認那五件是否跟著消失。
  • CM-2071、CM-2072(第 6 批):要動資料結構,原本就排在「第 1~5 批合回、測過一版」之後。

2. 改了什麼(按使用者看得到的行為分)

標「操作會變」的,是使用者畫面或流程會有感的地方,總測時要特別看。

2.1 登入後看不到不該看的

以前很多功能只問「你有沒有登入」,不問「這筆資料跟你有沒有關係」。現在補上了:

  • 檔案:稽核證據、SSP 佐證、意見回饋附件等檔案的下載、預覽、換發下載通行證、刪除,都要先確認你是這個檔案所屬專案或單據的相關人;不是的話一律回「找不到這個檔案」,不回「沒有權限」,避免別人拿編號一個一個試(CM-2033)。操作會變:系統認不出歸屬的舊檔(孤兒檔)會變成下載不了。
  • 問卷:任務問卷的列表、答案、填答歷史、討論串,改成「該專案任一成員可讀」;空白查詢不再回整張表,直接拒絕(CM-2034)。
  • 專案內的各種查詢:流程留言、稽核退回歷程、流程範本、專案與控制項成員、任務指派、摘要報告、稽核輪次、工作項,都會反查「這筆是不是屬於網址上的那個專案、你是不是成員」(CM-2035、CM-2036、CM-2037、CM-2039)。操作會變:摘要報告清單頁只列「我參與的專案」,習慣從這頁看全局的管理者會少看到東西。
  • 公告:新增「發送範圍」(全公司或指定部門),讀取時依範圍過濾,點進看不到的公告回「找不到」;既有公告一律標「全公司」,行為不變(CM-2026、CM-2027、CM-2028)。操作會變:公告表單多一個必選的「發送範圍」,選「指定部門」時部門欄才必填。
  • 資產與掃描設定的下拉選單:設備、資訊系統、掃描設定檔的讀取改成要有對應的讀取權限(device.read、information-system.read、detection-profile.read),缺權限的角色由 migration 自動補上(CM-2029、CM-2032、CM-2042)。操作會變:真的沒權限時,下拉選單不再「安靜變空」,而是顯示「沒有權限」並鎖住欄位(CM-2082)。
  • AI 儀表板與意見回饋:AI 儀表板 26 支查詢各自申報要什麼權限,拿掉「一律當管理者」的後門(CM-2038);意見回饋清單多一個「查看範圍」參數(只看我的/看全部),管理頁明確送「看全部」(CM-2030)。

2.2 動不了不是自己的資料

  • 任務完成與退回:只有該任務的被指派人與專案 manager 能按;弱點檢測的八個按鈕(開始、取消、刪除執行紀錄等)同一套規則(CM-2021、CM-2022)。操作會變:一般成員按別人任務的「完成」會收到 403(拒絕存取)提示。掃描跑完自動完成的那條路維持可用。
  • 只有作者能改刪:問卷討論(刪除改成軟刪除,畫面看得出被移除而不是整筆消失)、公告、意見回饋,都比對作者本人(CM-2024、CM-2025、CM-2026、CM-2030)。
  • 寫入時反查填進來的東西:專案成員與任務指派寫入時,確認填的任務、群組、控制項屬於這個專案(CM-2023);範本資源庫三條寫入路徑補歸屬、建立端加次數上限(CM-2040);SSP 參考文件刪除要確認文件真的屬於這份計畫(CM-2041);問卷資料夾與即時填答的身分改用登入身分,不信請求裡帶的名字(CM-2060)。
  • 全公司共用設定只有總部能改:LDAP、SMTP、登入政策、日誌轉送四處,子公司管理員改會被拒(CM-2054)。操作會變:子公司管理員存檔時收到 403。
  • 流程範本:驗證端點要權限且有長度與節點數上限;範本新增、修改一定經過檢查;起稽核輪次要求範本已發布(CM-2031、CM-2059、CM-2083)。操作會變:用草稿範本起輪次會被擋。
  • 停權立即生效:帳號被停權後,手上已發出的登入通行證下一個請求就失效,續期也被拒,網頁與即時通訊兩條路都擋(CM-2056)。

2.3 代理程式與防竄改

  • 代理程式每次打進來都要證明身分:代理程式(裝在客戶機房、替我們去掃主機的那支程式)登記時,雲端多發一張長效通行證;之後心跳、確認收單、回報結果、下載證據檔四條路都要帶這張證,雲端每次驗章並查資料庫看這台有沒有被撤銷或停用(CM-2052)。操作會變:管理畫面按「撤銷」後,那台機器四條路當場全斷;被撤銷的機器重新登記會被拒,不會洗回正常。
  • 重灌後接手原機器要證明:帶舊編號重新登記,必須用舊私鑰簽名證明自己是原機器,否則當新機器處理;登記時送的憑證申請(CSR)上的機器識別碼必須等於本次登記的機器,堵住冒用別台指紋拿真憑證的路(CM-2052)。
  • 時鐘偏差警告:代理程式登記與心跳時比對雲端時間,差超過 60 秒就醒目警告(只警告,不中止)。偏差過大時證據檔上傳會全部失敗,以前現場只看得到一行難懂的錯誤(CM-2085)。
  • 驗簽工具拔不掉:負責核對簽章的零件(cryptography、cffi)改成強制編進產品核心,不再以可替換的原始檔形式附帶;打包版不再理會「換掉要核對哪個目錄」的環境變數(CM-2053)。
  • 鎖定紀錄刪不掉:機器因竄改被鎖後,開機時除了看檔案標記也查資料庫;刪掉標記檔重開,資料庫還有紀錄就照樣鎖,並把標記補回去。解鎖回執要附原廠簽過的解鎖碼,手寫的回執不採信。竄改回報送出的主機紀錄先遮蔽密碼再附上(CM-2053)。

2.4 憑證與設定

  • 版控裡的密碼殘留清掉:資料庫管理員密碼(249 檔)、外部平台通行證、AI 金鑰、Google 雲端硬碟金鑰、交接文件帳密、47 檔過期登入通行證,全部從現存檔案清除(不改寫 git 歷史);開始掃描時不再把明文主機帳密多存一份進派工表(CM-2048、CM-2049、CM-2050、CM-2051)。
  • 密鑰不再回傳給前端:儲存設定頁的物件儲存密鑰,後端只回「有沒有設定過」,不回真值;儲存設定也加進密鑰遮蓋名單(CM-2063、CM-2054)。操作會變:密鑰欄顯示遮罩,沒改就不送,只改其他欄位不會洗掉密碼。
  • 日誌轉送可加密:日誌轉送設定頁新增「傳輸加密」開關與「信任憑證」欄(CM-2056)。操作會變:設定頁多兩個欄位,既有設定一律維持不加密。
  • 連線驗證與版本鎖定:GitHub 連線恢復憑證驗證(CM-2066);快取連線改用套件已修好的那份(CM-2043);套件 monorepo 17 支的版本鎖定檔(poetry.lock)納入版控(CM-2067)。
  • 交出去的東西先處理:匯出 Excel、Word 時,=、+、-、@ 開頭的內容當文字不當公式;日誌轉送的換行編碼,避免一筆被讀成兩筆(CM-2055);檔案預覽先驗真實格式,不在白名單或內容與副檔名不符的一律改成下載,HTML 預覽不執行裡面的程式(CM-2062)。操作會變:部分以前能直接預覽的檔案改成下載。
  • 各種上限:AI 儀表板與 AI 助手加逾時與次數上限,超過回 429(請求太頻繁);AI 助手訊息上限 4000 字(CM-2064);清單每頁筆數上限 1000、設定值打錯字改退回正式模式、寫日誌失敗不連累使用者請求(CM-2065);弱點檢測規則包解析前擋惡意內容、壓縮檔炸彈上限、測試連線主機數上限、重新解析去重(CM-2057、CM-2058)。操作會變:AI 連按太快會看到「請稍後再試」。

2.5 刪掉的功能

  • 三組沒人呼叫的任務管理功能(CM-2044)。
  • 開發用小工具 gen_comment.py 與從沒被讀過的死開關;jedi-common 的 [ai] 選配相依跟著拿掉(CM-2045)。
  • 全站成員名冊查詢入口 /issue/get_members(資料表與同步程式保留,意見回饋指派負責人還在用)(CM-2046)。
  • 「快速設定」獨立畫面兩個入口(專案規劃頁裡的快速配置不受影響)(CM-2047)。操作會變:那兩個網址直接打不開。
  • 密碼產生器兩份零引用的重複副本,只留 jedi-iam 那一份(CM-2068)。

3. 合回的硬順序(順序錯了服務起不來)

3.1 為什麼有順序

三個事實決定了順序,任何一個沒照做,服務會直接起不來或代理程式全斷線:

  1. BE 用到了套件的新東西,但 BE 還指著舊版套件。 BE 工作區已 commit 的程式 import 了只有新版套件才有的東西,例如 jedi_remote_agent.api.agent_pass_required(代理程式通行證守門)、jedi_integrity.ports.IBootLockStore(開機查資料庫鎖定)、jedi_common.utils.export_safety(匯出防公式)、jedi-task-platform 的 resolve_project_id_for_job。而 BE 主線 pyproject.toml 仍 pin 舊版(例如 jedi-remote-agent==1.1.2、jedi-integrity==1.1.0、jedi-common==1.2.0)。只合 BE 不發套件,一開機就 ImportError。 runner 開發時是靠 path dependency(直接指向本機套件資料夾)與 PYTHONPATH 繞過去的,那些設定沒有 commit。
  2. 代理程式新舊版與雲端新舊版互不相容,而且是兩個方向都不相容。 舊代理程式配新雲端:舊版只認「404 就重新登記」,收到新雲端的 401(未帶通行證)會一直失敗、一直重試,等於斷線。新代理程式配舊雲端:新版登記時要拿通行證,舊雲端不發,新版會當成雲端設定錯誤一直重試。所以雲端與代理程式要同一次上。
  3. 套件之間也有新依賴。 jedi-survey 用到 jedi-task-platform 新加的專案成員守門;jedi-issue 與 jedi-log 用到 jedi-common 新加的匯出防公式工具。這幾支發版時,依賴對方的版本下限要一起抬高,否則裝到舊版的組合會壞(這是我從 import 查到的三處,發版的人要再全面 grep 一次)。

首腦不合回、不發版、不部署,下表每一步都由決策者或你指定的人執行。

3.2 步驟表

步 做什麼 誰做 做完怎麼確認
0 做完第 4 節「合回前清理」 你指定的 runner(開一張清理卡) 清理卡回寫逐項打勾,工作區 commit
1 套件 monorepo:fix/security-b1 合回 feature/review 決策者或指定的人 合回後主線 git log 看得到 41 筆;CM-2032 那筆主線已有同內容的 eafc7ae,工作區是 cherry-pick 版 e98fea2,合回時同內容不該衝突,衝突就取任一邊
2 套件發版:下表 17 支 bump 版號、推 Nexus(內部套件庫)。順序:先 jedi-common,再 jedi-iam、jedi-task-platform,其餘不分先後 決策者明示後由指定的人照 docs/claude/jedi-packages.md 發版流程 Nexus 上查得到 17 支新版;抬高依賴下限的三處(見 3.1 第 3 點)已改
3 BE:合回;pyproject.toml 把 17 支的 pin 改成新版號;跑 poetry update <逐一列出 17 支套件名> 同上 一律指定套件名,不裸跑 poetry update(裸跑會把沒驗過的第三方一起升);python -c "import jedi_remote_agent; print(jedi_remote_agent.__file__)" 指到 site-packages 且版本是新版;python main.py 起得來、/api/1.0/version 回 200
4 FE:合回 同上 npm run build 通過
5 代理程式:合回;出一版代理程式 release(scripts/build/build_agent_release.sh) 同上 release 產物內含兩筆新 commit;版號與雲端版號對得上
6 部署 DEV:本機 BE 用合回後主線起服務、FE 起前端、DEV 上的代理程式換新版 同上 代理程式心跳正常、管理畫面看得到在線;log 無 ImportError
7 188 全量 build 唯讀驗證(第 5 節)與出貨基線重產(第 6 節) 基線重產要你一句「做」;build 驗證要你放行 見各節
8 總測(第 7 節) 決策者 各組清單全過;有問題開卡調
9 才談 STG/POC 決策者明示 另開上版卡,走 init image migrate 模式,不手動套

3.3 要發版的 17 支套件

依「除了測試與 lock 之外有沒有改到程式」判斷。以下是工作區 fix/security-b1 相對 feature/review 的實際變動(排除測試檔與 poetry.lock):

套件 現版 改動檔數 主要來自
jedi-issue 1.2.0 28 意見回饋權限與作者比對、名冊入口刪除、GitHub 驗證、附件刪除
jedi-survey 1.1.2 21 問卷讀取守門、討論作者比對、即時填答身分
jedi-remote-agent 1.1.2 18 代理程式通行證、撤銷、持有證明、雲端時間
jedi-detection 1.1.0 18 嚴格任務守門、資源上限、規則包、報告檔名
jedi-log 1.2.0 15 日誌轉送加密、匯出防公式、換行編碼
jedi-ai-dashboard 1.2.0 15 查詢權限白名單、逾時與次數上限
jedi-task-platform 1.1.1 13 指派寫入反查、成員查詢守門、工作項歸屬
jedi-file-upload 1.2.0 13 檔案歸屬檢查、預覽格式驗證、衍生檔清理
jedi-integrity 1.1.0 12 開機查 DB 鎖、解鎖回執驗章、log 遮蔽
jedi-bulletin 1.1.0 11 發送範圍
jedi-common 1.2.0 10 匯出防公式、序列化排除密碼、分頁上限、密碼遮蔽;拿掉 [ai] 選配
jedi-compliance-audit 1.1.3 7 稽核輪次守門、起輪次要求已發布、錯誤碼鏡像
jedi-asset 1.1.0 7 設備與資訊系統讀取權限
jedi-ai-bot 1.2.0 7 訊息長度、逾時、次數上限
jedi-flow-engine 1.3.0 5 流程圖走訪上限、範本檢查
jedi-iam 1.3.0 3 停權即時生效
jedi-system-core 1.1.1 1 儲存設定密鑰遮蓋名單

不用發版的 4 支:jedi-evidence-classification、jedi-license-runtime、jedi-notification、jedi-oscal-v2 只多了 poetry.lock 入版控,lock 不進發布出去的套件檔,程式沒變。

注意:派工時給我的 18 支清單裡有 evidence-classification、license-runtime、notification(只有 lock),但沒有 jedi-compliance-audit(7 檔程式)與 jedi-system-core(1 檔程式)。以上表為準。

3.4 合回時要對得上的關鍵 commit

合回的人核對用。每個 repo 的完整清單用 git -C <工作區> log --oneline feature/review..HEAD 看。

repo commit 內容
套件 c4acc687、9c049540 代理程式通行證、撤銷、持有證明、CSR 識別碼檢查(CM-2052)
套件 953697c9、ba129ca1 開機查 DB 鎖、log 遮蔽、解鎖回執驗章(CM-2053)
套件 bad15b7d 登記與心跳回傳雲端時間(CM-2085)
套件 e98fea29 CM-2032 的 cherry-pick 版,主線已有同內容 eafc7ae5
套件 09cbb7cf 17 支 poetry.lock 入版控(CM-2067)
BE 7a3bdf1ec 證據檔下載改驗通行證(CM-2052),import 新版 jedi-remote-agent
BE 0dda326b8、b64995ac9 驗簽工具編進核心、開機查 DB 鎖接線、補同步重驗回執(CM-2053)
BE 3a651140e、fc9fca7d0、38c5b131e、32ace7aa5、4e7754de7、1b52aa24b 六支 migration 與 manifest 登記
BE 264b42262、c87d2eea5 資安報告狀態批次更新(第 5 批以前的 Done 卡)
代理程式 ecdc9f3 每請求帶通行證、401 自動重新登記(CM-2052)
代理程式 9edda49 時鐘偏差警告(CM-2085)
FE 756783b 儲存設定密鑰欄遮罩(CM-2063)
FE 10dc47c、bbf0f68、4f1e501、45b3d7c 403 提示與七個錯誤碼文案(CM-2082、CM-2042)

BE 與 FE 主線在工作區分岔後:BE 主線多了 77 筆(只和工作區在 docs/features-site/ 重疊,見第 4 節),FE 與代理程式主線沒有新 commit,可以直接快轉合回。

3.5 出事怎麼退

合回之後、總測之前如果發現起不來或大面積壞掉,退法依壞在哪一層:

  • BE 起不來(ImportError):幾乎都是步驟 2、3 漏了某支套件。先看錯誤訊息指的套件名,確認 Nexus 上有新版、BE pin 有改、poetry update 有點名它。不要用 path dependency 臨時救,那會把開發設定帶進主線。
  • 代理程式全斷線:先看雲端與代理程式是不是都換成新版。只換了一邊就把另一邊也換上;兩邊都要退時一起退,不可只退一邊。
  • 某個功能被新守門擋住正常使用者:先確認那個角色有沒有對應權限(第 6 節的兩支補權限 migration 是否已套)。確定是守門寫錯才開卡改,不要為了讓總測過而拿掉守門。
  • 整批要撤:四個 repo 的合回各自是一筆合併 commit,可以各自 revert;套件已發出去的新版號不收回,BE 把 pin 改回舊版號即可。資料庫那六支 migration 都是「只加不刪」(加欄位、補權限、放寬一條新增規則),留著不影響舊版程式運作,撤程式時不必撤資料庫。

4. 合回前一定要做的清理

建議開一張清理卡一次做完,在四個工作區裡 commit,做完再進第 3 節步驟 1。

項 在哪 誰做/何時 做完怎麼驗
FE 補錯誤碼文案:GRC_400131「留言內容不可為空」、GRC_400132「留言內容過長,上限 2000 字」、GRC_400133「本流程留言則數已達上限(500 則)」 FE src/config/locales/i18n/{zh-tw,en,zh-cn}/error-code.json(我已確認三語目前都沒有) 清理卡/合回前 三個語系 grep 得到三個碼;送空白流程留言畫面顯示中文句子不是原始代碼
FE 補代理程式錯誤碼文案:FILE_AGENT_401002(通行證缺失或無效)、FILE_AGENT_403003(代理程式已停用)、FILE_AGENT_400007(憑證申請上的機器識別碼不符) 同上 清理卡/合回前 三語 grep 得到。這三個只有代理程式端點會回,畫面碰不到,補上是為了一致
收掉施工日誌型註解(程式裡寫「第幾棒、哪張卡、重派」這類,應該進 commit message) BE common/code/flow_control_error_code.py:384-386;BE 帶「FR-114.2-5」的 4 支檔 5 處(project_summary_report_service.py 等);套件 jedi-compliance-audit 錯誤碼鏡像對應段;FE 帶「CM-2082」9 檔 13 處、帶「重派」6 處、帶「CM-2042」4 處 清理卡/合回前 git grep -n "CM-20[0-9][0-9]|重派|FR-114\." 在程式碼(不含 docs)零命中,只留真正的「為什麼」
還原 BE 工作區未 commit 的開發設定:pyproject.toml 12 支 pin 被改成 path、poetry.lock 跟著變;共用 venv 裡 12 個 .pth 指到 jedi 工作區 BE 工作區 git status 看得到的兩檔;venv site-packages 清理卡/合回前(這些不能被合回) 工作區 git status 乾淨;python -c "import jedi_common; print(jedi_common.__file__)" 不再指到工作區
文件站以主線為準:BE 主線在分岔後多了 77 筆,和工作區重疊的只有 docs/features-site/(約 590 檔)。合回時這一區一律取主線 CM-2084 全量版(121 個 FR),工作區只保留 CM-2048 憑證清理那 22 個檔 BE docs/features-site/ 合回當下 合回後 docs/features-site/ 與主線相比只差憑證清理那幾檔;站內 FR 數 121
升級手冊補一段角色權限說明。內容要改向:原本要寫「升級前檢查各角色有沒有讀取權限」,但你 09-23 已裁補權限 migration 一律隨出貨,升級時會自動補上。所以改寫成「升級會把 device.read、information-system.read、detection-profile.read 補給缺的角色;刻意拿掉的,升級後要再收一次」 docs/spec-site/current/user-manual/onprem/05-upgrade-rollback.md 收尾棒(等令) 手冊頁看得到這三顆與「升級後再收」一句
權限守門兩種流程的說明文件(能力點型與資源歸屬型),SUMMARY「怎麼修」加連結 新檔 docs/security-report/GUIDE-02-authz-two-patterns.md(目前還不存在;桌面有 HTML 草稿) 收尾棒(等令) 檔案存在、SUMMARY 連結點得開
SaaS 版 TLS(加密連線)在哪裡終結(Cloudflare、雲端負載平衡或其他)寫一行 docs/features/FR-063-2608-nuitka-packaging/deployment-env.md 決策者或維運看一眼,合回前 那一行存在
SUMMARY 狀態列批次更新:#1、#17、#18、#90、#133 改已修,#91 改部分修;頂部的統計數字與「最要緊的五件」也要跟著改(五件實際都已修,其中第 4 件待 188 build 實證,但頁面上仍寫未修或只修一半;「還沒動的 99 件」也已過期) BE 工作區 docs/security-report/SUMMARY.md 與對應 M 檔 清理卡(首腦驗收後的報告批次更新) 重 build 後頁面欄數正常、抽五條狀態正確
FE 儲存設定頁 bucket 欄的錯誤樣式綁錯到密鑰欄的驗證(既有小錯,CM-2063 順帶發現) FE StorageConfigForm.vue 清理卡可順手,或另開 bucket 留空時紅框出現在 bucket 欄
CM-2037 套件側四支 service 各自寫一支 _require_participant,沒用 guard.py 既有守門 jedi-compliance-audit 四支 app service review 時看要不要收攏(不收也不影響功能) 收攏的話四處改呼叫同一支

5. 188 全量 build 要驗的三點

這是唯讀驗證,不部署、不動 STG。 CM-2053 把驗簽工具改成編進核心,有三件事只有跑一次完整打包才看得到,runner 只在 188 跑過單支套件的小探針(編 cryptography 33 秒、驗章正常),沒跑全量。

在哪跑、開跑前做什麼:

  • 188 的 /opt/guidant-ai-be,先 git pull 到合回後的主線 commit(部署機一律 git pull,不 scp)。
  • 開跑前 pgrep -f 'nuitka|build_all' 確認沒有別的 build 在跑(互撞會 linker crash)。
  • 照 188 固定陷阱:指定 smoke 專用臨時庫(不要連 STG 那顆庫、不要去套 migration)、注意 FE image 標籤、先看磁碟。細節見 scripts/build/README.md。
  • 出貨基線要先重產(第 6 節),否則 build 的 stamp gate(出包前檢查基線有沒有跟上 migration 的關卡)會紅。

要驗的三點:

點 怎麼看 過的樣子
驗簽工具真的在核心層 產物內 cryptography/ 目錄存在,完整性清單(manifest)把它歸在 core 層;產物裡少了 cryptography 的 dist-info(安裝資訊目錄)不影響執行 開機正常、驗章正常、manifest 查得到 core 歸屬
typing_extensions 是誰的 在產物裡執行 typing_extensions.__file__ 指向 Nuitka 編好的模組。若指向一支複製進去的 .py,代表在完整性閘門檢查之前就先執行了一段沒被驗過的原始檔,要回報
換掉驗簽工具會被擋 在一份 build 產物的副本上換掉驗簽零件再開機 開機被擋(修之前是綠燈放行,這是 #17 的核心驗收)

6. 出貨基線重產

背景:新客戶安裝時不是從頭重放每一支 migration,而是載入 scripts/init/02-schema.sql 這份「已經長好的資料庫結構」。主線新增了結構類 migration 卻沒更新這份檔,新裝客戶就會少掉那些欄位,而且服務全綠、沒有任何錯誤訊息。

本批六支 migration(全都已登記在 scripts/sql/manifest.tsv):

檔名 卡 類型 要不要進基線
2026-09-22-fr114-survey-discussions-soft-delete.sql CM-2025 結構(active/*) 要
2026-09-22-fr114-bulletin-send-scope.sql CM-2027 結構(active/*) 要
2026-09-22-fr114-feedback-issues-insert-relax-org.sql CM-2032 結構(active/*,改資料列存取規則) 要
2026-09-22-fr114-log-forwarding-tls.sql CM-2056 結構(active/*) 要
2026-09-22-fr114-asset-read-capability-backfill.sql CM-2032 資料(seed/*,補權限) 不進基線,靠安裝與升級時的 migrate 那輪套
2026-09-23-fr114-detection-profile-read-capability-backfill.sql CM-2042 資料(seed/*,補權限) 不進基線,同上

STATE 寫「七支」是多算了:實際是六支檔,其中四支要進基線,兩支補權限的是資料類,照規則本來就不進 02-schema.sql(資料類硬塞進基線蓋章,等於宣告那些資料永遠不插)。另外套件隨包的三支 migration(jedi-bulletin 001、jedi-issue 004、jedi-log 005)走攤平流程,不屬主專案基線。

重產要寫入 188 上的基線庫,屬於環境異動。 卡開好等你一句「做」。步驟(先備份、只套這四支、重產兩份產物、驗 diff 只有新增、本機重跑 stamp gate)見 .claude/skills/sql-migration/SKILL.md「首腦重產的步驟」,這裡不抄。建議時機:合回主線後、188 全量 build 之前。


7. 總測建議

你 09-23 裁「最後從安裝到功能整個重測一遍」。以下按六組列,每條都是能親手點、親眼看的。標 ★ 的是 opus 抽查時退回過、修法有判斷,請優先測。

測試帳號建議先備好:專案 manager、同專案一般成員(viewer)、不在這個專案的同公司帳號、子公司管理員、總部管理員、一個自建且拿掉讀取權限的測試角色。

7.1 安裝與升級

# 做什麼 應該看到
1 用新出的安裝包全新安裝一套 裝完能登入;公告表單有「發送範圍」、日誌轉送設定頁有「傳輸加密」開關(證明基線有跟上)
2 拿上一版的環境跑升級 升級完既有公告都是「全公司」、既有日誌轉送設定維持不加密
3 升級後查角色權限 所有角色都有 device.read、information-system.read、detection-profile.read
4 升級後用一個沒有部門的一般使用者送意見回饋 送得出去(以前會靜默失敗)
5 全新安裝後看產品開機 log 完整性檢查通過,沒有「無法查詢 DB 側竄改鎖定紀錄」的警示
6 全新安裝一次,確認物件儲存連線可用 檔案上傳下載正常

7.2 登入與權限

# 做什麼 應該看到
1 停權帳號 B,B 在已登入的畫面上再點一下 立刻被登出(401),自動續期也失敗;復權後重新登入正常
2 子公司管理員改 LDAP、SMTP、登入政策、日誌轉送 四處都 403 且訊息看得懂;總部管理員與平台管理員改得動
3 ★ 用拿掉讀取權限的測試角色,打開專案規劃頁、任務設定頁、合規文件設備分頁、資訊系統分頁、匯入資產挑選器、任務規劃頁的掃描設定檔下拉 每個下拉都顯示「沒有權限」並鎖住,不可以是安靜的空清單
4 同上的角色換回有權限 六處下拉都有資料
5 AI 儀表板連續快速生成、AI 助手連續快速送訊息、送一則超過 4000 字的訊息 超次數顯示「請稍後再試」;超長訊息被退;正常使用不受影響
6 意見回饋:一般員工看清單、管理頁看清單 一般員工只看到自己的;管理頁看得到全部
7 儲存設定頁:只改 bucket 名稱存檔,再上傳一個檔 上傳正常(密碼沒被洗掉);瀏覽器網路面板裡回應沒有任何密鑰真值

7.3 專案流程

# 做什麼 應該看到
1 viewer 按別人任務的「完成」與「退回」 兩個都 403;被指派人與 manager 做得到
2 跑一次弱點掃描直到結束 自動完成照樣生效(系統代勞的路沒被擋掉);viewer 取消或刪除執行紀錄被拒
3 不在專案的帳號,拿專案裡一個證據檔的編號去下載、預覽、刪除 全部回「找不到」;專案成員四個動作都正常
4 ★ 摘要報告清單頁,分別用 manager 與不在專案的帳號看;翻到第二頁 只列自己參與的專案;分頁後的結果也只有自己的(這是被退回補過的地方)
5 問卷:成員看列表、答案、歷史、討論;非成員拿同編號看 成員全看得到;非成員全被擋
6 問卷討論:A 留言,B 改或刪 A 的;管理者刪 A 的 B 被拒;管理者刪後畫面看得出「被移除」而不是整筆消失
7 公告:部門甲發「指定部門」公告,部門乙的人看清單與直接開網址 部門乙看不到、直接開回找不到;A 改自己的公告發送範圍沒被清空
8 用草稿狀態的流程範本起稽核輪次;送空白流程留言、送超過 2000 字留言 起輪次被擋;留言顯示看得懂的中文錯誤

7.4 代理程式

測這組需要工程師在旁邊,部分項目要用 runner 在 DEV 實跑過的那組腳本送請求。

# 做什麼 應該看到
1 新版代理程式全新登記、心跳、接單、回報、下載證據檔 六步全通;管理畫面顯示在線
2 ★ 管理畫面按「撤銷」那台,接著讓它心跳、確認收單、回報結果、下載證據 四條全部被拒(403),這是全案最嚴重那件的核心驗收
3 ★ 被撤銷的機器重新跑登記 被拒,而且管理畫面上仍是撤銷狀態,不會洗回正常
4 解除撤銷 四條路恢復
5 ★ 重灌情境:帶原本的機器編號重新登記,一次附舊私鑰簽名、一次不附 附了保住原編號;沒附被當新機器、拿新編號
6 ★ 送一份憑證申請,上面的機器識別碼填別台 被拒(400),而且沒有建出新機器列
7 把代理程式主機時鐘調快 5 分鐘再心跳 log 出現醒目的時鐘偏差警告,但代理程式照常運作;調回後出現「已恢復」
8 舊版代理程式配新版雲端 連不上(預期如此),確認升級說明有寫「要一起換」

7.5 防竄改

在 build 產物上測,不是在原始碼模式測(原始碼模式刻意不查資料庫鎖定)。

# 做什麼 應該看到
1 換掉驗簽零件後開機 被擋(第 5 節第三點,可與 build 驗證一起做)
2 ★ 讓機器進入竄改鎖定,刪掉檔案標記後重開 仍然鎖住,檔案標記被補回來
3 ★ 鎖定後自己手寫一份解鎖回執放進去,重開 不採信,仍然鎖住;資料庫紀錄也沒被改成已解鎖
4 用原廠簽發的解鎖碼正常解鎖 解鎖成功,之後同步把資料庫紀錄改成已解鎖
5 設 GUIDANT_RESOURCE_ROOT 指到別的目錄再開打包版 被忽略,照樣核對 binary 所在目錄
6 觸發一次竄改回報,看送出去的內容 主機 log 尾段裡的密碼、Authorization 已被遮蔽
7 把記錄解鎖碼用過沒的檔案改成亂碼 出現高等級警示(目前只警示不拒絕,見第 8 節)

7.6 設定頁

# 做什麼 應該看到
1 日誌轉送開「傳輸加密」、貼信任憑證、按測試 送得出去;選 UDP 時不能開加密
2 操作日誌匯出、意見回饋匯出(csv 與 excel),資料裡有 =1+1 開頭的內容 用 Excel 與 LibreOffice 開都顯示文字、不執行
3 SSP 匯出 Word、PDF、ODT,欄位裡有 &、<、> 三種都內容完整、排版沒壞
4 上傳一個副檔名是 .png、內容其實是 HTML 的檔案,按預覽 改成下載,不在瀏覽器裡執行
5 「快速設定」兩個舊網址 打不開;專案規劃頁裡的快速配置正常
6 GitHub 整合建一張單 正常建立(恢復憑證驗證沒擋到正常連線)

7.7 測完怎麼回報

  • 每組測完,把「哪一條不如預期、實際看到什麼、用哪個帳號」記下來,全部測完再一次交給首腦,不要測一條修一條。
  • 首腦依回報分三類:守門寫錯(開卡改程式)、權限資料缺(補 migration)、預期行為但使用者會困惑(改文案或手冊)。
  • ★ 那幾條如果有任何一條不過,先停,不要往 STG/POC 推。

8. 風險與已知未修

8.1 報告裡還沒修的

資安檢視總報告(docs/security-report/SUMMARY.md)145 件,目前狀態列還標未修或部分修的有 23 件:

件 一句話 歸誰
#1 代理程式五條管道不問身分、撤銷只斷三分之一 本批已修,狀態列待改
#17、#18、#90、#133 換驗簽零件、刪鎖定標記、換核對目錄、竄改回報夾帶 log 本批已修,狀態列待改(#17 待 188 build 實證)
#91 解鎖碼帳本改亂碼就能重用解鎖碼 本批部分修(只記警示)
#9、#66、#67 舊版證據分類讀雲端硬碟、不查成員、搜尋條件可被改寫 CM-1849 舊線退場
#89、#129~#132 舊版證據分類的 AI 指令注入、殘留資料、金鑰外露、壓縮檔、套件未鎖 CM-1849 做完後 CM-2061 確認
#23、#24、#104 資料庫隔離牆沒生效或方向寫反 第 6 批資料庫牆
#75 前端打包腳本內含套件庫帳密 CM-1998
#96、#97 郵件密碼進紀錄檔、郵件連線不認人 CM-1606,未排期,要你裁
#98、#99 同一組最高權限帳密、三環境公鑰並列 已裁暫緩
#101 內部套件庫走明文 已裁內網不修(部分修)

分三類說明:

本批已做完、只是狀態列還沒改的(6 件):#1(代理程式身分)、#17、#18、#90、#133(防竄改),這五件改「已修」;#91(解鎖碼帳本壞掉)改「部分修」,因為目前只記警示不拒絕,原因見下。

本 arc 範圍內、排在後面的:

  • #9、#66、#67(舊版證據分類):由 CM-1849 舊線退場處理。
  • #89、#129~#132(舊版證據分類的另外五件):等 CM-1849 做完,CM-2061 確認。
  • #23、#24、#104、#105(資料庫隔離牆):第 6 批資料庫牆,等第 1~5 批合回測過一版才開卡。
  • #41(標「部分修」)、#109(標「功能本身已斷」):第 6 批 CM-2071、CM-2072 補資料結構後收尾。

不在本 arc 的:

  • #75(前端打包腳本裡的套件庫帳密):沿用 CM-1998。
  • #98(每套安裝都種同一組最高權限帳密)、#99(三環境公鑰並列):已裁暫緩。
  • #101(內部套件庫走明文):已裁內網不修,lock 已入版控,標部分修。
  • #96、#97(郵件):寄信失敗時把整組郵件設定含密碼寫進紀錄檔;連郵件伺服器有加密但不認對方身分,攔在中間的人能收走帳密與每封信(含一次性驗證碼、新帳號初始密碼)。這兩件模組頁寫「工單 CM-1606 已開、未排期」,不在本 arc 任何一張卡裡。要你裁(見第 9 節)。

8.2 開機查資料庫失敗時一律放行,範圍比原裁示大

場景:客戶的產品主機開機時,防竄改機制會去資料庫查「這台有沒有未解除的鎖定紀錄」。你原本裁的是「資料庫連不上時放行並警示」,理由是不能因為資料庫暫時掛了就讓客戶整套起不來。

現況:jedi-integrity 的 boot_db_lock.py 把任何查詢失敗都當成「連不上」處理,包括「表不存在」「權限不足」「資料庫密碼設定缺欄位」。後面這幾種其實是連得上、但查不成功。

風險:一個有主機權限、想繞過鎖定的人,如果能讓查詢失敗(例如改掉資料庫帳號的權限),開機就只剩檔案標記那一道。要你裁(見第 9 節)。

8.3 另開卡候選(不在本 arc)

  • 離線機器的指紋可被接手:受害機離線時,別人直接用受害機的機器指紋登記,會照「重灌後接手」的設計拿到同一列。這是既有設計,不是本批造成(CM-2052 抽查點出)。
  • 公版只有一個管理員角色:出貨公版只內建 Administrator,客戶自建角色從零勾。以後每加一顆讀取守門,客戶都可能踩到「選單變空」。長期正解是公版內建幾個一般角色範本,預勾讀取類權限。
  • 兩支沒人呼叫的方法:摘要報告的 get_project_summary_reports、get_project_summary_report_by_id,可刪。
  • 稽核階段「目前進度」查詢:非成員仍查得到資料(CM-2035 範圍外)。
  • list_ap_parties 查不到輪次就放行:寫法偏寬,總測時留意(CM-2037 順帶)。
  • 儲存設定新建時密碼留空:只有前端擋,後端 create_system_config 沒檢查(CM-2063 順帶)。
  • tamper_event_repo.exists 沒人呼叫:開機查鎖改由宿主的短命連線做,這支舊方法閒置。
  • 管理者代刪問卷討論:CM-2024 卡上沒要求,沒做。

8.4 擋得到、擋不到的分界

不要把這批修正理解成「風險歸零」。

  • 代理程式(CM-2052):修完後,網路上的外人冒充不了代理程式、A 客戶冒充不了 B 客戶、被撤銷的機器當場斷線。擋不到的是能實際碰到那台代理程式主機的人,他撈得到機器上的私鑰與通行證。這是設計本身:代理程式要登入客戶主機做掃描,就一定得拿到那些鑰匙,而那台機器在客戶自己的機房。風險範圍從「網路上任何人」縮小到「能實際碰到那台機器的人」。
  • 防竄改(CM-2053):修完後,換掉驗簽零件、刪標記檔、手寫回執、換核對目錄這幾條已知的一步得手路徑都堵住了。擋不到的是有能力改整包執行檔(binary)的人:驗簽工具編進核心層,是讓「換一個零件」不再可行,但能整包重編或改二進位的人仍然繞得過。這套機制的定位是擋住隨手改檔案,不是擋住有完整主機權限又懂內部運作的攻擊者。
  • #91 為什麼只記警示:解鎖碼帳本檔毀損時如果直接拒絕開機,而原廠目前沒有「帳本壞了重新簽發」的流程,機器一壞就永遠解不開。所以降級成高等級警示,等原廠有重簽流程再收緊。

9. 給你的裁決清單

① 什麼時候合回

  • 現在合:清理卡做完就照第 3 節步驟開始合回、發版、部署 DEV、總測。第 6 批與 5B-5 之後在主線上另外做。
  • 等 5B-5 與第 6 批一起:三張剩下的卡也做完才一次合回。代價是第 6 批要等 CM-1849,時間不確定,這段期間主線繼續往前跑,合回衝突會變多。

② 發版順序確認

  • 照第 3 節步驟表:套件先合先發(jedi-common 最先),BE 改 pin,FE,代理程式,然後雲端與代理程式同一次上 DEV。你只要回「照表」。
  • 要調整:請指出哪一步要換。

③ #96、#97 郵件密碼寫進紀錄檔與連線不認人

  • 另開卡納入本 arc:改動小(錯誤訊息不帶整組設定、加密時驗證對方憑證),可以跟這批一起合回、一起總測。
  • 維持 CM-1606 另排:本批合回不等它,報告上這兩件繼續標未修。

④ 開機查資料庫失敗時的放行範圍

  • 維持現狀:任何查詢失敗都放行並警示。客戶端資料庫任何小毛病都不會擋開機,但「改權限讓查詢失敗」這條繞法留著。
  • 收窄:只有「真的連不上」才放行,「連得上但查詢失敗」改成拒絕開機。擋掉那條繞法,代價是資料庫權限或結構有問題時客戶會開不了機,要靠支援排除。

⑤ 出貨基線什麼時候重產

  • 合回主線後、188 全量 build 前做(建議):build 的出包檢查才不會紅。
  • 等 STG/POC 上版前再做:現在不動 188 基線庫,但在那之前出不了包。

⑥ 另開卡候選要開哪些(第 8.3 節八項,每項回「開」或「不開」即可)

  • 我的建議:「公版一般角色範本」與「儲存設定後端密碼空值檢查」值得開;「兩支死方法」「tamper_event_repo.exists」可以併進下一張清理卡;其餘總測時觀察再定。

⑦ 小事,合回時順便裁

  • 套件 monorepo 還有 10 支沒有 poetry.lock(含 6 支封存的),要補:合回時一起跑。不補:維持現狀,只有那 17 支有 lock。