本卡屬 FR-111(母卡見建卡後補號),第 3 棒:舊 Drive 線:觸發/job 狀態/Drive 讀寫/正解匯入(jedi-evidence-classification,4 檔 1,781 行)。只掃不修。
FR-107 之前的舊路徑:直接掃客戶雲端硬碟(Google Drive)某個資料夾裡的證據檔、把分類結果與紀錄寫回硬碟。觸發端點已標 legacy(CM-1868)但仍掛在路由表上,加上查 job 狀態、讀 Drive 檔預覽、匯入正解四條線。
舊線沒拆,就是攻擊面。它拿的是租戶授權的 Drive token(能讀到什麼取決於授權範圍)、job 登記簿是整個程序共用的 dict、容器紀錄會上傳到客戶硬碟。FR-110 剛把 Drive 憑證改成畫面設定,token 取得路徑變了但套件側的用法沒變。
evidence_classification_route.py:59-72、evidence_classification_service.py:136-246 trigger_classify、:247 _derive_evidence_folder_id):body 帶 evidence_folder_id 就掃那個資料夾。守門驗專案 manager(_require_project_manager :118),但沒驗那個資料夾屬於這個專案——用該租戶 token 讀得到的任何 Drive 資料夾都掃得到(授權範圍若是 drive 全域而非 drive.file,就是客戶整個雲端硬碟)。驗 override 有沒有比對 IEvidenceSource.get_folder_id 的結果。evidence_classification_route.py:79-90、job_registry.py:22-60):ClassifyJobStatusRoute.get 只查 job_uid 存不存在、不驗 project/tenant;JobRegistry._jobs 是程序級 dict、鍵只有 job_uid。拿到 job_uid(route 有 project_uid 但沒用它過濾)就能讀別租戶的 job 內容:資料夾 ID、模型、狀態、錯誤訊息原文。ClassifyJobListRoute :93-109 有沒有守門也對一下。_finalize_drive_output :348-496、archive_run :892、put_state :752):容器紀錄(_container-log.txt,E1 ②)、_state.json、報告上傳到客戶硬碟的 run 資料夾;copy_file 把證據檔複製進各控制項資料夾。驗上傳前有沒有二次遮蔽、失敗時原文會不會留在本機工作目錄;ensure_ao_folder 用 AI 回的 ao_id 當資料夾名——名稱來自 AI 輸出,能不能含 / 或 Drive 特殊字元。evidence_drive_ops.py):_service :43 每次拿 token;read_text_file :88 有 5MB 上限、download_bytes :101 有沒有上限;list_children :50 查詢用 parent_id 組 q 字串——parent_id 來自 ①的 override,能不能注入 Drive 查詢語法('{parent_id}' in parents 這種字串拼接)。get_state :666、get_file_preview :696、get_validation_report :1064、get_adjudication_report :1117、list_jobs_for_project :556):走 _resolve_tenant_for_run_folder(:978)與 _ensure_run_persisted_for_read(:999)——run_folder_id 是 Drive 資料夾 ID、來自 URL;查無 DB 紀錄時會不會退回「直接去 Drive 讀」(那就是任何 participant 給個資料夾 ID 就能透過系統的 token 讀客戶硬碟任意資料夾)。get_file_preview 的 file_drive_id 有沒有驗屬於該 run 資料夾。import_ground_truth :1098、ClassificationGroundTruthImportRoute route :207-225):守門是 _require_any_project_manager(租戶內任一專案 manager)——租戶層資料由任一專案 manager 改;mapping dict 大小與內容驗證;tenant_id 從 user_context 拿(不從 body)確認。_run_classify_worker :294-347):與 E2 ③ 同題但這是舊線自己的實作——set_user_context 帶了嗎、_persist_run_to_db :497 在哪個 scope。本套件從未掃過。 觸發端點 POST /projects/<uid>/evidence/classify 已標 legacy(CM-1868 3835bdb)、FR-110 記「離線 Drive 分類腳本已停用待 FR-107 舊線一併刪」——但路由仍掛著(api/routing.py:40-56),掃它是為了知道「留著會怎樣」,結論可以是「刪掉就好」。Drive token 由主專案 google_drive_token_manager 供(di_containers/evidence_classification/evidence_classification_containers.py:86-94),授權範圍(scope)在主專案 Drive 整合那邊決定,不在本棒;runner 查一下主專案 grep -rn 'drive.file\|auth/drive' app/cloud_integration 記在報告即可,不深追。正解表 evidence_classification_ground_truth DEV 實查已開 RLS 4 條(002 檔頭「刻意不掛」已過時,別被說服)。
第一步:驗 scope 檔數與行數,對上 4 檔/約 1,781 行才啟動(scope 以套件 HEAD 955e409 為準;git log -1 --format=%h 不是它就先回報,不自行改 scope):
cd /Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/jedi-evidence-classification && git ls-files -- jedi_evidence_classification/app/service/evidence_classification_service.py jedi_evidence_classification/api/routes/evidence_classification_route.py jedi_evidence_classification/infra/evidence_drive_ops.py jedi_evidence_classification/app/service/job_registry.py | wc -l # 要 = 4
cat jedi_evidence_classification/app/service/evidence_classification_service.py jedi_evidence_classification/api/routes/evidence_classification_route.py jedi_evidence_classification/infra/evidence_drive_ops.py jedi_evidence_classification/app/service/job_registry.py | wc -l # 要 ≈ 1781
第二步:把啟動指令交給決策者(你不能自己啟動)。/claude-security 這個 skill 帶 disable-model-invocation: true,模型用 Skill tool 叫會被擋;也不可以自己叫 Workflow 或自己派研究員/verifier 代替它——面板票數是工具算的、報告的驗證章蓋在那個數字上。這是刻意設計不是故障,撞到不要 debug、不要找繞路。
檔數對上後停下回報:說「檔數 4 已對上,可啟動」,並把下面兩行原樣附在回報裡交還給決策者,由決策者在本 session 親手打(單次送出、第二行不能省、每個新 session 都要重打):