本卡屬 FR-114 資安修正(母卡 CM-2019),第 4 批「憑證殘留」卡 4-3,修 SUMMARY #70(出自模組報告,jedi-detection)。中。修法規格來自本批查證,計畫在 docs/features/FR-114-2609-security-fix-dispatch/batches/plan-b4.md「卡 4-3」段。
問題是什麼(白話)
掃描弱點時,程式在把「這次要掃什麼」的工作單(派工表 agent_tasks)寫進資料庫時,多此一舉地把解密後的明文帳密也一起塞進去存了一份。這份多存的明文完全沒有任何程式在讀它——代理程式(agent)實際拿到帳密走的是另一條、心跳時才重新解密組裝的正確路徑,這行是舊的殘留,刪掉不會影響任何功能。
首腦核對:
- 寫入點:jedi-detection/jedi_detection/app/service/detection_orchestration_service.py:480,在 _dispatch_one()(:438-517)裡,params["_credentials"] = creds 這一行,整個 params 字典會被存進 agent_tasks.params(JSONB 欄位)
- 兩條呼叫路徑都會經過這一行:正常派工路徑(:215-217 呼叫 _resolve_credentials,:1397-1430 定義,:1429 用 self._crypto.decrypt 解密)與「立即重新指派/重跑」路徑(:942-947 的 start_assignment_now(),一樣拿到 creds 後在 :980 呼叫同一個 _dispatch_one())——所以只要刪這一行,兩條路都同時修好,不用改兩處
- 零讀者驗證:套件內 grep _credentials 只命中寫入處本身(:215/:218/:480)與 4 個註解(:603/:605/:799/:2273),沒有任何程式碼在讀 params["_credentials"];BE 側 grep "_credentials" 也是 0 命中
- 確認安全可刪的關鍵:agent 實際拿到憑證走的是另一條、獨立的路徑——BE 的 infra/remote_agent/adapter/detection_task_payload_provider.py:68 在心跳時呼叫 _resolve_tool_credentials()(同檔 :109-125,:124 自己重新做一次 json.loads(self._crypto.decrypt(...))),這是與 agent_tasks.params 完全無關、心跳當下才組裝的全新解密副本;套件自己 :799 的註解也印證設計意圖是「改由心跳組裝時當場注入」,:480 那行是舊殘留;既有測試 test/test_agent_enrollment_service.py:376(test_heartbeat_attaches_pending_tasks_with_decrypted_credentials)就是在測這條正確的活路徑
工作區
- 套件側:在 /Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/.claude/worktrees/jedi-wt-fix-security/jedi-detection(branch fix/security-b1)改,只動自己這支套件的子目錄、只 git add 該子目錄下的檔。
- 跨 repo:BE 工作區 pyproject.toml 把 jedi-detection 的 pin 改成 path dependency 指向套件工作區,develop = true,poetry update jedi-detection。這個 path 改動不 commit。
在哪裡
jedi_detection/app/service/detection_orchestration_service.py:480 params["_credentials"] = creds 這一行,整支刪除
jedi_detection/app/service/detection_orchestration_service.py:438-517 _dispatch_one(),刪除那行所在的函式(只刪那一行,函式其他部分不動)
jedi_detection/app/service/detection_orchestration_service.py:942-947 start_assignment_now()(第二條呼叫路徑,:980 呼叫 _dispatch_one,不需改這裡,因為只刪一行就兩條路都修好)
jedi-remote-agent/jedi_remote_agent/infra/agent_task/model/agent_task.py:45 agent_tasks 的 params JSONB 欄位 model(參考用,不改)
infra/remote_agent/adapter/detection_task_payload_provider.py:68,109-125 正確的心跳重新解密路徑(參考用,確認不受影響,不改)
怎麼修
- ① 刪除 detection_orchestration_service.py:480 這一行 params["_credentials"] = creds,不動 _dispatch_one() 函式其他部分。
- ② 資料庫既有殘留資料清理:對 agent_tasks 表跑 UPDATE agent_tasks SET params = params - '_credentials' WHERE params ? '_credentials';(JSONB 移除單一 key,不動其他欄位)。⚠️ 動手前先做唯讀計數:SELECT count(*) FROM agent_tasks WHERE params ? '_credentials'; 先在 DEV 查一次,把這個數字記進 Notion 卡當驗收基準,再執行清理。
- ③ DEV 先跑清理;STG/POC 的清理需要決策者明確放行才能做(寫入類環境異動),本卡先不動,回寫時記錄「DEV 已清,STG/POC 待裁示」。
手測
- DEV:跑一次完整「開始掃描」流程 → 確認新產生的 agent_tasks 紀錄 params 裡不再出現 _credentials 這個 key(SELECT count(*) 對新紀錄應為 0)
- DEV:同一輪確認 agent 仍然正確拿到憑證並執行掃描到完成(不是卡在「缺欄位」)