FR-114 資安修正派工計畫

FR-114 資安修正派工計畫

這份文件是什麼:docs/security-report/SUMMARY.md 的問題總表是按嚴重度排的檢視結果,不是派工單。這份計畫把 145 件翻成「一個工作區一張卡、一個工程師一次做完哪些事」。決策者看過、裁完第 6 節後,才照它建 Notion 卡。

狀態:🟡 計畫待審(尚未開卡)|母卡 CM-2019|每批的逐卡細節在 batches/plan-b*.md,本頁是總覽。


1. 30 秒版

整案一句話:145 件裡 121 件要動手(24 件已修或裁定不修),拆成 46 張卡,分六批;第 1、3、4、5 批今天就能開,第 2 批要等第 1 批合回主線+套件發版,第 6 批等程式面修完測過一版。

批 做什麼 卡 能不能現在開 動哪些 repo
1 權限地基 把「誰有資格動這筆東西」的判斷做出來(任務完成/退回只准指派人與管理者、專案成員寫入要驗物、公告/設備/意見回饋的擁有者判斷) 9 ✅ 現在開 BE、jedi-detection/task-platform/survey/bulletin/asset/issue
2 只驗登入不檢查歸屬 29 件全是「補一行去問第 1 批」:檔案四出口、問卷六支、流程四處、名冊、摘要報告、AI 儀表板 26 支、資源庫三入口、檢測 8 支 10 🔴 等第 1 批合回+套件發版 六支套件+BE
3 刪除沒人用的 舊版證據分類、零呼叫的任務功能、開發小工具、死開關、成員名冊死程式、快速設定畫面、快取複製品 5 ✅ 現在開 BE、FE、jedi-task-platform/common/issue
4 憑證殘留 密碼全部已換發,清版控字串;另兩件真修(派工表明文落表、Google 金鑰) 4+沿用 CM-1998 ✅ 現在開 BE、FE、jedi-detection
5 設定與信任鏈 代理程式身分、防竄改、客戶層級改全域、交出去要編碼、停權即時生效、上限類、AI 兩塊、儲存帳密明文 18(含 1 張驗證卡) ✅ 現在開(兩張要先裁方向) agent、BE、FE、十支套件
6 資料庫牆 SaaS 前 53 張表補隔離、授權三張表方向、M18-8 停權復權 0(本棒不開) ⏸ 程式面修完→測一版→再開 BE migration

工作區怎麼開(決策者 2026-09-21 裁定:依序做、不平行;開 worktree 是為了不碰掃描線正在讀的主 checkout):只開兩個常駐工作區——BE 一個、套件 monorepo 一個——所有卡依序在裡面做,一張卡一個 commit,做完驗過再派下一張。第 3、5 批 FE/agent 那兩張卡到時各自在 FE/agent repo 開一個。


2. 工作區(worktree)配置

2.1 為什麼開 worktree、開幾個

  • 目的是隔離,不是平行:FR-113 掃描線正在讀 BE 主 checkout(feature/review),修正不能在那裡動。套件 monorepo 沒有掃描在跑,但 BE 工作區的 path dependency 要指向一個固定路徑,開一個 worktree 讓它指過去比較乾淨。
  • 常駐兩個:
工作區 開在哪 指令 誰在裡面做
BE ~/Projects/Billows/Audit-Manager/wt-fix-security(BE repo 旁邊) cd compliance-manager-be && git worktree add ../wt-fix-security -b fix/security-b1 所有 BE 側的卡(1-1、1-8、1-9、2-5、2-7、2-8、2-9、3-1、4-1、4-2、5A-2/3 的 BE 半、5B-3 的 BE 半、5C-2、5C-7…)
套件 ~/Projects/Jedicogy/module/jedi-wt-fix-security(monorepo 旁邊) cd jedi-python-package && git worktree add ../jedi-wt-fix-security -b fix/security-b1 所有套件側的卡;runner 只動自己那支套件的子目錄、只 git add 該子目錄
  • BE 工作區的 pyproject.toml:把本卡動到的套件 pin 改成 path dependency 指向套件工作區(例:jedi-task-platform = { path = "/Users/chouraymond/Projects/Jedicogy/module/jedi-wt-fix-security/jedi-task-platform", develop = true }),poetry update jedi-task-platform。這個改動不 commit;一張卡做完不用還原(下一張卡接著用),整批合回前才還原 pin。BE 工作區跑服務用另一個 port(例 PORT=8001),不跟主 checkout 的 8000 撞。
  • FE 卡(3-5、1-5 若拆出 FE 半、5A-5 的下拉)到時在 FE repo 開 wt-fix-security;agent 卡(5A-1)到時在 agent repo 開。
  • 同一張 branch 累積多張卡的 commit:branch 名不帶卡號,因為卡是依序做的;commit message 帶卡號。

2.2 依序做的順序(一次一張,做完驗過再派下一張)

  1. 第 1 批:1-1 → 1-3 → 1-4 → 1-5 → 1-7 → 1-8 → 1-9 → 1-6(等 1-9 的 migration 套 DEV)→ 1-2(等 1-1)
  2. 第 3 批(可插在第 1 批任何位置,互不相干):3-1 → 3-2 → 3-3 → 3-4 → 3-5(FE)
  3. 第 4 批(同上可插):4-3 → 4-1 → 4-2 → 4-4
  4. 第 5 批:先派方向已定的(5A-3、5A-4+5C-7 合併、5A-5、5B-1~5B-4、5C-1~5C-5、5C-8),5A-1/5A-2 裁完方向再派,5C-6 排最後(動所有 pyproject)
  5. 合回+套件發版(決策者下令)→ 第 2 批:2-1 → 2-2 → 2-3 → 2-4 → 2-5 → 2-6 → 2-7 → 2-8 → 2-9 → 2-10
  6. 測過一版 → 第 6 批開卡

2.3 合回與發版順序(誰下令)

事 什麼時候 誰下令
fix/security-b1 合回各 repo 的 feature/review 一批做完、首腦驗收通過 決策者(合回=對主線的變更)
套件發版(bump + 推 Nexus) 第 1 批合回後(第 2 批要吃新守門) 決策者(CLAUDE.md:絕對禁止自動發版)
第 2 批開卡派工 套件發版、BE pin 更新後 決策者
第 6 批開卡 第 1~5 批合回、測過一版 決策者

2.4 先後有相依的卡(依序做時要守的順序)

先 → 後 為什麼
1-1 → 1-2 1-2 呼叫的方法是 1-1 做出來的;反過來是 AttributeError 500
1-9 → 1-6 1-9 的 migration 先套 DEV,否則 1-6 驗起來五個下拉選單安靜變空
2-8 → 2-9 2-9 照抄 2-8 的寫法
5A-4 → 5C-7 合併成一張(見 §6 D-X2),先套件側再 BE 接上
其他卡 → 5C-6 5C-6 動每一支 pyproject.toml,排最後

3. 各批的卡片(總表;逐卡的修法、入口清單、手測見 batches/plan-b*.md)

第 1 批 權限地基(13 件 → 9 張)→ batches/plan-b1.md

卡 做什麼 repo # model
1-1 任務「完成/退回」改成只有被指派人與管理者能做(新開一道嚴守門) BE 37 opus/medium
1-2 弱點掃描八支改狀態端點改吃那道新守門 jedi-detection 37 sonnet/medium
1-3 專案成員與任務指派寫入時,反查填進來的東西是不是這個專案的 jedi-task-platform 41、109、110 opus/medium
1-4 問卷還原歷史版本要驗版本歸屬;討論改/刪要驗作者本人 jedi-survey 38、39 opus/medium
1-5 公告改/刪要驗是不是自己發的;發送對象改必選 jedi-bulletin 42、111 opus/high
1-6 設備清冊七支讀取補權限;修改請求不准夾帶停用/啟用 jedi-asset 43、112 opus/medium
1-7 意見回饋六支裸奔端點補權限,改/刪補「這筆是不是你的」,清單分兩套 jedi-issue 45 opus/high
1-8 「檢查流程圖」端點補權限與輸入上限 BE 40 sonnet/medium
1-9 兩支 migration:設備讀取權限給稽核人員角色、放寬意見回饋新增規則 BE scripts/sql/ 44、43 sonnet/medium

第 2 批 只驗登入不檢查歸屬(29 件 → 10 張,等第 1 批)→ batches/plan-b2.md

卡 做什麼 repo # model
2-1 檔案四個出口取檔前先問「這個檔掛在哪、你碰不碰得到」(新增共用通道+登記表) jedi-file-upload+BE+jedi-issue 3 opus/high
2-2 問卷六支讀取補「編號必填+你是這個專案的人」,含共編房間 jedi-survey 5、6、48~51 opus/medium
2-3 稽核流程四處補歸屬檢查,流程範本讀取補權限 jedi-flow-engine+BE+jedi-compliance-audit 7、8、52、53、115 opus/high
2-4 專案名冊與任務指派清單四支補「編號必填+成員」(#59 在此結案) jedi-task-platform 54、55、58、59 sonnet/medium
2-5 專案摘要報告五支讀取與稽核輪次選單補參與者檢查 BE+jedi-compliance-audit 56、57 sonnet/medium
2-6 AI 儀表板 26 支查詢加「要什麼權限」欄位並在呼叫前檢查,拿掉視同管理員後門 jedi-ai-dashboard+BE+jedi-common 60、61、62、114 opus/high
2-7 查任務詳細資料補「屬不屬於網址上那個專案」,改與刪也補 BE 63 sonnet/medium
2-8 合規資源庫三入口補歸屬檢查、建立入口補權限與用量上限 BE(oscal) 46、65 opus/high
2-9 刪佐證文件/文件庫文件時核對「要刪的屬不屬於你管的那份計畫」 BE(oscal) 64 sonnet/medium
2-10 弱點檢測「測試連線」補權限,八支讀取補權限 jedi-detection 4、47、113 opus/medium

第 3 批 刪除沒人用的(11 件+M13-10 → 5 張)→ batches/plan-b3.md

卡 做什麼 repo # model
3-1 M13 快取連線複製品刪除、改用套件那份(M07 舊線那半見 §6 D-X1) BE M13-10(+9、66、67 待裁) sonnet/medium
3-2 拆掉三組零呼叫的任務管理功能 jedi-task-platform 68、69、120 sonnet/medium
3-3 刪開發小工具+刪死開關 jedi-common 116、117 sonnet/medium
3-4 刪全站成員名冊死程式 jedi-issue 121 sonnet/medium
3-5 拆除「快速設定」獨立畫面兩個入口 FE 119 sonnet/medium

⚠️ 這批材料檔沒有程式座標,11 個入口全部要在開卡前補查(首腦派 opus 一支補,不佔 runner)。

第 4 批 憑證殘留(10 件 → 4 張+沿用 CM-1998)→ batches/plan-b4.md

卡 做什麼 repo # model
4-1 清版控裡的憑證殘留字串(外部平台通行證/AI 金鑰/管理員密碼/交接文件帳密) BE 10、11、72、73、122 sonnet/medium
4-2 資料庫管理員密碼 249 檔殘留+堵住還在寫入的路徑 BE(初判) 12 sonnet/medium
4-3 開始掃描時不再把明文帳密多存一份進派工表(程式修正) jedi-detection 70 sonnet/medium
4-4 Google 雲端硬碟金鑰清殘留字串(金鑰重設另裁,見 D-b4-3) 待補查 74 sonnet/medium
沿用 打包前端映像檔腳本內嵌 Nexus 帳密 BE+FE 75 既有卡 CM-1998

⚠️ 249 檔與 15 檔清單要在開卡前盤點附卡(唯讀 grep,首腦做;不把憑證印進卡,只列檔案路徑)。

第 5 批 設定與信任鏈(54 件 → 18 張)

A 子集 → batches/plan-b5A.md | 卡 | 做什麼 | repo | # | model | |---|---|---|---|---| | 5A-1 | 代理程式每次打進來都要證明身分,「撤銷」真的斷乾淨 | evidence-agent+jedi-remote-agent | 1 | fable/high(先裁方向) | | 5A-2 | 驗簽工具與鎖定紀錄變成拔不掉的 | jedi-integrity+BE | 17、18、90、91、133 | fable/high(先裁方向) | | 5A-3 | 「改全公司共用設定」收到客戶總部那一層,儲存設定密鑰遮蓋 | jedi-system-core+jedi-log+BE | 19、22、134 | opus/high | | 5A-4 | 交出去統一編碼:匯出試算表不被當公式、日誌不被讀成兩筆(共用函式放 jedi-common) | jedi-common+jedi-log+jedi-issue | 20、93 | opus/high | | 5A-5 | 停權當下通行證立刻失效;日誌轉送加密選項 | jedi-iam+jedi-log+FE | M13-17、92 | opus/medium |

B 子集 → batches/plan-b5B.md | 卡 | 做什麼 | repo | # | model | |---|---|---|---|---| | 5B-1 | 規則包解析前先看內容;三道防炸彈上限搬到所有來源都經過的那層 | jedi-detection | 15、76、77、78 | opus/high | | 5B-2 | 弱點檢測三處資源上限:測試連線收斂、重新解析去重、換工具用生效值重查 | jedi-detection | 79、80、81 | opus/high | | 5B-3 | 流程圖走訪記路+補上限;範本新增修改與起輪次一定過檢查 | jedi-flow-engine+BE | 16、87、88、128 | opus/high | | 5B-4 | 問卷資料夾與即時填答:身分改用登入身分、送進來的欄位逐一收掉 | jedi-survey | 85、86、126、127 | opus/high | | 5B-5 | 驗證卡:確認 M07 五件是否已隨舊線退役消失(第 3 批之後) | jedi-evidence-classification | 89、129~132 | opus/medium |

C 子集 → batches/plan-b5C.md | 卡 | 做什麼 | repo | # | model | |---|---|---|---|---| | 5C-1 | 別人點預覽時跑不起攻擊者的程式;存檔前先洗檔名 | jedi-file-upload+jedi-detection | 13、123 | opus/high | | 5C-2 | 儲存空間帳密不再回傳前端,連線改加密(M22-2 那側在 5A-3) | BE+FE | 14、124 | opus/high | | 5C-3 | AI 助手與儀表板補逾時、次數上限,停止整包送出密碼材料 | jedi-ai-dashboard+jedi-ai-bot+jedi-common | 21、94、95 | opus/high | | 5C-4 | 共用底層五處小修:密碼遮乾淨、清單筆數上限、設定打錯字往嚴的倒、寫日誌失敗不連累請求、紀錄等級 | jedi-common | 82、83=136、84、103、125 | opus/high | | 5C-5 | 意見回饋:連 GitHub 恢復身分驗證;刪附件用上算好的過濾結果 | jedi-issue | 100、135 | sonnet/medium | | 5C-6 | 內部套件倉庫全面改走加密連線,版本鎖定檔納版控(先查 Nexus 有沒有 TLS) | monorepo 28 支+BE+FE | 101 | sonnet/medium | | 5C-7 | 匯出 Word/Excel 把使用者填的字當資料處理(與 5A-4 合併見 D-X2) | BE | 102 | opus/high | | 5C-8 | 自動產生密碼補回少的那個字元;清兩支零引用複製品 | jedi-survey+jedi-log | 137 | sonnet/medium | | 不開 | #98 安裝程式同一組最高權限帳密(裁定暫不調整)、#99 三環境共用公鑰(等正式簽發站) | — | 98、99 | — |


4. 第 6 批:資料庫最後一道牆(本棒不開卡)

# 件 開卡條件
105 SaaS 前 53 張表補隔離(併 M11) 第 1~5 批合回、測過一版、決策者裁「開牆」
104 隔離規則方向寫反 11 條(8 張改方向、授權 3 張讀保持寫要擋) 同上;授權那 3 張的裁定見交接文件「M03 那 11 張表要分兩組改」
23 被停權客戶用子單位帳號刪停權紀錄復權(M18-8) 同上(是 #104 授權三張表那組的直接後果)
24 13 張表隔離牆「部分修」(M20-1) 同上

5. 報告頁八處不一致的歸屬(CM-2020 併入本棒)

處 是什麼 誰改
① M15 第 6 條狀態 vs M17 第 10 條(同一組帳密):M15 改「已修正、殘留待清」 卡 4-1 runner(#73)
② M17 第 135 行「27 支」→ 26 支 首腦
③ M17 第 8 條 vs M23 第 1 條:以 M23 🟠 高為準,狀態統一「密碼已換發、249 檔殘留待清」,M23 修法第三步標已完成 卡 4-2 runner(#12)
④ M16 第 100 行指向:三頁統一「同一組密碼、總表只計一次」 卡 4-2 runner
⑤ M10 第 86 行「12 條其中 3 條刪除」範圍措辭 首腦
⑥ M19 統計表 4/2/1 與問題表 3 列對不上 首腦
⑦ M20 統計表「未修 0 條」→「2 條只修一半」 首腦
⑧ 掃描總表 §3.3 兩項已過期(S7 重掃、R1b 補掃已完成) 首腦

6. 決策者要裁的事

七份批次計畫共列了 42 項待裁(各批檔末段),大多數是 runner 動手時才要選的細節、且每項都附了建議。這裡只把「不裁就不能開卡」的抓出來;其餘照各卡建議走,runner 卡上會寫「先回寫問決策者再動手」。

我自己查出來的兩個跨批衝突(先裁這兩個)

D-X1 舊版證據分類退役已有人在管,第 3 批要不要再開? 第 3 批 3-1 卡把 #9/#66/#67「M07 舊線退役」排進去,但 Notion 已有 CM-1849(FR-107.6 舊線退場+收口,4 張子任務卡,Not started) 在管這件事,且 M07 模組頁第 77~87 行寫明退役要照完整清單逐支做(含被鎖定的網址清單要一起改、否則自動測試會失敗)。

  • 我的建議:第 3 批不再開退役卡,3-1 只做 M13 快取複製品那半;#9/#66/#67 在 SUMMARY 標「由 CM-1849 處理」,5B-5 驗證卡改成「等 CM-1849 做完再驗」。兩張卡做同一件事只會互撞。

D-X2 「匯出時把 = + - @ 開頭的字標成純文字」這支共用函式,只准有一份 5A-4(jedi-common 抽一支,給 jedi-log 與 jedi-issue 的匯出用)與 5C-7(BE 抽一支,給 Word/Excel 匯出用)會各自長一份。5C 子集實查過:FR-113 README 說「早就抽過、三個出口沿用」的那支函式不存在。

  • 我的建議:合併成一張卡,函式放 jedi-common(BE 與所有套件都拿得到),先做套件側再回 BE 接上,序列 5A-4 → 5C-7 同一個 runner。

各批「動手前必裁」的(其餘見各批檔)

批 項 一句話 我的建議
1 D-b1-1 任務完成/退回的嚴守門:新開一支,還是把既有那支收嚴(收嚴會連帶改到佐證上傳那三支) 新開一支,佐證那三支留給後續照同一支接
1 D-b1-2 公告發送對象改必選後,既有「發送對象是空的」舊公告怎麼辦 多一個「發送範圍」欄位,舊資料一律標全公司(它們現在實際就是全公司可見);卡 1-5 因此拆成套件+migration+FE 三張
1 D-b1-3 意見回饋「我的」與「管理頁」後端怎麼分辨 同一支入口多一個範圍參數(原則二:不為情境各開路由)
2 D-b2-3 流程範本到底要不要權限(還是人人可看) 補權限(同一家客戶內沒被授權的人不該看到階段設計與判斷條件)
2 D-b2-5 合規資源庫開放哪些角色建 專案管理者+客戶管理員,一般成員不開
4 D-b4-1 清殘留字串要不要改寫 git 歷史 只清現存檔案,不改歷史(憑證已失效,改歷史動到所有人的 commit)
4 D-b4-3 Google 金鑰重設+重新加密既有通行證要不要併進第 4 批 另開一張獨立卡排在 4-4 後面
5A D-b5A-1 代理程式拿什麼當身分證明:短效通行證 vs 客戶端憑證 短效通行證當主軸(不必動客戶機房設備)
5A D-b5A-3 驗簽工具怎麼變成拔不掉的(三方案) 方案①:在產生防竄改清單的工具裡新增「安全關鍵」分層
5A D-b5A-4 鎖定紀錄治本:開機查資料庫,還是補同步反向補回;DB 連不上時擋不擋開機 開機查 DB+反向補同步當輔助;連不上時放行並記警示(原則十一)
5C D-b5C-2 內建物件儲存有沒有開加密——沒有的話 5C-2 要連帶做 runner 第一步只唯讀查證回報,不先改
5C D-b5C-8 Nexus 有沒有 TLS——沒有的話 5C-6 動不了 同上,先查再說

不用裁、我會直接照建議進卡的

D-b2-1/2/4/6/7/8、D-b3-1(由 D-X1 取代)、D-b4-2(首腦盤點)、D-b5A-2/5/6/7/8/9/10、D-b5B-1~6、D-b5C-1/3/4/5/6/7/9/10(由 D-X2 取代)/11——各項的問題與建議在對應批次檔末段,你若對哪項有意見再點名。


7. 開卡前首腦要補的(決策者點頭後、建卡前做)

  1. 第 3 批 11 個入口座標(派 opus 一支補查,唯讀)
  2. 第 4 批 249 檔與 15 檔清單(唯讀 grep,只列路徑)
  3. 第 1 批 5 個待補:detection complete_job 要不要跟著收嚴、batch_add_task_assignees 是否經過單筆、project_group_participant_service.py 三支寫入整支無守門是不是 #109 漏記的、survey_discussions 有沒有軟刪欄位、內建範本有沒有超過 100 節點
  4. 第 5 批 A/B 共 5 個待補(FE 日誌轉送下拉元件、_read_entries()、重抽入口、if entity.xml:)
  5. 第 2 批 1 個:稽核輪次同檔統計功能要不要一次補完

8. 共同紀律(每張卡都會帶)

  • runner 做完程式後順手把該條在模組頁(docs/security-report/M<NN>-*.md)與 SUMMARY.md 的狀態改「已修」+修法一句,重 build(python scripts/deliverables/render_index.py docs/security-report/ --site-root docs/security-report/),再 Notion 回寫。只動狀態欄與修法那句,不重寫段落。
  • 每個入口 file:line 都是驗收項,每個入口都改了才收(同一個問題常有 route+service+FE 三個入口)。
  • 功能不能壞(原則三)、安全措施不可擋正常客戶(原則十一)、刪除前零引用(原則十五)。
  • 套件 path dependency 改動不 commit;顯式 git add;做完立刻 commit+回寫+狀態改「修正待驗證」;不 push、不切 branch、不發版。
  • 檔案內註解只寫「為什麼」與「陷阱」,做了什麼進 commit message。
  • 動到已超過 800 行的檔(例:workflow_execution_service.py 1,374 行)新邏輯一律新開檔。