# FR-058 第二批（InSpec/CINC → GCB）實作 session 派工交接（2026-07-30）

| 項目 | 內容 |
|------|------|
| 緣由 | FR-058 分批出貨。第一批（ID 解耦 + 任務層敏感參數 + ZAP，CM-958〜970）實作已完成、agent 已 bump 0.2.12 部署 DEV 中。本文是**第二批（InSpec/CINC → GCB）實作 session 的派工單** |
| Branch | BE：`feature/FR-058`（不切 branch）；evidence-agent：當下 branch（HEAD `c775fc8` bump 0.2.12） |
| **本棒角色** | **實作者。** 完成 FR-058.2（InSpec/CINC connector）與 FR-058.3（GCB），依 T-2.1〜T-2.4 + T-3.1〜T-3.3 順序做，每個子任務完成即 commit + 回寫 Notion 卡 |
| 接手前必讀 | 本文全份 + design.md §2（D5/D6/D7/D8）+ §4.3〜§4.4（InSpec 與 GCB 詳細設計）+ §5.5〜§5.6（子任務表） |
| 上游文件 | `docs/features/FR-058-2607-detection-tools-expansion/handoff/2026-07-30-fr058-planning-complete-handoff.md`（全案大圖與需求演變；本文已摘實作所需部分，卡住時才回頭讀） |

## §0 讀序

1. 本文 §1（範圍）→ §2（硬性決策約束，**逐條遵守**）→ §3（第一批帶來的新事實）
2. `design.md` §4.3（FR-058.2 InSpec/CINC 詳細設計）+ §4.4（FR-058.3 GCB 詳細設計）全讀
3. `design.md` §2 的 D5 / D6 / D7 / D8 定案原文（本文 §2 是摘要，原文含被排除方案與理由）
4. §4 的範本檔案——動手寫每個子任務前先開對應範本照形狀寫


---

## §1 任務範圍與 Notion 卡

### 1.1 範圍

第二批 = **FR-058.2（InSpec / CINC Auditor）→ FR-058.3（GCB）**，共 7 個子任務，序列執行（.3 依賴 .2 的 connector，不可對調）。

| # | 子任務 | Repo | 一句話 |
|---|--------|------|--------|
| T-2.1 | seed InSpec/CINC（connection_type 涵蓋 SSH 與 WinRM）+ config_field_schema（雙 transport 憑證，含條件顯示）+ param_schema + setup_guide（含 CINC 授權說明與 WinRM 啟用前提）；三環境套用 | BE | migration |
| T-2.2 | Dockerfile 加入 CINC Auditor + `inspec.py` 骨架（雙 transport 連線參數解析）+ `probe()`（連線 / 認證 / CINC 可執行三段檢查與錯誤分類） | evidence-agent | connector 骨架 |
| T-2.3 | `run()` 執行 profile + `--reporter json` 統一解析 + 逐台多檔證據 + `host_failures` 逐台失敗回報 + `cancel_event` / timeout | evidence-agent | connector 主體 |
| T-2.4 | 結案 Notion CM-953（本 FR 吸收，於 T-2.3 完成時一併標記） | Notion | 結案 |
| T-3.1 | seed GCB 條目（引擎指向 .2 的 CINC，Windows 與 Linux 共用）+ param_schema（含 content 來源指定欄位）+ setup_guide；三環境套用 | BE | migration |
| T-3.2 | content 外部載入接口（profile 由外部提供給 connector，不硬編、不隨 agent image 發布） | evidence-agent | 接口 |
| T-3.3 | 一份 Windows 最小 Demo profile（必須落在 `HKLM\Software\Policies` 正規政策區）——端到端鏈路的驗收留到全案最後（見 §5），本子任務交付 profile 本體與載入驗證 | evidence-agent | Demo content |

### 1.2 Notion 卡對照（完成後逐卡回寫，母案 CM-957：`https://app.notion.com/p/3ad346da4cd081859d2ed8b21ca2697c`）

| 卡 | 對應 | Notion URL |
|----|------|-----------|
| **CM-971**（FR-058.2 母卡） | InSpec / CINC Auditor | `https://app.notion.com/p/3ad346da4cd0811faa85fd15a38df059` |
| CM-972 | T-2.1 | 從母卡 CM-971 子卡清單進入 |
| CM-973 | T-2.2 | 同上 |
| CM-974 | T-2.3 | 同上 |
| CM-975 | T-2.4（結案 CM-953） | 同上 |
| **CM-976**（FR-058.3 母卡） | GCB | `https://app.notion.com/p/3ad346da4cd08120b9f1cf9b1f976847` |
| CM-977 | T-3.1 | 從母卡 CM-976 子卡清單進入 |
| CM-978 | T-3.2 | 同上 |
| CM-979 | T-3.3 | 同上 |

**CM-953**（`https://app.notion.com/p/3ac346da4cd0819390d2c5b85c754bf8`，「FR-057 後續：異質 OS 環境的檢測支援方案」）：規劃階段已先標 Done 並指向 CM-971；T-2.4 時**確認其結案敘述指向實際落地的 commit 與 connector**，補上一段白話結案說明（InSpec/CINC 即該案選項 2 的具體答案，「一任務一工具、多任務處理異質環境」模型沿用未改）。


---

## §2 硬性決策約束（design.md §2 已拍板，實作不得偏離）

逐條列出，違反任一條即為錯誤實作：

1. **D5 授權紅線**：必須用 **CINC Auditor**（Apache 2.0 自由重建版，Progress 官方認可的 drop-in 替代品），**不可用官方 InSpec 6+ 商業 binary**（需接受 Chef EULA 並持有 license key）。打包方式可自由選（apt / 直接下載 binary），**授權來源不可換**。`setup_guide` 與部署文件都要寫明這一點。
2. **D6 雙 transport 一次到位**：SSH（Linux）+ WinRM（Windows）都做，同一套 CLI 與 profile 格式，結果解析**統一走 `--reporter json`**（兩個 transport 輸出格式一致，connector 只寫一套解析）。不要只做 WinRM——GCB 的 Linux 線之後就要回頭補一次。
3. **D7 GCB 不另立引擎、不另寫 connector**：GCB 跑的就是 `inspec.py`，T-3.x 不新增任何 connector 檔案。content 只做**一份 Windows 最小 Demo profile**；驗收條件是「鏈路可運作」，**不是「涵蓋多少規則」**——不要做 content 工程。
4. **D7 content 必須可外部載入**：profile 不可硬編進 connector、不可打包進 agent image。理由：content 會持續變動，打包等於每次更新 content 都要重新發版並更新所有客戶站點 agent。T-3.2 的驗收就是「更換 content 不需重建 image、不需改 connector 程式碼」。
5. **D8 content 格式 = InSpec profile**（Ruby DSL）。不引入 XCCDF + OVAL 第二套格式——引擎統一的真正目的是 content 格式統一。
6. **WinRM 憑證預設走租戶層**：`tenant_detection_tool_configs` 加密鏈（與 SSH 同模型）。**只有「每台主機不同帳密」的情境**才走 FR-058.0 的任務層敏感參數（平台能力已就緒，見 §3.3），不要一開始就往任務層推。
7. **Windows GPO tattoo settings 陷阱**：Demo profile 的檢查規則**必須讀 `HKLM\Software\Policies` 正規政策區**。非 Policies 路徑的設定套用前不會被清空、會殘留（tattoo settings），讀到殘留舊值會**誤判為通過**——稽核情境屬嚴重問題。Demo 選題時就要挑正規政策區的項目。
8. **多目標處理沿用 FR-057 模式**：逐台掃、每台一個證據檔（`result_ref.upload_uids` 多檔回收鏈直接沿用），`host_failures` 逐台失敗回報——其中一台失敗不可拖垮其他台，也不可靜默假成功。
9. **`connection_type` 的 `WinRM` 為新值**（`SSH` 已存在）；`detection_tools.connection_type` 需涵蓋兩種型態，seed 時注意欄位值與 FE 渲染相容。

遇到 D1–D11 沒涵蓋的新決策：**停下來回報，不要自己開新方向**（判斷原則見 design.md §2 各條的「被排除方案與原因」欄）。


---

## §3 第一批帶來的新事實（第二批直接受益 / 必須遵守）

### 3.1 factory 已改依 code 取 connector（agent commit `f17a311`，D11）

- `get_connector()` 現在**優先吃 `detection_tool_code`**，`detection_tool_id` 降為 fallback（走 fallback 記 warning log）。
- 新 connector 的註冊方式：在 `core/task_executor_connectors/__init__.py` 加一個 `_build_inspec()` builder（import 留在 builder 內部，維持 lazy import 慣例——某支 connector 的第三方相依缺失時只有該工具不可用），並在 `_CONNECTOR_BUILDERS` dict 加 `"inspec": _build_inspec`（實際 code 以 T-2.1 seed 的 `detection_tools.code` 為準）。
- **絕不把新工具加進 `_LEGACY_TOOL_ID_TO_CODE`**——檔頭註解已明訂該表只涵蓋 FR-056/057 已出貨四筆，新工具加入等於把剛移除的脆弱性種回去。ZAP 已照此模式（參考 `_build_zap`）。

### 3.2 BE 派工 payload 已夾帶 `detection_tool_code`（BE commit `5151fb2c`，T-X.1 已上線）

`_collect_pending_tasks()` 已加欄位，第二批**不需要動 BE 派工鏈**——seed 進 `detection_tools` 後派工自然帶 code，agent 端照 §3.1 註冊即可接上。

### 3.3 任務層敏感參數平台能力已就緒（同 commit `5151fb2c`，T-0.1〜0.3）

param_schema 欄位標 `secret: true` 即自動走 Fernet 加密落庫 / 派工解密下發 / FE 與稽核 log 剝除（實作在 `common/util/detection_secret_params.py`）。第二批預設用不到（WinRM 憑證走租戶層，見 §2 第 6 條），但若真遇到「每台主機不同帳密」需求，直接標 `secret: true` 即可，不需自建機制。

### 3.4 D4 教訓通則化：報告取得 API 必須先驗「回傳內容 bytes」

ZAP 原定用 `reports.generate` 產 PDF，實作時發現該 API **只把檔案寫進工具主機磁碟、回傳路徑字串**，官方沒有回傳檔案內容的端點（zaproxy issue #7821）——遠端部署模型下 agent 拿不到，被迫改案（改 `core.htmlreport` 取 bytes）。

**通則**：任何「工具端產檔」的設計，動手前都必須先驗證取得管道回的是**內容本體**而不是「對方主機上的路徑」。InSpec 走 CLI `--reporter json` 輸出 stdout / agent 本機檔，**天然沒有此問題**——但若 T-3.2 content 載入或任何環節出現「由目標主機/工具主機產檔再取回」的設計，先驗這一點再寫。

### 3.5 agent 版號

第一批已 bump **0.2.12**（部署 DEV 中）。第二批出貨版 bump **0.2.13**，bump pattern 照 evidence-agent commit `c46aeeb`——**四處版號同步**：`pyproject.toml` / `config/config.py`（`AGENT_VERSION` 預設值）/ `deploy/docker-compose.yml`（`AGENT_IMAGE` + `AGENT_VERSION` 兩處）/ `rebuild.sh`（註解範例）。注意依 §5 測試紀律，開發期間**不重建 image、不部署**，bump commit 做完留著等全案端到端才出貨。

### 3.6 第一批可照抄的實作水準基準

- seed SQL：`scripts/sql/2026-07-30-fr058-1-zap-seed.sql`（見 §4）——檔頭把決策背景寫成註解、`ON CONFLICT DO NOTHING`、用 `nextval` 自然拿 id 且註明「code 派工後 id 不影響正確性」、`schema_migrations` 收尾。
- mock 單元測試：`test/test_zap_connector.py`（485 行，47 項全 mock + 突變測試驗斷言真咬）——InSpec connector 測試照此水準寫 `test_inspec_connector.py`。


---

## §4 實作範本座標（照形狀寫，不重新發明）

### 4.1 BE seed 範本（T-2.1 / T-3.1）

| 檔案 | 用法 |
|------|------|
| `/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be/scripts/sql/2026-07-30-fr058-1-zap-seed.sql` | **最新範本，優先照抄**——nextval 拿 id + 「code 派工後 id 不影響正確性」註解、`ON CONFLICT (code) DO NOTHING`、param_schema 的 `condition` / `secret` / `default` 寫法、setup_guide 的 E'' 多行 markdown 寫法、`schema_migrations` 收尾 |
| `/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be/scripts/sql/2026-07-28-fr057-1-openscap-seed.sql` | FR-057 版範本，SSH 型工具的 config_field_schema（SSH 帳號 / 金鑰欄位）可參考 |

### 4.2 agent connector 範本（T-2.2 / T-2.3）

| 檔案 | 用法 |
|------|------|
| `~/Projects/Billows/Audit-Manager/evidence-agent/core/task_executor_connectors/openscap.py`（578 行） | **InSpec 最像它**——SSH 多目標多檔型：逐台掃、每台一個證據檔、`host_failures` 逐台失敗回報、SSH 私鑰暫存處理、`probe()` 分段檢查與錯誤分類。InSpec 在它之上多一個 WinRM transport 分支 |
| `~/Projects/Billows/Audit-Manager/evidence-agent/core/task_executor_connectors/zap.py`（480 行，剛出爐） | 第一批的新 connector——`cancel_event` / timeout 輪詢寫法、summary 解析容錯、log 紀律（憑證絕不進 log）的最新範例 |
| `~/Projects/Billows/Audit-Manager/evidence-agent/core/task_executor_connectors/base.py` | `DetectionConnector` ABC、`ScanResult`、`ScanCancelledError`、`cancel_event` / `host_failures` / `content_mismatch_hosts` 注入點——介面不動 |

### 4.3 factory 註冊（T-2.2 的一部分）

`~/Projects/Billows/Audit-Manager/evidence-agent/core/task_executor_connectors/__init__.py`——f17a311 之後改依 code 註冊（見 §3.1）。照 `_build_zap` 的形狀加 builder + `_CONNECTOR_BUILDERS` 一列，**不動 `_LEGACY_TOOL_ID_TO_CODE`**。factory 迴歸測試在 `test/test_connector_factory.py`（90 行），新 code 註冊後補對應 case。

### 4.4 其他座標

| 檔案 | 用途 |
|------|------|
| `~/Projects/Billows/Audit-Manager/evidence-agent/Dockerfile` | T-2.2 加入 CINC Auditor（授權紅線見 §2 第 1 條） |
| `~/Projects/Billows/Audit-Manager/evidence-agent/test/`（跑法 `PYTHONPATH=. poetry run pytest test/ -q`，repo 缺 conftest.py 必帶 PYTHONPATH） | 單元測試落點 |
| BE `app/remote_agent/service/agent_enrollment_service.py` | 派工鏈（只讀參考，第二批預期不動——code 夾帶已上線） |


---

## §5 測試紀律（決策者 2026-07-30 裁示，**取代**原「批次結束測一次」）

### 5.1 端到端驗收整批延後

**端到端驗收延後到全案最後一次做**（與第一批、第三批合併驗收）。開發期間：

- **不重建 agent image**
- **不部署**（121 / 122 / 123 三台都不動）
- **不跑真實掃描**（不對真實 Linux / Windows 目標發動 InSpec 掃描）

版號 bump 0.2.13 的 commit 照做（§3.5），但不出貨。

### 5.2 做中持續做的便宜檢查（照舊，每個子任務完成前必過）

| 檢查 | 做法 |
|------|------|
| import / 語法檢查 | `PYTHONPATH=. poetry run python -c "from core.task_executor_connectors.inspec import ..."` 之類，改完即驗 |
| mock 單元測試 | 全 mock、不碰網路與真實主機；水準對齊第一批 `test/test_zap_connector.py`（47 項全 mock + 突變測試驗斷言真咬——刻意改壞被測邏輯確認測試會紅，避免寫出永遠綠的假測試） |
| SQL 套 DEV 後 SELECT 驗證 | seed 檔套 DEV 後 `SELECT id, code, connection_type, status FROM config.detection_tools ORDER BY id` + 查 `detection_tool_param_schemas` 確認 schema 進去且 `is_current` 正確 |

### 5.3 seed migration 三環境都要套

DEV → STG → POC 三環境（指令照 CLAUDE.md「DB 環境清單」段；密碼**請查 `.env` 的 `DB_SECRET` 或部署文件**，禁入任何版控檔案）：

```bash
# DEV
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev \
  --single-transaction -v ON_ERROR_STOP=1 -f scripts/sql/<fr058-2 seed 檔>.sql
# STG（同台不同 DB）
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_stg \
  --single-transaction -v ON_ERROR_STOP=1 -f <同上>
# POC（另一台）
psql -h 192.168.50.189 -p 25432 -U cmmgr -d guidant_ai_poc \
  --single-transaction -v ON_ERROR_STOP=1 -f <同上>
```

SQL 撰寫鐵則：檔頭 `-- Date:`、每個語句加日期註解、收尾 `INSERT public.schema_migrations`（本批只 seed 不建表，若意外需建表則必加 `GRANT ... TO cm_app` + sequence 權限）。


---

## §6 行為規範（實作 session 會踩到的，逐條遵守）

- **不切 branch**：任何 `git checkout <branch>` / `git switch <branch>` 一律不執行。BE 永遠在 `feature/FR-058` 工作；發現 branch 不對**停下回報**，不自己 fix（「為了在正確 branch commit 而切 branch」也不允許）
- **push 永遠等決策者明示**，不自動 push；階段性 commit（子任務完成後）直接做，毋需停下問
- **顯式 git add 檔名，禁用 `-am`**——避免誤 add 其他 arc 留下的 untracked / modified 檔案
- **跨 repo 各自分開 commit**：BE 與 evidence-agent 的改動不混在一個 commit 敘事裡
- **憑證禁入版控**：密碼、token、API key 絕不寫進任何會 commit 的檔案（含 SQL migration、docs、handoff）。連線資訊只寫帳號 / host / port / db 名，密碼一律寫「請查 `.env` 或部署文件」
- **收尾類動作等命令**：SPEC / SUMMARY / memory / Notion 母案收尾一律等決策者明確下令，子任務 commit 完只回報 status，不往收尾跑
- **Notion 卡回寫格式（每個子任務完成後）**：狀態改「**修正待驗證**」+ 補一段**白話說明**（做了什麼、怎麼驗證的）+ **commit hash** + **執行紀錄**（跑了哪些檢查、結果）。格式參考第一批 CM-967〜970 的回寫
- **BE 出錯先看 log**：`tail -200 log/app.log | grep -A 30 -i 'Traceback\|ERROR'`，log 沒線索才回報
- **不要晶晶體**（中英夾雜語法），不用「速贏」一詞


---

## §7 給 fresh session 的超短派工 prompt（直接複製貼上）

```
接手 FR-058 第二批（InSpec/CINC → GCB）的實作工作。

完整讀序入口：
/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/FR-058-2607-detection-tools-expansion/handoff/2026-07-30-fr058-batch2-dispatch.md
先讀它全份（含 §2 硬性決策約束與 §3 第一批新事實），再照它的 §0 讀序開 design.md §4.3-§4.4。

範圍：T-2.1〜T-2.4（CM-972〜975，母卡 CM-971）+ T-3.1〜T-3.3（CM-977〜979，母卡 CM-976），
序列執行，T-2.4 完成時一併結案 CM-953。

硬紅線速記：CINC Auditor 不可換官方 InSpec 商業版（D5）；SSH+WinRM 雙 transport 一次到位、
--reporter json 統一解析（D6）；GCB 複用 inspec.py 不另寫 connector、content 必須可外部
載入不打包進 image、只做一份 Windows 最小 Demo profile（D7/D8）；Demo 規則必讀
HKLM\Software\Policies 正規政策區；新 connector 依 code 註冊、絕不加 _LEGACY_TOOL_ID_TO_CODE。

測試紀律：端到端驗收整批延後到全案最後，開發期間不重建 image、不部署、不跑真實掃描；
只做 import 檢查 + 全 mock 單元測試 + SQL 套 DEV 後 SELECT 驗證；seed 三環境都要套。

BE 在 feature/FR-058 工作，不切 branch、不 push、顯式 git add 禁 -am；每個子任務完成即
commit 並回寫 Notion 卡（修正待驗證 + 白話說明 + commit hash + 執行紀錄）；收尾動作等我下令。
```

---

> 📌 **寫完自檢**：下個 session 只看這一份 + design.md §4.3-§4.4，能不能不回頭問任何人就開工？——本文所有路徑 / 卡號 / commit hash / SQL 指令皆可直接使用；密碼類資訊一律指向 `.env`。

