Runner Session 交接文件(2026-07-25,資安掃描 arc 第三棒 runner)

給下一棒 runner 的冷接文件。 本文件自包含,看完即可開工,不需回頭翻對話。

上一棒:2026-07-25-security-arc-final-session-handoff.md(同目錄,資安 arc 第二棒收官)


🧭 我是誰、這棒在做什麼

角色定位:任務執行 runner。 user 指派 Notion case 編號 → 我照 notion-case-work skill 流程做掉 → 回填 Notion 標「修正待驗證」+ 白話補充。

不是 arc 主導、不是分析 session。user 說「執行 CM-xxx」我才動,做完停下等下一個指令。

本棒處理 6 條 case(CM-886~889 / 893 / 新開 894)+ 1 條 user 臨時指派的 UI 一致性修正。


§0 開工前必讀(硬 gate)

接手後不要自動開始做任何事。 等 user 指派 case 編號。

若 user 直接說「繼續」而沒給編號 → 回問要處理哪一條,不要自己從 Notion 挑。

冷接自檢題(答不出來先讀完本文件)

  1. 這棒的 commit 已經 push 了嗎?→ 已 push(user 於 2026-07-25 自行 push,兩 repo 皆同步)
  2. BE 需要重啟嗎?→ 需要,且我沒有重啟(見 §5 風險項)
  3. 為什麼 BE git log 有些 commit 不是我做的?→ 有另一個 session 平行在跑同一個資安 arc(見 §3 ⚠️)
  4. CM-888 的修正驗證到什麼程度?→ 只驗語法,GitLab 實際行為未跑(見 §5)

§1 本棒完成的 case(全部已 push)

Case 範圍 狀態 commit
CM-886 FE 修正待驗證 c8aa7bc 480090d c634f32 9c59c8b
CM-887 FE 修正待驗證 7b2cd96
CM-888 BE 修正待驗證 ecffff39
CM-889 BE+FE 修正待驗證 f972d92d / a6a895b
CM-893 BE 修正待驗證 456f1a1d + 文件 747bd35c
CM-894 Not started(新開,未動工)
(無 case) FE 已 commit 40e8d4c

Notion 六條都已回填白話補充。CM-894 是本棒開的新 case、沒做,內容已寫到可直接動工的程度。

各 case 一句話

  • CM-886:Sonar a11y 49 條(input label 37 + iframe title 12),29 個 vue 檔全清
  • CM-887:BaseService.js 五方法收斂到 settleEnvelope helper,消 S3403/S4822
  • CM-888唯一會動資料的修正——GitLab 附件刪除從「全刪」改成「只刪指定檔案」
  • CM-889:semgrep WARNING 33 條加 nosemgrep 註記,BE/FE 雙邊歸零
  • CM-893:摘要報告 PDF 拔 Google Fonts 外連,字型改 Noto Sans CJK TC
  • 40e8d4c/project/task-manage 狀態篩選 CSS 對齊全站慣例(user 臨時指派,無 case)

§2 三個「比 case 描述更嚴重 / 不同」的發現

這三項是本棒實際查證後推翻或補強了 case 原本的假設,下一棒若碰到相關區域要知道

2-1 CM-888 是真 bug,且原作者的「錯」有原因

delete_gitlab_feedback_attachmentfile_uids 卻立刻用「該 issue 全部附件」覆寫 → 刪一個附件會全刪 GitLab 端。

根因不是隨手寫錯:GitLab 附件 uid 是 note body 裡 /uploads/<hex>/ 的雜湊,local 附件 uid 是 DB uuid,兩者不同 id 空間,拿 local uid 去比對交集恆空、什麼都刪不掉。推測原作者因此改成全刪繞過。

修法:改用檔名比對定位(同名檔案依出現順序 1:1 配對),對不到就回 False 不再退化成全刪。caller 配合改為「先查檔名再刪 local」——順序不可對調,local mapping 刪掉後就查不到檔名了。

2-2 CM-893 揭露的問題比 case 假設的更實際

case 假設是「內網抓不到只剩等待成本」。實查發現:部署環境(Debian + fonts-noto-cjk)根本沒有 Noto Sans TC 這個家族名——那是 Google Fonts 的名稱,容器內 fc-match 'Noto Sans TC' 掉到 DejaVu Sans(無中文字符)。

中文不會變豆腐字(WeasyPrint 有字符級 fallback),但實測會撿到 Noto Sans CJK JP,也就是用日文漢字字形排繁中報告。故第一順位改指定 Noto Sans CJK TC

已確認 DEV 主機字型 OK(user 實跑 fc-matchNotoSansCJK-Regular.ttc: "Noto Sans CJK TC")。

2-3 nosemgrep 註記格式有坑(下次會再踩)

nosemgrep: 必須在 finding 行的行尾、或緊鄰的前一行。寫成「nosemgrep 獨立一行 + 中文說明換行」會把 nosemgrep 推離錨點,BE 剩 13 條、FE 剩 1 條沒消掉

正確格式:說明放更前一行,# nosemgrep: <rule> 放行尾。多行語句(logger.warning( / make_response()錨在起始行


§3 環境與協作狀態

Git(兩 repo 皆已 push、working tree 乾淨)

BE  ~/Projects/Billows/Audit-Manager/compliance-manager-be   main  已同步
FE  ~/Projects/Billows/Audit-Manager/compliance-manager-fe   main  已同步

BE 有若干 untracked(docs/交付文件/security-audit-report-2026-07-17.html 等)——本 session 開始前就存在,不是本棒產物,不要順手清。

⚠️ 有另一個 session 平行在跑同一個 arc

BE git log 裡這些不是本棒做的,是平行 session 的產物:

commit 時間 內容
9de55a8e 12:23 semgrep avoid-sqlalchemy-text ERROR 歸零
1ac436a5 12:41 SonarQube hotspots 逐條審查
d245cb72 12:46 SonarQube Quality Gate new-code 策略
e52ea26b 12:51 weasyprint 升 69.0(CM-892 CVE)
e81c8c05 13:09 摘要報告 img src 限縮 data: URI(CM-892)

時間戳與本棒的 ecffff39(12:18) / f972d92d(12:58) / 456f1a1d(13:10) 交錯

對下一棒的影響

  • Notion 同一個 DB 可能有另一棒正在寫 → 開新 case 前務必先搜尋,避免撞號或重複開案
  • api/project_summary_report/ 這個目錄兩棒都動過(本棒動 template 字型、平行棒動 route 的 bleach 白名單)→ 動之前先 git log 看最新狀態
  • 不要假設 git log 上的 commit 都是自己人做的

BE 服務狀態

本棒沒有啟動也沒有重啟 BE。session 中觀察到 PID 33978 在跑(port 8000,啟動時間 13:05),是 user 先前自己起的,跑的是舊 code。

CLAUDE.md 記載 2026-07-22 起 BE 重啟由 Claude 負責,但因該 process 非我所起、user 可能正在使用,我問過後 user 未回覆是否重啟 → 維持未重啟


§5 風險與未驗證項(最重要,優先讀)

🔴 CM-888 的 GitLab 行為未實跑驗證

這是本棒唯一「改了會動資料、但只驗語法」的項目。

  • 已驗:Python 語法檢查通過、call site 全數更新(grep 確認無殘留舊簽名)
  • 未驗:實際刪 GitLab 附件的行為——需要有掛 GitLab 的回饋資料才測得到
  • 若 GitLab 設定當前沒開(_is_gitlab_enable() 為 false),這條路徑根本不會執行

複測步驟已寫在 Notion CM-888 頁。下一棒若 user 回報「刪附件有問題」,優先看這裡。

🟡 BE 需重啟才生效

CM-888 改的是 service 層,CM-893 改的是 template(理論上隨請求讀取、不需重啟,但既然同輪有 service 改動,一起重啟最保險)。

目前跑的 BE 是舊 code。

🟡 STG / POC 主機字型未確認

CM-893 拔掉 Google Fonts 外連後,「主機有中文字型」從隱藏的保險變成明確前提

  • DEV auditmanager-dev-01:✅ 已確認(Noto Sans CJK TC 正常解析)
  • STG / POC:未確認

上線前各跑一次:

fc-match 'Noto Sans CJK TC'   # 要回 NotoSansCJK,不是 DejaVu

若某台沒裝,這個 commit 在那台會讓中文從 PDF 整段消失(實測:完全無中文字型時中文不是豆腐字,是不見)。

🟡 DEV 主機有既有的 python3.11 套件衝突

auditmanager-dev-01 跑任何 apt-get install 都會報 libpython3.11-stdlib 版本不一致。與本棒工作無關(字型套件本身已是最新版)。

⚠️ 不要跑 apt --fix-broken install——會動系統 python,該機正在跑 BE。要處理需另案評估。

已寫進 docs/claude/host-dependencies.md


§6 本棒新增的文件

docs/claude/host-dependencies.md(新檔,commit 747bd35c

主機層依賴(部署前提)——記錄「poetry install 裝不到、但缺了功能會壞」的 OS 層套件:

  • 中文字型 fonts-noto-cjk(摘要報告 PDF)
  • LibreOffice(SSP 匯出 docx→pdf/odt)
  • 新機一行檢查指令 + 各主機確認狀況對照表
  • DEV 主機的 apt 陷阱警語

CLAUDE.md 的 Environment Variables 段已加 pointer + LIBREOFFICE_CMD 選用變數。

下一棒若動到 PDF / 匯出相關,先讀這份。 CM-894 完成後需回填多語系字型段。


§7 下一棒可能接到的工作

已備好、可直接動工

CM-894(本棒新開,Not started):PDF 匯出多語系字型缺漏。

  • 高棉文 408 字全豆腐、阿姆哈拉/僧伽羅內容被畫成同一個高棉字符(字碼已失真)
  • 緬甸文落到非標準的 Zawgyi 字型
  • 阿拉伯/希伯來 RTL 字序、婆羅米系 shaping 標為待人眼複核(pdfplumber 取的是內部儲存順序,不必然等於視覺順序——不要當成確定的 bug)
  • 動工前必須先問 user/PM「產品實際要支援哪些語系」 ——這決定工作量是「加一行註記關案」還是「裝全套 Noto + 處理 bidi/shaping」
  • ⚠️ 診斷資料產自 macOS 本機,部署主機(Debian)表現會不同且可能更差,需在部署環境重測才能定案

case 內已含完整診斷指令(可直接重跑)與逐語系實測對照表。

待 user 裁決

  • 是否重啟 BE(見 §3)
  • CM-894 的語系範圍(見上)
  • DEV 主機 python3.11 套件衝突是否另開 case 處理

§8 工作慣例備忘(本棒實際遵守的)

  • commit 可自行做,push 永遠等 user 明示(本棒全程未自行 push,user 於收尾時自行 push)
  • 顯式 git add 逐檔列名,禁用 -A / -am
  • 不切 branch,一律在 user 當下的 branch 工作
  • 收尾動作等 user 下令——fix 完只給一句話 status + 手測 checklist
  • Notion 作業人員填 小弟(Claude 做的),來源 雷門,專案 CM
  • 掃描輸出丟 /private/tmp不寫入 docs/security-reports/ 日期資料夾
  • 暫存腳本用完即刪,不在版控檔留憑證

本棒的驗證紀律(建議延續)

  • FE 每批改動都跑 npm run build:DEV(指令是 build:DEV 不是 build
  • 大量機械性修改後逐檔比對來源清單確認零遺漏(CM-886 用此法確認 29 檔全涵蓋)
  • 只加註解的改動用 git diff 逐行比對,確認每個刪除行都以「原內容+註記」形式回來(CM-889 用此法確認零邏輯異動)
  • 引用 i18n key 前先 grep 確認存在(本棒有兩個想用的 key 實際不存在,先驗才沒出包)
  • 跨環境問題在部署環境模擬容器驗,不能只驗 macOS(CM-893 用 docker python:3.9-slim + fonts-noto-cjk)

§9 給下一棒的 prompt

見同目錄 2026-07-25-runner-session-prompt.md,或直接用本文件開頭那段。