# 2026-07-25 資安掃描 arc 第二棒收官 — 換 session Handoff

| 項目 | 內容 |
|------|------|
| 緣由 | 資安 arc 第二棒（剩餘線）已全部執行完畢：jedi 兩輪發版、jedi-issue 憑證外洩處置、半夜重掃 + MEDIUM 分析、runner 派工 4 案完結、掃描基建三項調整。換 session 交接剩餘驗收與行政收尾 |
| Branch | BE / FE / jedi monorepo 皆 `main`，working tree 全乾淨 |
| 接手前必讀 | 本文件全讀 → 前一棒 handoff `2026-07-24-security-scan-arc-session-handoff.md`（背景）→ Notion 搜「資安」 |
| 預估時間 | 剩餘皆為 user 驗收/裁決後的零星動作，無大工程 |

## 🧭 原始需求 / WHY

User（雷門）對 BE + FE 跑三工具資安掃描（semgrep/trivy/SonarQube），目標：**HIGH 歸零、憑證外洩處置完畢、剩餘項條條有歸屬**。07-24 第一棒完成主體；本棒（07-25）接「剩餘線」：user 追加指示「**MEDIUM 也要修掉**」+「每次掃描結果要留存」。

**大圖**：這是掃描常態化進 GitLab CI 前的手動 baseline 期。CI/CD case 已建但 user 明示**先不做**。

**目前達成狀態（本棒結束時）**：
- BE trivy：**只剩 weasyprint CVE-2026-49452 一條**（上游 no-fix，風險接受）——從 arc 起點 26 條到此
- FE trivy：**0 條**（含 HIGH/MEDIUM 全清 + docs/reference 範本排除）
- FE Sonar BLOCKER/CRITICAL bug：**0 條**；semgrep FE ERROR：**0 條**
- 兩波憑證外洩（Telegram/Discord + jedi-issue wheel PAT）全處置

## §0 接手讀序

1. 🔒 先讀本文件 🧭 + §1（本棒成果）+ §3（剩餘工作），能答冷接自檢再動
2. 前一棒 handoff：`docs/features/security-scan-2607/handoff/2026-07-24-security-scan-arc-session-handoff.md`（arc 全貌 + 教訓）
3. 重掃分析：`docs/features/security-scan-2607/2026-07-25-rescan-medium-analysis.md`（MEDIUM 級逐條判定）
4. Notion 任務清單（data source id `23c346da-4cd0-8041-955e-000bb6976dd2`）搜「資安」——即時狀態以 Notion 為準

**冷接自檢 4 問**：
① 本 arc 的 MEDIUM 目標達成了嗎？（BE 剩 weasyprint 1 條 no-fix、FE 歸零——達成，「修掉 MEDIUM」的指示已完成）
② jedi 套件這棒發了幾輪版、為什麼兩輪？（第一輪 18 套件解 flask/marshmallow/dotenv/pytest 4 條 CVE；pytest 8.4.2 隨即冒新 CVE 要 9.x 被 `<9` 擋住，user 裁決「一次解決」→ 第二輪 18 套件放寬 `<10` + pytest 9.0.3。另 jedi-issue 單獨發了 0.0.16 移除 .env）
③ 掃描報告放哪、規則是什麼？（`docs/security-reports/YYYY-MM-DD/` 日期資料夾制，本機留存不入版控、僅 README force-add；禁止根目錄固定檔名覆蓋——07-24 兩版就是這樣丟的）
④ SonarQube 在哪？（**192.168.50.171:9000**，07-25 從 localhost 搬家；token 是 ~/.zshrc `SONAR_USER_TOKEN`，bash 下要 grep 抽值不能 source）

## §1 本棒成果（2026-07-25）

### jedi-* 套件（三次發版動作，全部 publish Nexus 成功）
1. **第一輪 18 套件**（monorepo `c6188f7`）：dotenv>=1.2.2 / pytest>=8.4；jedi-common 另放寬 Flask>=3.1.3 / marshmallow>=3.26.2 → BE 4 條 CVE 歸零
2. **jedi-issue 0.0.16**（`d6a8d09`）：移除打包進 wheel 的 `jedi_issue/.env`（含上古已 revoke 的 GitLab/GitHub PAT，Notion P1 case 已 Done）。正式 token 介面是 DB `ISSUE_INTEGRATE_CONFIG`（system_configs 表）config 注入，該 .env 只是被套件 `__init__.py` 的 `load_dotenv()` 意外載入——拔除零功能影響
3. **第二輪 18 套件**（`0bdadde`）：pytest pin 放寬 `<10`（user 裁決一次解決），BE pytest 升 9.0.3
- 最終版號：common 0.0.29 / auth 0.1.33 / oscal-v2 2.2.3 / issue 0.0.17 / survey 0.0.32 / flow-engine 0.0.34 等（詳 monorepo git log）

### BE 修正
- pyproject 三波：jedi 全套升 pin ×2 + pytest 9.0.3（`092c69af`）+ **Flask-Cors 6.0.0**（`d338b5ab`，升 flask 3.1.3 後 trivy 新入列 3 條 MEDIUM CVE-2024-6839/6844/6866，CORS preflight 驗證過）

### FE（runner session 完成，全部已 user 驗收標 Done）
- CM-879 依賴 CVE 第二輪：overrides +9 鍵（範圍鍵防 eslint 舊鏈拉壞）+ uuid ^11（`a848f4a`）
- CM-881 Sonar CRITICAL ×7：duplicate id ×5 改後綴 + S930 ×2 讀 source 確認後移除多傳引數（`aa01edd`）
- 另 runner 完成：preact 升版、TipTap 收斂（quill+ckeditor5 已拔）、S2486/a11y 批次、BE Sonar 安全四桶

### 掃描基建（user 三項指示全落地）
1. **報告留存**：`docs/security-reports/YYYY-MM-DD/` 日期資料夾制（先建於 repo 根、後奉命搬入 docs/），方案 A 本機留存，README force-add 入版控（BE `47e66bf6` / FE `15fdcb9`）。**gitignore 的 `!` 例外會被目錄排除蓋過，加 README 要 `git add -f`**
2. **docs/reference 排除**：FE `trivy.yaml`（`9a2b51c`）——sonar/semgrep 本來就不掃
3. **SonarQube 搬家 171:9000**（BE `00b591ad` / FE `35de2c6`）：scripts/sonar_scan.sh 首次入版控；新 server 兩專案由首掃自動建立

### Final 收官掃描（07-25 上午，三工具 ×2 repo 全跑）
結果存 `docs/security-reports/2026-07-25/`（BE/FE 各三檔）。數字：BE trivy 1（weasyprint）/ FE trivy 0 / FE semgrep ERROR 0 / FE Sonar CRITICAL bug 0 / BE Sonar 825 issues（VULN 34 全誤報或已控——判定依據在重掃分析文件 §5）/ FE Sonar 750。

## §2 本棒教訓（別重蹈）

1. **zsh `echo $resp | jq` 會弄壞 JSON**（echo 吃跳脫字元）——Sonar API 匯出一律 curl 落檔再 jq
2. **bash 下 `source ~/.zshrc` 不生效**——token 用 `grep -E '^export SONAR_USER_TOKEN=' ~/.zshrc | sed 's/.*=//; s/"//g'` 抽
3. **`poetry run dotenv -f` 參數不存在**——BE 起服務標準式：`nohup poetry run python -c "from dotenv import load_dotenv; load_dotenv('.env'); import runpy; runpy.run_path('main_app.py', run_name='__main__')" &`
4. **升版會揭新洞**：flask 3.1.0→3.1.3 讓 trivy 把 Flask-Cors 3 條 MEDIUM 掃出來；pytest 8.3.4→8.4.2 冒新 CVE 要 9.x。升版後必重掃驗證，別假設「升了就乾淨」
5. **runner 紅線含「永不動 jedi/發版」**——jedi 發版類 case 一律主 session 做，別派 runner
6. **gitignore `!` 例外 + 目錄排除**：`docs/security-reports/*` + `!.../README.md` 組合下 git add 仍被擋，force-add 才進得去

## §3 剩餘工作

### §3.1 等 user 驗收（Notion「修正待驗證」，勿代標 Done）
- CM-873 BE Sonar 品質債四桶（runner 清完 S1481/S1192，S125/S1172 整桶跳過有記錄）
- CM-874 FE Sonar 品質債（a11y 批次等）
- CM-876 TipTap 收斂（公告/兩回饋表單/摘要報告四處手測）

### §3.2 push 狀態（⚠️ 待確認）
本 session 尾聲觀測到**三 repo 的本地 `origin/main` ref 已等於 HEAD**——Claude 無 GitLab 憑證（fetch/push 都會 `could not read Username`），所以極可能是 **user 已自行 push 過**。下一棒 pre-flight 跑 `git status -sb` 確認；若顯示 ahead 則仍未推，push 永遠等 user 明示。

### §3.3 部署對齊（user/運維執行，Claude 提醒即可）
- classify docker image 各主機 rebuild（Dockerfile 加了 USER）
- 分類器 job 目錄 /tmp→~/.cm-jobs，部署 `-v` 掛載同步
- **部署機 `poetry update`** 才吃得到 jedi 新版（兩輪發版 + Flask-Cors/pytest 升版）
- Nexus 舊版 jedi-issue wheel（≤0.0.15 含已 revoke token）是否下架——user 說 token 已死不急

### §3.4 未來線
- CI/CD case（Notion 有完整架構）——user 明示先不做，等環境準備
- 掃描報告留存屆時改 GitLab CI artifact（README 已預告）
- BE pytest 環境修復（126 collection errors）——既有問題，值得開 case 未開

## §4 開工順位

1. 跑 §6 pre-flight
2. 等 user 指示（驗收結果處理 / 新任務）——**本 arc 無 pending 工程，不要自己找事做**
3. 若 user 要再掃：照 `docs/security-reports/README.md` 的指令備忘，輸出進當天日期資料夾

## §5 該讀的檔案

- `docs/features/security-scan-2607/2026-07-25-rescan-medium-analysis.md` — MEDIUM 逐條判定（semgrep 誤報依據 / Sonar VULN 34 條判定 / CSRF 設計決策）
- `docs/security-reports/README.md`（BE，政策 owner）— 留存慣例 + 各工具掃描指令
- `docs/claude/notion-bug-loop-runner.md` — runner 手冊（紅線清單）
- memory `reference_security_scan_tooling` — SonarQube 座標 / token / 留存慣例

## §6 Pre-flight（接手必跑）

```bash
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
git log --oneline -6   # 應見 00b591ad / 47e66bf6 / b26fcef7 / d338b5ab / 092c69af / 672413a0
git status -sb          # main 乾淨；若顯示 ahead N 代表未 push
ls docs/security-reports/2026-07-25/   # 應有 trivy/semgrep/sonar 三檔
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe
git log --oneline -4   # 應見 35de2c6 / 15fdcb9 / 9a2b51c / 8295248
cd ~/Projects/Jedicogy/module/jedi-python-package
git log --oneline -3   # 應見 0bdadde / d6a8d09 / c6188f7
# BE 起服務（改過 service/依賴後）：
# cd BE repo && 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 Verify 本棒確實 close

```bash
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
jq -r '.Results[] | (.Vulnerabilities // [])[] | "\(.Severity) \(.PkgName)"' docs/security-reports/2026-07-25/trivy-backend.json
# 應只有: MEDIUM weasyprint
jq '[.Results[].Vulnerabilities // [] | .[]] | length' ~/Projects/Billows/Audit-Manager/compliance-manager-fe/docs/security-reports/2026-07-25/trivy-frontend.json
# 應為: 0
python -c "import pytest, flask; print(pytest.__version__)"   # 9.0.3
ls .venv/lib/python3.11/site-packages/jedi_issue/ | grep -c .env   # 0
```

## §8 行為規範重要提醒

- 不切 branch / 顯式 git add 禁 -am / push 等 user 明示（§3.2 先確認狀態）
- BE 起服務 = main_app.py（8000）+ load_dotenv 包裝（§2.3 標準式）；kill -9 清殘留
- jedi-* 異動需 user 明示；發版絕不自動推 Nexus；runner 永不碰 jedi
- 掃描輸出進 `docs/security-reports/YYYY-MM-DD/`，禁根目錄固定檔名
- 大檔（trivy json 27MB / sonar issues 2.7MB）一律 jq，勿整檔 Read
- user 說「先不用/等等」就停手

## §9 收尾流程

本 arc 主體 + 剩餘線皆已收。CM-873/874/876 user 驗過標 Done 即全案終結；屆時若 user 下令「總結」，走 closing-and-handoff 的完整收尾（SUMMARY + memory + spec 盤點——資安修正無頁面行為變更，spec 更新預期不適用）。

## §10 不在本期 scope

- CI/CD 實作（user 明示擱置）
- FE Dockerfile nginx USER（等部署決策）
- BE pytest 環境修復（126 collection errors）
- git history rewrite（憑證已全 revoke，不值）
- FE `App.vue:11` toast v-html（判低風險留檔，重掃分析 §4 有記錄——若日後 BE 訊息直塞 toast 需先 sanitize）

## §11 本棒 commits（07-25，時序）

**BE**：`672413a0`(jedi-issue 0.0.16) `092c69af`(pytest 9.0.3+jedi 二輪) `d338b5ab`(Flask-Cors 6.0.0) `b26fcef7`(留存 README) `47e66bf6`(搬 docs/) `00b591ad`(Sonar 搬家) + `969983f0`(重掃分析) `66d160a9`(runner handoff) + runner 的 loop log/清理串
**FE**：`a848f4a`(CM-879) `aa01edd`(CM-881) `8295248`(CM-882-884 回饋附件) `9a2b51c`(trivy.yaml) `15fdcb9`(搬 docs/) `35de2c6`(Sonar 搬家) + runner 的 TipTap/S2486 串
**jedi monorepo**：`c6188f7`(一輪) `d6a8d09`(issue .env) `0bdadde`(二輪)

## §12 給 fresh session 的超短 prompt

```
請讀 docs/features/security-scan-2607/handoff/2026-07-25-security-arc-final-session-handoff.md，
先答 §0 冷接自檢 4 問（不跳過 WHY），再跑 §6 pre-flight + §7 verify。
本 arc 工程已全部完成，你的工作是待命：等我對 CM-873/874/876 的驗收結果、或新指示。
注意：push 狀態見 §3.2 先確認；BE 起服務用 §2.3 的 load_dotenv 標準式（port 8000）。
```
