2026-07-25 資安 arc 全收官 + Sonar 存量清理 arc 開局 — 換 session Handoff

CLOSED — 2026-07-25 同日收官:清理 arc 全案完成(CM-895~905 全 Done、兩 repo open 1,440→0、QG 雙綠),已進版 v1.10.1(tag 已推)。收官全貌見同目錄 2026-07-25-v1.10.1-sonar-cleanup-arc-SUMMARY.md。本文件僅供歷史參考。

項目 內容
緣由 資安 arc(2607)全案終結:全部 case Done、三工具帳面全零、Quality Gate 雙綠。同日 user(雷門)依 PM 要求開啟新 arc「Sonar 存量 code smell 清理」,已完成裁決 + accept 標記 + case 群開案,實作交下一棒
Branch BE / FE 皆 main,working tree 乾淨(BE 的 untracked 為既有已知項,與本 arc 無關)
本棒角色 任務分析首腦(只派工不實作):主 session 派 subagent + user 的外部 loop runner 並行
接手前必讀 本文件全讀 → 前一棒 handoff 2026-07-25-security-arc-final-session-handoff.md(資安 arc 背景)→ Notion 搜「Sonar 存量清理」

🧭 原始需求 / WHY

資安 arc(已終結):三工具(trivy/semgrep/SonarQube)掃描 BE+FE,HIGH/MEDIUM 歸零、憑證處置、剩餘項條條有歸屬——目標是掃描流程進 GitLab CI 前的乾淨基線。本日達成:全零 + 存證

新 arc(Sonar 存量清理,本 handoff 的主交接物):user 進 SonarQube 看到大量程式建議,PM 要求盡量清掉。2026-07-25 雷門裁決三級處置:

  • 一級(機械性 ~700 條)→ 真清,開 case 群給外部 runner
  • 二級拆兩刀:S8786 regex ReDoS ×44 + S5754 裸 except ×11 + S5886 回傳型別 ×18(73 條真修,需查證紀律);S1172 ×80 / S107 ×37 / S7721 ×34(154 條標 accept 緩做,已標完)
  • 三級(S3776 認知複雜度 ×236 + S3516 stub ×8)→ 不做,「本來就是這樣」,已標 accept

冷接自檢 4 問(答得出再動工): ① 三級 S3776 為什麼不修?(既有裁決禁區:重構 200+ 函式風險高於收益;S3516 是 FR-038 2A 刻意 stub,改真邏輯會出事、等 2B) ② 二級 154 條標 accept 的理由?(動函式簽名/作用域、無測試護航風險高——裁決緩做,不是永不做) ③ 「派 runner」是什麼意思?(user 的外部 loop runner session 接 Notion case 執行;主 session 只開 case 不 spawn subagent 做 runner 類 case——memory feedback_runner_means_external_loop_runner) ④ Quality Gate 現在是什麼策略?(Guidant-NewCode:只看 new code 零新增,存量不擋版;scanner 要帶 -Dsonar.projectVersion 讓 baseline 隨進版重置——見 docs/features/security-scan-2607/sonar-quality-gate-setup.md

§1 資安 arc 終結狀態(不需再動,僅存證)

最終帳面(2026-07-25 第二輪基線掃描 + 尾巴收零後): | 指標 | BE | FE | |------|-----|-----| | trivy vuln | 0(weasyprint 升 69.0 收掉最後一條) | 0 | | semgrep ERROR+WARNING | 0 | 0 | | Sonar OPEN VULN / hotspots | 0 / 0 | 0 / 0 | | Sonar OPEN BUG | 0 | 0 | | Quality Gate(Guidant-NewCode) | PASSED | PASSED |

Notion case 全 Done:CM-873/874/876(前棒)+ CM-886~893(本日)。基線報告存 docs/security-reports/2026-07-25/(早上收官 6 檔 + 下午 -final 6 檔,同日兩輪並存)。

本日 BE commits(時序)ecffff39(CM-888 GitLab 附件真 bug) 9de55a8e(semgrep ERROR 消音) 1ac436a5(hotspots 審查) d245cb72(Quality Gate) e52ea26b(weasyprint 69.0) f972d92d(semgrep WARNING 消音) e81c8c05(CM-892 img src 限縮) 456f1a1d(CM-893 拔 Google Fonts+字型修正) 747bd35c(主機依賴文件) 6579e2b8(runner 自寫交接) 62a0c465(尾巴收零小修) FE commits7b2cd96(CM-887 BaseService) c8aa7bc/480090d/c634f32/9c59c8b(CM-886 a11y×4) a6a895b(semgrep 消音) 40e8d4c(runner 樣式) 5785c58(S6638)

重要事實

  • weasyprint「no-fix」是 GHSA patched 欄位缺漏誤導,69.0 實際已修(論證文件 2026-07-25-weasyprint-cve-2026-49452-resolution.md
  • SonarQube 26.7 MQR 模式下 hotspots 規則已併入一般 issues,hotspots 恆 0(2026-07-25-hotspots-review.md
  • CM-888 挖出真 bug:GitLab 附件刪除原為「全刪」,已改檔名定位
  • CM-893 挖出字型陷阱:Noto Sans TC 在部署主機不存在,會 fallback 日文字型——已改 Noto Sans CJK TC(主機層依賴見 docs/claude/host-dependencies.md
  • 未 push:BE/FE 本日全部 commits 未推,push 等 user 明示
  • 部署對齊未做(user/運維側):部署機 poetry update(weasyprint 69.0 + 先前 jedi 升版)、classify image rebuild、字型 fonts-noto-cjk 確認——見前棒 handoff §3.3 + host-dependencies.md

§2 新 arc 已完成的地基

  1. Accept 批次標記完畢(395 條,零失敗):三級 S3776×236 + S3516×8、二級緩做組 S1172×80 + S107×37 + S7721×34。全附裁決 comment。效果:open CODE_SMELL BE 776→450、FE 664→595
  2. 清理 case 群已開(Notion,Not started)——case no 以 Notion 實查為準(開案順序①~⑤):
    • ① FE S6853 label 殘量 ~120:手法同 CM-886(已 Done 可參照),runner 接
    • ② 註解碼 BE S125 ×66 + FE ×65:純死碼刪 / 含意圖改寫說明 / FR-038 stub 註解不動,runner 接
    • ③ BE logging 桶 S3457 ×34 + S8572 ×30 + S1192 殘量 ~40:等價改寫,runner 接
    • ④ FE 語法/樣式桶 ~200:CSS 對比度 ×48(先對 guidant-design-system,勿自創色)+ 棄用語法 + 一行級改寫,runner 接
    • ⑤ BE 語意桶 73 條(S8786 regex ReDoS / S5754 裸 except / S5886 回傳型別)需逐條查證,主 session 派 subagent 做,非 runner 機械活
  3. 另注意:runner 曾自行開 CM-894(見 BE commit 6579e2b8 訊息「CM-894 開案待動工」)——接手時 Notion 查一下該條內容避免與 case 群重工

§3 下一棒的工作

  1. 跑 §6 pre-flight 確認狀態
  2. 派工順序建議:⑤ 語意桶派 subagent(S8786 優先,有真實 ReDoS 面);①~④ 等 user 的外部 runner 自取(主 session 不要 spawn subagent 做這四條——見冷接自檢③)
  3. runner 產出的驗收:user 驗過標 Done;主 session 可 diff 抽查品質(本棒抽查零返工,維持此標準)
  4. 全部清完後:重掃一輪看殘量長尾,殘量要嘛再收一輪要嘛 accept,由 user 裁決
  5. 不在 scope:CI/CD 實作(user 明示等環境)、S3776/S3516 重構、已 accept 的 154 條

§4 帳面數字速查(清理 arc 起點)

BE FE
open CODE_SMELL(accept 後) 450 595
其中 case 群涵蓋 ~140(②③⑤) ~320(①②④)
清完預估殘量 <100 <250

§5 該讀的檔案

  • docs/features/security-scan-2607/sonar-quality-gate-setup.md — gate 條件/CI 接法/projectVersion 注意
  • docs/features/security-scan-2607/2026-07-25-hotspots-review.md — hotspots 0 條的原因
  • docs/features/security-scan-2607/2026-07-25-weasyprint-cve-2026-49452-resolution.md — not-affected 論證
  • docs/claude/host-dependencies.md — 部署主機字型/LibreOffice 前提
  • docs/claude/notion-bug-loop-runner.md — runner 紅線
  • memory:feedback_runner_means_external_loop_runnerreference_security_scan_tooling

§6 Pre-flight(接手必跑)

cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
git log --oneline -3   # 應見 62a0c465 / 6579e2b8 / 747bd35c(之後 runner 可能再疊 commits,屬正常)
git status -sb          # main;untracked 僅既有已知項
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe
git log --oneline -2   # 應見 5785c58 / 40e8d4c(runner 可能再疊)
# Sonar 帳面(token 用 grep 抽,勿 source zshrc;API 回應落檔再 jq,勿 echo 管線)
TOKEN=$(grep -E '^export SONAR_USER_TOKEN=' ~/.zshrc | sed 's/.*=//; s/"//g')
curl -su "$TOKEN:" 'http://192.168.50.171:9000/api/qualitygates/project_status?projectKey=guidant-ai-backend' -o /tmp/qg-be.json && jq -r .projectStatus.status /tmp/qg-be.json   # OK
curl -su "$TOKEN:" 'http://192.168.50.171:9000/api/qualitygates/project_status?projectKey=guidant-ai-fe' -o /tmp/qg-fe.json && jq -r .projectStatus.status /tmp/qg-fe.json   # OK
# BE 服務(若需):目前 pid 48289 在 8000;重啟標準式:
# lsof -ti :8000 | xargs -r kill -9; nohup poetry run python -c "from dotenv import load_dotenv; load_dotenv('.env'); import runpy; runpy.run_path('main_app.py', run_name='__main__')" > /dev/null 2>&1 &
# curl -s -X POST localhost:8000/api/1.0/login -H 'Content-Type: application/json' -d '{}'  # 400=正常

§7 行為規範重要提醒

  • 不切 branch / 顯式 git add 禁 -am / push 永遠等 user 明示(本日兩 repo 全部未推)
  • 「派 runner」= 只開 Notion case;主 session 派工 = spawn subagent。兩者不可混
  • Sonar 標記類操作(accept/falsepositive)走 server API,附 comment 註明裁決出處
  • 掃描輸出進 docs/security-reports/YYYY-MM-DD/(正式存證)或 /private/tmp(過程驗證),禁根目錄
  • 大檔一律 jq;Sonar API curl 落檔再 jq
  • BE 改 service 後重啟(kill -9 + load_dotenv 標準式);user 說「先不用/等等」就停手

§8 給 fresh session 的超短 prompt

請讀 docs/features/security-scan-2607/handoff/2026-07-25-security-arc-close-and-smell-cleanup-handoff.md,
先答 §0 冷接自檢 4 問(不跳過 WHY),再跑 §6 pre-flight。
資安 arc 已全案終結;你的工作是 Sonar 存量清理 arc:
⑤ BE 語意桶(S8786/S5754/S5886)派 subagent 做,①~④ 是外部 runner 的 case 不要碰。
push 永遠等我明示。