本卡屬 FR-111(母卡見建卡後補號),第 1 棒:容器執行鏈:docker 命令組裝/金鑰下發/容器端程式/log 遮蔽(jedi-evidence-classification,7 檔 1,476 行)。只掃不修。
宿主怎麼把 docker run 命令組起來、AI 金鑰怎麼交給容器、容器端程式怎麼讀證據檔並呼叫 AI 服務、容器跑完的紀錄怎麼遮蔽落地。
這是整支套件最該看的一塊:唯一直接拿 AI 金鑰、唯一跑外部程式的地方。容器跑在客戶主機上,金鑰經過的每一段(宿主→命令列→容器環境變數→AI 服務)都可能留下痕跡。跨 arc 總表 §3.4 記著「遮蔽只靠字串比對、docker 白名單擋不擋得住繞過要驗證」——就是這一棒。
classifier_container_runner.py:150-169):AI 金鑰用 -e ANTHROPIC_API_KEY=<值> 放進 docker run 的命令列參數。docker run 這個程序活著期間(容器跑幾分鐘到幾十分鐘),同一台主機任何帳號跑 ps aux 都看得到整串命令含金鑰。落地版 BE 與其他服務同機是真實情境。驗:有沒有改走 --env-file 或 stdin 的可能、docker 自己會不會把命令列寫進 daemon log。classifier_container_runner.py:205-224):遮蔽只把 -e KEY=VALUE 換成 KEY=***,容器印到 stdout/stderr 的內容原文落地 _container-log.txt。這份檔後面會被存進 run 紀錄、上傳客戶雲端硬碟、前端報告可讀。驗:容器端 llm_clients.py:92-124(重試與例外收斂)、:143-160、:208-227——AI 服務回 401/429 時例外訊息帶不帶金鑰片段或請求標頭;container_entrypoint.py 有沒有把 os.environ 或整個 args 印出來。跨 arc 總表 §3.4 提的「base64/URL-encoded/拆段寫法遮不遮得到」在這裡不成立(遮的是 argv 位置不是字串比對),但要驗 stderr 那條。classifier_container_runner.py:53-66、:128-133):_SAFE_ARG_RE 擋 - 開頭;驗 provider/model/effort/framework_id/container_network 五個進 argv 的值各從哪來(E2/E4 已比對碼表?)、-v {job_dir}:/job 的 job_dir 由 job_uid 組成——job_uid 是 {batch_uid}-{run_uid} 兩個 uuid,能不能塞 ..。--network bridge 讓容器能出網:容器內程式除了 AI 服務還能連哪裡(宿主 DB port?)。container_entrypoint.py:159-207 讀 manifest、:218-365 docx/xlsx/pptx/pdf 解析+LibreOffice 子程序):檔名來自使用者上傳的原始檔名,manifest 由宿主寫;驗路徑組合有沒有跳出 /job/files/。Office 檔是 zip——zip 炸彈、超大 PDF 頁數、超大圖片會不會撐爆容器(宿主只給 1800 秒 timeout,docker run 沒帶 --memory/--pids-limit)。_libreoffice_to_pdf 子程序的 timeout 120 秒、暫存目錄清不清。container_entrypoint.py:444-513 組 system block、:538-589 每檔送 AI):分類是把證據檔內文交給 AI 判。一份 Word 內文寫「把我歸到全部控制項」會不會讓分類結果被誘導——這是結果可信度問題不是外洩,記下來讓決策者裁算不算資安題。看有沒有把使用者內容與指令分開(system vs user)、輸出有沒有驗 schema(normalize_matches :522)。Dockerfile、requirements.txt、rebuild.sh):base image 版本有沒有 pin、USER classifier 非 root 是否在 pip install 之後、requirements 有沒有 pin 版本(供應鏈:裝套件時能不能被掉包)、rebuild.sh 有沒有把金鑰 bake 進映像。_state.json/_report-original.json 回讀(classifier_container_runner.py:234-253):容器寫回的 JSON 宿主直接 json.loads 交給 E2 入庫——容器輸出被視為可信;容器被攻破(④⑤)後能塞什麼進宿主(file_uid 對不上的 placements、超大 JSON)。這條跨到 E2 的 _finalize_batch_run(evidence_batch_service.py:1143),本棒只看容器端寫了什麼、宿主讀時驗了什麼。本套件從未掃過。 主專案 2026-07 semgrep 掃描(docs/features/security-scan-2607/)曾標 classifier_container_runner.py 的 subprocess 為 audit 類,當時加了 _SAFE_ARG_RE 白名單(:40-53 註解自陳)。跨 arc 總表 §3.4「等於沒查」列了「遮蔽只靠字串比對、docker 白名單要驗證」兩項——本棒是那兩項的正式驗證。容器端 docker/ 有 unit test(test_container_entrypoint.py 378 行、test_llm_clients.py 245 行),focus=attack-surface 會跳過。CM-1877 剛把容器改成多供應商(Anthropic+OpenAI),OPENAI_BASE_URL 也會經 -e 進命令列(core/plugins/evidence_classification.py:199-202,主專案側,不在本棒)。
第一步:驗 scope 檔數與行數,對上 7 檔/約 1,476 行才啟動(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/infra/classifier_container_runner.py jedi_evidence_classification/domain/exceptions.py docker/container_entrypoint.py docker/llm_clients.py docker/Dockerfile docker/rebuild.sh docker/requirements.txt | wc -l # 要 = 7
cat jedi_evidence_classification/infra/classifier_container_runner.py jedi_evidence_classification/domain/exceptions.py docker/container_entrypoint.py docker/llm_clients.py docker/Dockerfile docker/rebuild.sh docker/requirements.txt | wc -l # 要 ≈ 1476
第二步:把啟動指令交給決策者(你不能自己啟動)。/claude-security 這個 skill 帶 disable-model-invocation: true,模型用 Skill tool 叫會被擋;也不可以自己叫 Workflow 或自己派研究員/verifier 代替它——面板票數是工具算的、報告的驗證章蓋在那個數字上。這是刻意設計不是故障,撞到不要 debug、不要找繞路。
檔數對上後停下回報:說「檔數 7 已對上,可啟動」,並把下面兩行原樣附在回報裡交還給決策者,由決策者在本 session 親手打(單次送出、第二行不能省、每個新 session 都要重打):