# FR-058 檢測工具擴充 — 全案收尾 SUMMARY

| 項目 | 內容 |
|------|------|
| 日期 | 2026-07-31（§1〜§9 初版）；2026-08-01 擴充 §10〜§14 |
| 作者 | 小弟（協調者派工，多 subagent 平行產出） |
| 狀態 | **全案結案：2026-08-01 決策者驗收通過**（T-7.4 含 T-7.5／T-7.6 皆過）。未 push、未進版 |
| Branch | `feature/FR-058`（BE / FE / evidence-agent 同名） |
| 收尾範圍 | **範圍 B：完整收尾，但不 push、不進版** |
| Notion | CM-957（FR-058 母卡）、CM-993（本次收尾追蹤卡） |
| 後續變動 | 2026-07-31 收尾後 SonarQube 重新納入為 FR-058.5（§10）；再追加 FR-058.6 主動掃描（§11）與 FR-058.7 上傳檔案掃描（§12）；範圍界定補註見 §13、上版清單見 §14 |

---

## 1. 結論

FR-058「檢測工具擴充」是 FR-056 檢測工具整合平台（v1.11.0 上線）的後續 arc，在既有平台上新增四款檢測工具（OWASP ZAP、CINC Auditor、Nmap、GCB）並補強平台層能力（憑證 / 目標主機宣告欄位、互斥憑證組別、取消執行、hosts / targets 分離）。本次為**全案收尾**，由協調者派工多個 subagent 平行處理文件與死碼清理。

收尾範圍為**範圍 B：完整收尾但不 push、不進版**。具體邊界：

- **做**：文件補齊（使用手冊 / 三頁 SPEC / DB schema 參考 / discussion.html）、前端死碼清理、階段性 commit
- **不做**：push（BE / FE 皆保留本地）、進版與 release note、STG / POC 同步、對非 DEV 環境套 migration

所有產出已 commit 在 `feature/FR-058`，push 與進版皆等決策者明示。本文 §1〜§9 為**2026-07-31 收尾時點的快照**；其後 SonarQube 重新納入為 FR-058.5（§10）、再追加 FR-058.6 主動掃描（§11）與 FR-058.7 上傳檔案掃描（§12），**2026-08-01 全案驗收通過結案**。主體各節維持四工具口徑不回溯改寫；範圍界定補註（防下一棒誤判）見 §13、發版時的上版清單見 §14。

## 2. FR-058 全案做了什麼

### 2.1 四款檢測工具

四款工具皆登錄於平台目錄表 `config.detection_tools`：

| 工具 | key | connection_type | 定位 |
|------|-----|-----------------|------|
| OWASP ZAP | `zap` | API | Web 應用弱點掃描 |
| CINC Auditor | `inspec` | SSH + WinRM | 主機組態合規檢測（Linux / Windows 雙傳輸） |
| Nmap | `nmap` | SSH | 網路服務與埠掃描 |
| GCB | `gcb` | SSH | 政府組態基準檢測（依 D7 復用 CINC 引擎） |

CINC Auditor 的目錄 key 仍為 `inspec`（歷史沿革，migration `fr058-10` 改的是顯示名稱，未改 key）。四款中只有 CINC Auditor 支援雙傳輸：Linux 走 SSH、Windows 走 WinRM。GCB 在執行引擎上復用 CINC，差別在載入的 profile content。

### 2.2 平台層新增能力

- **`requires_credentials` / `requires_target_host` 兩支宣告欄位** — 取代前端原本硬編 `connection_type === 'SSH'` 的耦合判斷。工具是否需要憑證、是否需要目標主機，改由後端目錄宣告，前端只讀旗標。原本前端靠 `connection_type` 反推行為，工具一多就會誤判（例如 API 型的 ZAP 其實也需要憑證），改成目錄宣告後，新增工具不必再動前端條件式。
- **`credential_group_schema`（JSONB）** — 宣告互斥憑證組別。前端只送組別 key，後端自行從 DB 組裝探測參數，憑證明文不經過前端。
- **取消執行（cancel）** — 執行中的檢測任務可主動中止。
- **hosts / targets 分離** — 連線目標（hosts）與掃描標的（targets）拆為兩個概念，不再混用同一組欄位。

## 3. 關鍵設計決策摘要

四條主要決策，完整推理與被排除選項見 `design.md` 與 `discussion.html`。

### D4 — ZAP 證據格式由 PDF 改為 HTML

改用 `core.htmlreport()` + `core.jsonreport()` 取出報告。原因是 `reports.generate` 只會把檔案寫到 ZAP 主機本機磁碟、呼叫端取不回來（ZAP issue #7821）。

### D7 — GCB 復用 CINC 引擎 + content 外部載入

GCB 不另起檢測引擎，直接復用 CINC Auditor。GCB profile 放在 BE repo 的 `content/detection-profiles/`，**刻意不放 agent repo** —— agent Dockerfile 末尾的 `COPY . .` 會把 content 靜默烘進 image，造成 content 更新必須重建 image 的隱性耦合。

### D9 — Nmap 由 CLI 型改為 SSH 型

兩個理由：一是容器化與 CLI 型定位本身矛盾；二是 NPSL v0.95 §3 的衍生作品條款涵蓋「專門執行本軟體並解析其結果」的軟體，GPL 式的 subprocess 防線在 NPSL 下不成立。出口是同條款尾段並未主張控制「執行使用者早已安裝的 nmap」——因此改為 SSH 型，由 agent 透過 SSH 呼叫目標主機上既有的 nmap。

### D12 — SPA 限制

ZAP 的「登入後主動掃描」對單頁式應用（SPA）會誤判 `logged_in_indicator`，導致無限重試登入，觸發 ZAP 2.17.0 的 Insights 門檻後 daemon 自我關閉，進而波及同租戶其他掃描。使用手冊已明確標註**請勿對 SPA 使用該模式**——限制範圍是該模式，不是全面禁用 ZAP。

## 4. 本次收尾產出（5 個 commit）

收尾工作包由多個 subagent 平行處理，落成 5 個 commit（BE 4 + FE 1）。

| # | Commit | Repo | 內容 |
|---|--------|------|------|
| ① | `23dedd78` | BE | 使用手冊新章（客戶面檢測工具操作指南） |
| ② | `e253a403` | BE | `database-schema.md` 補齊 Detection Tools 章節 |
| ③ | `562f4b79` | BE | discussion.html 依實作與實測結果更新 |
| ④ | `ece8c02e` | BE | SPEC 三頁更新 |
| ⑤ | `5aea161` | FE | WorkflowSetupEditor 死碼移除 |

### ① `23dedd78` — 使用手冊

新增 `docs/user-manual/detection-tools-guide.md`（432 行，客戶面操作指南），並更新 `docs/user-manual/README.md` 登記。

**獨立成檔的理由**：既有手冊偏「稽核生命週期 / 教育訓練」敘事，本篇的對象是「設定期 + 非系統使用者的 IT 管理員」，讀者輪廓與閱讀時機都不同，硬塞進既有章節會破壞原手冊的敘事線。

結構：

- §1 位置與角色分工／Agent 概念
- §2 四款工具對照
- §3 共通四步驟
- §4 各工具細節（4.1 ZAP／4.2 CINC／4.3 Nmap／4.4 GCB）
- §5 排查
- 附錄：名詞對照

### ② `e253a403` — `database-schema.md` 補齊

`docs/claude/database-schema.md` `+270` 行，新增「Domain: Detection Tools（FR-056 ~ FR-058）」章節。

六張表：

| 表 | 說明 |
|----|------|
| `config.detection_tools` | 平台目錄，無 RLS |
| `config.detection_tool_param_schemas` | 各工具掃描參數 schema |
| `config.tenant_detection_tool_configs` | RLS `tdtc_tenant_isolation` |
| `config.job_execution_detection_tools` | RLS `jedt_tenant_isolation` |
| `compliance.agent_tasks` | 無 FK |
| `compliance.detection_executions` | 無 FK |

另補：8 個 JSONB 欄位結構說明（附 DEV 實際樣本）、Cross-Module FK Reference `+8` 列（明確區分真 FK 與 soft-ref）、RLS 對照表，以及一個只有 `\d` 查得到、schema dump 看不出來的 partial index：

```
uq_jedt_job_active UNIQUE(job_execution_id) WHERE is_delete = false
```

已知缺口一併記錄：`detection_tools` 尚無 i18n（沒有對應的 `*_trans` 表）。

### ③ `562f4b79` — discussion.html 更新

討論稿由 1060 行擴為 1351 行（`+334 / −43`），依實作與實測結果回填：

- §4.2 — D12 SPA 主治
- §5.3 — CINC 架構 + 雙傳輸
- §6.4 — GCB content 介面 + Demo 2 項限制／CM-992
- §7 — 改寫（Nmap；§7.1 為 D9 理由）
- §8 — D12 決策卡
- §9 — 風險表 `+2` 列
- §11 — 全新（平台能力 11.1–11.5）

NPSL 授權段由原本單一「主張豁免」的 callout，改寫為兩張 crit callout：先陳述壞消息（§3 衍生作品條款確實涵蓋本案情境），再說明出口。這個改寫是為了避免讀者只看到結論、誤以為授權風險不存在。三張 mermaid 圖首行的 `%%{init:...}%%` 完好保留。

### ④ `ece8c02e` — SPEC 三頁更新

`docs/specs/current/` 三頁 SPEC，含 html 產物共 6 檔異動，`+1272 / −275`。

**`system-admin/tool-plugin-manage.md`**

- §1 由「兩款已上線」更正為目錄八筆（六筆 `available`、兩筆 `coming_soon`）
- UC-TPM-01 憑證合併；UC-TPM-02 改寫為「前置條件 Dialog、兩軸聯集」
- §4 / §5 / §6 / §9 / §12 的狀態閘門改以 `requires_target_host` 為鍵
- 補憑證分組面板、Dialog 動態寬度、逐區塊文案、卡片等高
- 補 response schema + `credential_group_schema` 結構表 + 取自 DEV 實庫的八列 seed 表
- 新增／改寫九條陷阱

**`project-management/project-task-edit.md`**

- 新增 §5 子節：四款工具掃描參數（取自實庫 `detection_tool_param_schemas`）、任務層 secret 加密鏈五階段、必填驗證
- §6.2 補 `secret_keys_set`
- §9.3 補 envelope 儲存
- 三條新陷阱
- 既有 JSON 範例中的內網 IP 換成 `<target host>` 佔位

**`audit-execution/my-tasks.md`**

- 功能 #14（取消執行）
- §6.1 三個檢測端點
- §11.1 新增「取消」子節（共用 `_cancel_running_execution`、兩種 409、「成功才標記 cancelled」）與「hosts / targets 分離」子節

三頁皆依 `writing-feature-specs` SOP 補檔頭變更紀錄。驗證：`render_html.py "docs/specs/current"` 全綠、敏感資訊 grep = 0、「GRC 系統」= 0。

### ⑤ `5aea161`（FE）— WorkflowSetupEditor 死碼移除

`src/views/workflow/WorkflowSetupEditor.vue` 移除死碼 `toolsMenu`（Nessus / Nmap / OWASP ZAP / Wireshark 硬編清單）與兩個 Dropdown，改為說明註解。

判定依據（DEV 實查，三條獨立佐證）：

1. 該硬編清單與 `config.detection_tools` 完全脫鉤，工具目錄改動不會反映到這裡
2. 唯一渲染條件 `actionType === 'TOOL_EXECUTION'` 已不可能成立——`public.system_menus` 中 TASK_TYPE 的 `exec_tool` 列 `enable=0`，而 `GET /system-menu/TASK_TYPE` 在 route 層即濾掉 `enable != 1`
3. DEV 全部 `workflow_templates` / `hi_workflow_templates` 的 BPMN XML 查無 `TOOL_EXECUTION`

檢測工具的真實入口是專案規劃頁：ProjectPlanningView → `menuStore.detectionToolMenu` ← `GET /detection-tools`，存 `job_type='detection_tool'`。

## 5. 同期落地（3 個 commit）

收尾期間另有三個功能面 commit 由協調者另派、同期落地，不屬收尾工作包但屬同一 arc。

| Commit | 內容 |
|--------|------|
| `f2f61e70` | 接入 TWGCB-01-011 Windows Server 2022 v1.1 完整基準 profile（708 項），**僅 DEV**，取代原本只有 2 項的 Demo profile |
| `603b8ac8` | 檢測工具卡片描述文案第二版——方向改為聚焦功能與稽核價值（migration `fr058-15`） |
| `d6cab1ee` | GCB 檢測 Profile 下拉只留完整基準一筆並縮短 label（migration `fr058-16`） |

`f2f61e70` 屬 FR-058.3 的直接延續，**與 CM-992 不衝突**：CM-992 的範圍是「content 產製（GPO 解析器）+ 後台管理機制」，本筆是「接入一份已產好的 content」，走的是既有機制，兩者不重疊。

## 6. 環境與 migration 現況

> 本節為**截至撰寫時（2026-07-31）**的狀態快照。收尾期間有平行工作線同時在動環境，此類跨 session 事實請以時點理解，不要當恆真陳述。

### 6.1 Agent 版本軸

DEV / STG / POC 三環境 agent 皆為 **0.2.18**，STG / POC 的上版（agent 更新 + content 掛載 + Demo profile 投放）稍早已完成。

因此 FR-056 時期列管的風險「工具顯示 `available` 但 agent 無對應 connector」，在 FR-058 **已解除**，不再列為未決風險。

另有一條平行工作線在修 WinRM UTF-8 錯誤，該修正完成後 agent 會 bump 到 0.2.19。本文記載為撰寫時的 0.2.18。

Agent 版本軸與 DB migration 數量軸是**兩條獨立的軸**，不要互相推論：agent 三環境齊平，不代表 migration 也齊平。

### 6.2 Migration 數量軸

| 環境 | 已套 migration | 狀態 |
|------|---------------|------|
| DEV | 16 | 領先 |
| STG | 13 | 落後 `fr058-14` / `fr058-15` / `fr058-16` |
| POC | 13 | 落後 `fr058-14` / `fr058-15` / `fr058-16` |

**DEV 領先三支是刻意的開發期狀態，不是違規。** 三支分別為 `fr058-14`（TWGCB profile 選項）、`fr058-15`（工具描述 v2）、`fr058-16`（下拉選項清理），皆在決策者審閱中尚未同步。依環境異動鐵律，STG / POC 同步屬**上版動作**，需決策者明示放行。

需要釐清的分界：收尾派工單所寫的「任何 migration 只套 DEV」是**給收尾 session 的行為指令**（收尾期間不要自己往 STG / POC 套），不是對歷史現況的描述。`fr058-1` ~ `fr058-13` 是在環境異動鐵律確立之前套進三環境的，該事實已記錄於 CLAUDE.md 與 `sql-migration` skill，**不列為待補救事項**。

### 6.3 完整 migration 清單（16 支）

`scripts/sql/` 下 FR-058 相關 migration：

| 日期前綴 | 檔名主體 | 環境 |
|----------|----------|------|
| 2026-07-30 | `fr058-1-zap-seed` | DEV / STG / POC |
| 2026-07-30 | `fr058-2-fix-zap-login-required-flags` | DEV / STG / POC |
| 2026-07-30 | `fr058-3-zap-setup-guide-spa-limitation` | DEV / STG / POC |
| 2026-07-30 | `fr058-4-zap-setup-guide-spa-shutdown-correction` | DEV / STG / POC |
| 2026-07-30 | `fr058-5-detection-tools-requires-credentials` | DEV / STG / POC |
| 2026-07-30 | `fr058-6-inspec-seed` | DEV / STG / POC |
| 2026-07-30 | `fr058-7-detection-tools-requires-target-host` | DEV / STG / POC |
| 2026-07-30 | `fr058-8-nmap-seed` | DEV / STG / POC |
| 2026-07-31 | `fr058-9-detection-tools-credential-group-schema` | DEV / STG / POC |
| 2026-07-31 | `fr058-10-inspec-rename-to-cinc` | DEV / STG / POC |
| 2026-07-31 | `fr058-11-gcb-seed` | DEV / STG / POC |
| 2026-07-31 | `fr058-12-detection-tools-description-enrich` | DEV / STG / POC |
| 2026-07-31 | `fr058-13-gcb-demo-profile-option` | DEV / STG / POC |
| 2026-07-31 | `fr058-14-twgcb-server2022-profile-option` | **僅 DEV** |
| 2026-07-31 | `fr058-15-detection-tools-description-v2` | **僅 DEV** |
| 2026-07-31 | `fr058-16-gcb-profile-option-cleanup` | **僅 DEV** |

## 7. 已知待辦

| # | 項目 | 說明 | 卡住在誰 |
|---|------|------|----------|
| 1 | BE / FE 尚未 push | 依範圍 B 設定，本次收尾不 push、不進版；本文記載的 BE 7 個 + FE 1 個 commit 皆保留在本地 `feature/FR-058` | 決策者明示 |
| 2 | STG / POC 同步 `fr058-14/15/16` | 三支 migration 僅套 DEV，同步屬上版動作 | 決策者放行 |
| 3 | CM-992 尚未開工 | GCB content 產製（GPO 解析器）+ 後台管理機制 | 排程 |
| 4 | 使用手冊 §4.4 前向相依 | 目前以「本機路徑」形式描述 GCB demo content；若 CM-992 改為 URL 形式，該節需同步更新 | 隨 CM-992 |
| 5 | discussion.html Artifact 是否重新發佈 | 討論稿已更新到 1351 行，收尾期間未自行發佈 | 決策者裁示 |

第 4 項是本次收尾唯一刻意留下的文件債：手冊寫的是當下能跑的形式，不是未來的形式。CM-992 開工時要記得回頭改這一節，否則手冊會教出一個不存在的操作路徑。

## 8. 經驗教訓

### 8.1 Notion 卡號碰撞

收尾派工單記「互斥憑證組別 = CM-986」，中段 handoff 卻記 CM-985。實查 Notion 確認 **CM-986 才是正確的**；CM-985 是「FR-058 後續優化：InSpec 報告呈現」，比 CM-986 晚 3.5 小時建立。

CM-986 卡片內文已記錄此碰撞，並裁定**不回頭修改既有 commit message**（那些 message 寫的是 `cm-985`）——改寫 git 歷史的成本高於留一條註記。

**教訓**：跨 session 傳遞的卡號要以 Notion 實查為準，不要以任何一份 handoff 的轉述為準。轉述會漂。

### 8.2 git index 競態（發生兩次，皆自行復原）

多個平行 subagent 共用同一個 git index，各自的第一次 commit 都掃入了對方已 staged 的檔案。兩次皆以 `git reset --soft HEAD~1` + `git restore --staged` 復原後，重新只 commit 自己的檔案。

**教訓**：多 agent 平行作業時，顯式 `git add <檔名>` **不足以隔離**——因為別的 agent 可能已經先 stage 了東西，`git commit` 仍會把整個 index 掃進去。正確做法是兩層：

1. commit 前先看 `git status --short`，確認有沒有他人預先 staged 的檔案
2. 改用 `git commit --only <檔名> -m "..."`，只 commit 指定檔案，繞過 index 現況

這條已回寫到後續派工單的鐵則段。

### 8.3 多 session 併行的狀態漂移

收尾 session 開工時查到的環境狀態（agent 版本、migration 數），在其工作期間被另一條平行工作線改變了。收尾方選擇**停下回報而非自行判斷**，是正確處理。

**教訓**：此類跨 session 事實應以「撰寫時點」標註（本文 §6 即照此處理），而不是寫成恆真陳述。文件裡一句沒有時間戳的「三環境皆為 X」，在多線併行的 arc 裡幾小時就會過期，且過期後看不出來已過期。

## 9. 座標索引

| 項目 | 位置 |
|------|------|
| 設計討論 | `docs/features/FR-058-2607-detection-tools-expansion/design.md` |
| 決策討論稿（HTML） | `docs/features/FR-058-2607-detection-tools-expansion/discussion.html` |
| 收尾派工單 | `docs/features/FR-058-2607-detection-tools-expansion/handoff/2026-07-31-fr058-closing-dispatch.md` |
| 工具外掛管理 SPEC | `docs/specs/current/system-admin/tool-plugin-manage.md` |
| 專案任務編輯 SPEC | `docs/specs/current/project-management/project-task-edit.md` |
| 我的任務 SPEC | `docs/specs/current/audit-execution/my-tasks.md` |
| 使用手冊 | `docs/user-manual/detection-tools-guide.md` |
| DB schema 參考 | `docs/claude/database-schema.md`（Domain: Detection Tools 段） |
| Migration | `scripts/sql/2026-07-3*-fr058-*.sql`（16 支） |
| GCB content | BE repo `content/detection-profiles/` |

### Notion 卡片

| 卡號 | 內容 | 狀態 |
|------|------|------|
| CM-957 | FR-058 母卡 | 進行中 |
| CM-986 | 互斥憑證組別（注意 §8.1 卡號碰撞） | 已落地 |
| CM-992 | GCB content 產製 + 後台管理機制 | 未開工 |
| CM-993 | 本次收尾追蹤卡 | 本文對應 |

## 10. 收尾後的範圍變動：FR-058.5 SonarQube

本節記載**收尾動作完成之後**才發生的範圍變動，不在本 SUMMARY 主體（§1〜§9）的快照範圍內。主體各節維持「四款工具、D1–D12」的收尾時點口徑，**不回頭改寫**。

### 10.1 變動內容

SonarQube **重新納入**，成為第五個子需求 **FR-058.5**。規劃期決策者曾裁示「本期不做」而將其移出本案，D10 因此成為空編號；2026-07-31 決策者裁示重新納入，決策以 D13–D16 定案。

| 決策 | 主題 |
|------|------|
| D13 | pull-snapshot 整合模式 |
| D14 | 任務參數 |
| D15 | 證據格式 |
| D16 | 認證與跨版本相容 |

**D10 編號維持 tombstone，不重用、不重排**——避免與先前已溝通過的編號錯位。

### 10.2 技術定位

SonarQube 是平台第一個「**拉取快照（pull-snapshot）**」型工具：server 端沒有任何可觸發掃描的 Web API，掃描由客戶端 CI / sonar-scanner 執行，connector 只拉取既有分析結果組報告。歸類上仍屬「① 連遠端服務 API」形態，但語意不同——連的是 API 卻不下掃描指令，只讀取既有結果。平台面零改動，工作集中在 connector 與 seed。

### 10.3 落點與對本文的影響

design.md 已更新：新增 §4.6 詳細設計、拆分表加 T-5.1〜T-5.3 三子任務、§2 決策表改為 D1–D16、§6 加對應驗收項。該份 design.md 異動落於 commit `18a01d1a`（2026-07-31 19:51），本文不重複其內容。

對本 SUMMARY 而言：§2「FR-058 全案做了什麼」的四款工具表、§3「關鍵設計決策摘要」的 D4 / D7 / D9 / D12，都是收尾時點的正確記載，不因 FR-058.5 而失效。要看完整範圍與 D1–D34 全表，請直接開 design.md。

FR-058.5 落地 commit：BE seed `7b9d831e`（T-5.1，param_schema v1）、agent connector `2d92ac4`（T-5.2，bump 0.2.21 `2aa95ec`）、FE 微調 `fef7e94`（T-5.3 程式碼部分）。UI 端到端驗收依裁示併入 FR-058.6 的 T-6.3 一輪做完（見 §11）。

## 11. FR-058.6：SonarQube 主動掃描模式（2026-07-31 深夜追加，2026-08-01 驗收通過）

### 11.1 需求與定位

決策者看到 FR-058.5 pull 模式實際畫面後指出「流程不對」——他要的是**平台真的發動一次掃描**（使用者提供 Git repo URL → agent clone 源碼、跑 sonar-scanner → 推上客戶 SonarQube server → 輪詢 → 拉結果組報告），而非只讀客戶 CI 已推上去的既有結果。**這是前提變了的新需求，不是 FR-058.5 做錯**：D13 當時排除「agent 自跑 scanner」的理由是 agent 沒有源碼，本案補上了那個輸入。決策以 **D17–D24** 定案，兩模式並存靠 `scan_mode` 參數分流（對已有成熟 CI 的客戶 pull 仍是正確答案；C# / VB.NET 因 MSBuild 架構限制**永遠只能走 pull**）。

### 11.2 落地內容

| 子任務 | 內容 | Commit |
|--------|------|--------|
| T-6.1 | BE：param_schema 升 v2（`scan_mode` select 預設 `scan`＋scan 兩欄／pull 兩欄 condition 分流，版本策略先下架 v1 再 INSERT v2）＋ `setup_guide` 全面改寫（原「本平台不會觸發掃描」在 scan 模式下變成錯的） | BE `e020a3b9`；另 scan 選項標籤精簡 `e78f1fd9`（fr058-20，param_schema v3） |
| T-6.2 | agent：Dockerfile 打包 sonar-scanner CLI（自帶 JRE，不裝 JDK，D20）＋ `sonarqube.py` scan 分支（clone → Popen 起 scanner → 解析 `report-task.txt` → 輪詢 `ce/task` → 複用 pull 的拉取報告段）；非法 `scan_mode` 明確 raise 不靜默降級；`finally` 清 tmp | agent `ca01ca1`，bump 0.2.22 `074f3b8` |
| T-6.3 | FE 微調（scan 模式主要參數識別＋寫入警語）＋兩模式合併端到端驗收 | FE `c167f26` |

### 11.3 端到端驗收（2026-08-01 上午通過）

`detection_executions` 內 sonarqube 從 0 筆變 2 筆皆 `succeeded`（pull：`project_key=guidant-ai-backend`；scan：repo `soybean-ui`），且 171 server 上實際長出 **`Guidant-AI-soybean-ui`** 專案（D21 前綴生效）。這一輪同時補完了 FR-058.5 尚欠的 UI 驗收。

### 11.4 品質門檻條件修正（驗收期間發現）

報告顯示「此專案未設定品質門檻條件」但門檻結果卻是 `OK`。**真因不是解析少剝一層**（協調者原推測被實測推翻）：SonarQube 內建 gate 條件幾乎全是 `new_*` 指標，需要**比較基準期（period）**——**專案首次分析沒有前一版可比**，API 回 `conditions: []` 且 `status` 仍給 `OK`。修正為「條件為空時整塊不輸出、不再謊稱客戶未設定；品質門檻結果一格一律保留」——agent `139156f`，bump 0.2.23 `e0d11c6`。教訓：收到「沒東西就藏起來」的顯示層要求，先驗資料層是不是我們沒讀到。

## 12. FR-058.7：SonarQube 上傳檔案掃描（2026-08-01 追加，同日實作完成並驗收通過）

### 12.1 需求與決策

FR-058.6 驗收通過後，決策者提出客戶要能**直接上傳源碼壓縮包**做檢測（不是每個客戶都有可公開存取的 Git repo）。定位為 **scan 模式的取源擴充，不是新模式**——`scan_mode` 多一個 `upload` 選項，取源之後整條掃描管線全複用。決策 **D25–D34** 定案（D32 併入 D29 ④；D33 / D34 為驗收期間追加）。關鍵定案：

- **上傳時機在任務抽屜發起執行時**，不是任務設定表單（D26）——`source_file` 是執行時輸入不進 param_schema
- **取源通道**：agent 主動 mTLS 拉取（BE 端點 `GET /api/1.0/agents/files/<uid>` 串流轉發不落地），非 BE 推檔（D25）
- **檔案生命週期**：server 端壓縮包**保留供重掃沿用＋歷史不刪**（D29，推翻討論中「終態即刪」的中間版本）；agent 端掃完即刪
- **格式與限額**：.zip / .tar / .tar.gz / .tgz；上傳 100MB／解壓後 500MB／50,000 檔，環境變數可覆寫（D27）；磁碟預留檢查（D28）＋標準庫安全解壓與解壓炸彈計量（D30）

### 12.2 落地內容

| 子任務 | 內容 | Commit |
|--------|------|--------|
| T-7.1 | BE：param_schema 升版（**實為 v4 非設計時寫的 v3**——v3 已被 fr058-20 標籤精簡佔用，fr058-21 為 v3 下架＋INSERT v4）＋限額 config＋execute sticky 參照（帶 uid 覆寫／不帶沿用／首次無檔 400）＋agent 下載端點（**可插拔 resolver 清單**——此介面被 FR-059 `1d9e43e4` append profile_ref resolver 復用，是兩案契約） | BE `fc3cbbe5`；404 修正 `fdfbb091`（查無檔案的 uid 回 404 而非 500，改用複數版 `get_upload_files()`） |
| T-7.2 | agent：mTLS 串流下載＋sha256 對帳＋磁碟檢查＋zip / tar 兩家族安全解壓＋接進既有 scan 管線 | agent `13af0b9`（bump 0.2.24 `64e41d9`）；BE 契約對齊修正 `8a444d3`（limits key 名稱＋X-Agent-Uid header，bump 0.2.25 `fd2572f`） |
| T-7.3 | FE：任務抽屜上傳區（sticky 檔案顯示／沿用／替換；首次無檔不給按執行）＋執行紀錄顯示檔名 | FE `a424511` |
| T-7.5 | upload 任務不進自動派發清單（D33，驗收發現）：自動派發不帶檔案，對 upload 任務必打中首次無檔 400 且被批次 try/except 吞掉——**PM 看到成功 toast、執行者無感的靜默失敗**，且失敗不產生執行紀錄使冪等條件永遠成立、每按一次再失敗一次。修在挑選查詢排除 `scan_mode=upload` 綁定，非派了再擋 | BE `648d3370`；FE confirm 提示 `f6a26d8` |
| T-7.6 | 檢測掃描通知加厚（D34）：內容擴為九項（專案／控制項群組／控制項／AO／任務名稱／工具名稱／掃描設定／時間／成功或失敗）＋報告檔名；**失敗也通知**（原本失敗完全不通知），收件人與成功相同；管道補齊 Discord / Telegram（三管標準）。兩坑照守：`catalog_controls.control_id` 跨 catalog 不唯一必帶 `catalog_id` 過濾、CMMC 的 AO title 全 NULL 用 title→prose→part_id fallback | BE `85d9ca9f` |

### 12.3 驗收紀錄（2026-08-01 決策者驗收通過）

T-7.4 端到端驗收通過（含 T-7.5 / T-7.6）。四個未實測項的裁示：

1. **磁碟不足模擬**——接受單元測試涵蓋，不另做環境級模擬
2. **解壓炸彈超額壓縮包**——接受單元測試涵蓋
3. **環境變數調限額**——不另實測
4. **nginx `client_max_body_size`**——**列上版必驗項**（見 §14），DEV 直連 BE 驗不到

至此 FR-058 全案（.0〜.7 ＋ 橫向前置項）結案。

## 13. 範圍界定補註（重要，防下一棒誤判）

**「任務層敏感參數已修」的範圍是 `job_execution_detection_tools.tool_params` 內 `secret: true` 欄位**（FR-058.0，envelope 加密機制在 `common/util/detection_secret_params.py`）。

**不含 `_credentials`**——那是 FR-056 既有的租戶憑證派工快照（`compliance.agent_tasks.params` 內），**at-rest 仍是明文，且仍在持續產生新資料**（非歷史遺留）。已裁示**發版時一併修**：複用 `common/util/detection_secret_params.py` 現成的 envelope（不要新造輪子），改存加密、心跳組裝時才解；會動派工路徑，**四款工具（ZAP / CINC / Nmap / GCB）都要回歸**。

看到 `_credentials` 明文時不要誤判為迴歸——第三棒協調者就曾因此誤判過一次。

## 14. 上版清單（發版時一併處理，全部需決策者當次明確指示才能碰 STG / POC）

| # | 項目 | 說明 |
|---|------|------|
| 1 | STG / POC 補 migration `fr058-14`〜`fr058-21`（8 支） | DEV 已套 21 支，STG / POC 停在 13 支。含 TWGCB profile、工具描述 v2、SonarQube seed（17）、8 支 OS profile（18）、scan 模式 v2（19）、標籤精簡 v3（20）、upload 模式 v4（21） |
| 2 | STG / POC agent `0.2.18` → 最新版 | DEV 已迭代至 0.2.25+（FR-058 範圍內），STG / POC 仍 0.2.18 |
| 3 | STG / POC 的 sonarqube `coming_soon` → `available` | 隨 migration 17 一併生效，上版時確認 |
| 4 | **`_credentials` at-rest 加密** | 見 §13——複用 `detection_secret_params.py` envelope，四款工具回歸 |
| 5 | 121 / 122 的 `AGENT_VERSION` 舊 pin | 顯示用版本字串，不影響功能，發版一併清 |
| 6 | 🔴 **nginx `client_max_body_size` 驗證（上版必做）** | 上傳檔案掃描走 FE → nginx → BE。**DEV 直連 BE 驗不到這一層**；nginx 預設 1MB，若上版環境沒調，上傳功能上去就是壞的。上版後必須實際上傳一個大於 1MB 的壓縮包驗證 |

## 15. Notion 卡最終狀態

CM-957 家族共 52 張卡，全案驗收通過後由收尾 Notion 線批次標 Done（母卡 CM-957 一併更新結案註記）。
