# FR-058.3 GCB 三棒派工單（第四批，2026-07-31）

> **本文是派工單，不是交接文件。** 兩個實作 session 各讀自己那一段即可，不必全讀。
> 協調者以短 prompt 指向本文對應章節派發，見 §5。

| 項目 | 內容 |
|------|------|
| 範圍 | FR-058.3 GCB — T-3.1（seed）/ T-3.2（文件）/ T-3.3（Demo profile） |
| Notion | CM-976（子需求母卡）→ CM-977 / CM-978 / CM-979 |
| Branch | 三 repo 皆 `feature/FR-058`，**不切 branch、不 push** |
| 前置 gate | ✅ **已通過**——InSpec / CINC `run()` 實機驗收 2026-07-31 完成（見 §1） |
| Session 切分 | **兩個 session**：A = T-3.1 + T-3.2，B = T-3.3（理由見 §5.1） |

---

## §0 必讀（各 session 開工前讀，不要跳）

1. `docs/features/FR-058-2607-detection-tools-expansion/design.md`
   - §2 決策表的 **D5 / D6 / D7 / D8**（引擎選擇、雙 transport、範圍收斂、content 格式）
   - §2.1「Linux GCB 為何不沿用既有 OpenSCAP」
   - **§4.4 FR-058.3 GCB 全段**（身分範圍、為何 Demo 選 Windows、content 外部載入約束、tattoo settings）
   - §5.6 拆分表（三棒驗收條件）
2. 範本檔：
   - seed migration → `scripts/sql/2026-07-30-fr058-6-inspec-seed.sql`
   - connector（GCB 完全複用、不另寫）→ `evidence-agent/core/task_executor_connectors/inspec.py`
3. 本文 §1（三個既成事實）——**design.md 尚未反映，不讀會做錯**

---

## §1 開工前必須知道的三個既成事實（2026-07-31 剛確立）

### ① T-3.2 已縮成「驗證 + 寫文件」，而且關鍵驗證已經做完

D7 原要求「content 不可硬編、必須可從外部載入」，原規劃 T-3.2 要做一層載入接口。
**已裁示不做抽象層**——CINC 原生支援三種 content 來源（Git URL / 本機路徑 / Supermarket），
而 `params.profile` 是直接進 `cinc-auditor exec` 的 argv，外部載入能力本來就在，
另做一層抽象只是把 CINC 的能力再包一次。

**今日實跑驗證的結論（直接採信，不要重驗）**：

- **裸 GitHub URL 走的是 git fetcher 而非 tarball 下載**——fetcher 會先 shell out 呼叫 `git` 查 default branch
- agent image 原本沒裝 `git`，導致 `Errno::ENOENT`；**已於 agent commit `6d1a4fc` 補裝**，
  DEV 現跑 `0.2.17`，容器內 `git 2.47.3`
- 實跑通過的統計數字：`dev-sec/linux-baseline` 對 151（Linux/SSH）**pass 131 / fail 60 / error 0 / n/a 2**；
  `dev-sec/windows-baseline` 對 160（Windows/WinRM）**pass 300 / fail 472 / error 0 / n/a 122**

**所以 T-3.2 只剩「把這個結論寫成文件」**——不需寫 code、不需重驗。

### ② InSpec 正在更名為 CINC Auditor（另一 session 進行中）

UI 名稱 `InSpec / CINC Auditor` → **`CINC Auditor`**。決策者 2026-07-31 拍板，理由：
① 客戶／稽核方看到 InSpec 會問「這要授權嗎」——名稱製造了它自己要闢謠的問題；
② InSpec 是 Progress 商標（CINC 專案本身就是因商標才改名）。

**對本單的影響**：seed 與 setup_guide 裡**使用者可見的引擎名稱一律寫「CINC Auditor」**；
描述相容性時可寫「相容 InSpec profile 格式」（合法的描述性使用）。
內部識別碼 `code='inspec'`、檔名 `inspec.py` 一律不動。

### ③ profile 欄位要改成可下拉選擇（併入 T-3.1）

**現況**：InSpec 的 `param_schema.profile` 是純文字（`type: "text"`），使用者得自己貼網址。
**已上線的 OpenSCAP 早就用 `select_or_text`**（下拉給預設選項 + 允許自行輸入），
FE 元件 `DetectionConfigField` 已支援此型態——**FE 與 agent 零改動**。

要做的是把 InSpec 與 GCB 的 profile 欄位都改成 `select_or_text`：

| 層 | 內容 |
|----|------|
| 下拉選項 | 我方預置的已知可用 content：dev-sec `linux-baseline` / `windows-baseline`，以及 T-3.3 產出的 GCB Demo profile |
| 自行輸入 | 客戶自備的 Git repo / 本機路徑 / Supermarket 名稱——**維持現有彈性，一個都不減** |

⚠️ **選項的網址形式要實跑驗證後才定案**：git 已裝所以兩種都能跑，
但建議下拉選項用 **tarball 形式**（`.../archive/refs/heads/master.tar.gz`），少一個外部相依與故障點。
**實跑比較兩種形式再決定，不要憑猜。**

---

## §2 Session A：T-3.1（seed）+ T-3.2（文件）

### T-3.1 — BE + migration（Notion CM-977）

1. **新增 migration**（**先 `ls scripts/sql/ | grep fr058` 確認流水號**——目前已到 `fr058-9`，
   另一 session 的改名單可能已佔用 `fr058-10`）：

   - **seed GCB 工具目錄（第 8 筆）**：`code='gcb'`、`connection_type='SSH'`、`status='available'`、
     `requires_credentials=TRUE`、`requires_target_host=TRUE`
   - **`config_field_schema` 與 `credential_group_schema` 直接對照 inspec 那筆**
     ——GCB 是 `credential_group_schema` 的**第二個使用者**（SSH 給 Linux 目標、WinRM 給 Windows 目標）
   - **`param_schema`**：`hosts` / `transport` / **`profile`（`select_or_text`，選項含 T-3.3 的 GCB Demo profile）** / `timeout_sec`
   - **`setup_guide`**：目標主機準備（比照 inspec 的 SSH / WinRM 兩段）、
     明確寫「本工具的檢測引擎為 **CINC Auditor**（Apache 2.0）」、
     Windows 政策區與 **tattoo settings 警語**、GCB content 的來源與限制說明
   - **同一支 migration 順便把 inspec 的 `param_schema.profile` 也改成 `select_or_text`**（§1 事實③）

2. **SQL migration 鐵則**：檔頭 `-- Date:`、每語句加日期註解、收尾 `INSERT public.schema_migrations`

3. **三環境都套**（DEV / STG / POC，連線資訊見 CLAUDE.md「DB 環境清單」段，**密碼查 `.env` 的 `DB_SECRET`**）：
   `psql --single-transaction -v ON_ERROR_STOP=1 -f <檔>` 用 `cmmgr`，套完各 `SELECT` 確認

4. **agent factory 要不要動？先查再說**——GCB 走 `code='gcb'` 但要複用 inspec connector。
   grep `evidence-agent/core/task_executor_connectors/` 的 factory（`get_connector` 依 code 取），
   確認 code → connector 的對應處；若需要加一筆 `gcb → InspecConnector` 映射就加
   （**這是 agent repo 的改動，要另外 commit**）。
   D11 已把 factory 改為依 code 取，**不要回頭加硬編 id 映射**。

**驗收**：設定頁出現 GCB、任務可選 GCB 並指定目標與 content。

### T-3.2 — 文件（Notion CM-978）

**不寫 code。** 把 §1 事實① 的驗證結論寫成文件：

- 更新 `design.md` §4.4 的 content 外部載入段（或加一個小節），寫明：
  三種來源、裸 GitHub URL 走 git fetcher（**有實跑佐證**）、agent image 已補裝 git、
  更換 content 不需重建 image 也不需改 connector（**D7 的約束已滿足**）
- **一併記錄兩個已知限制**（已裁示開後續卡、不在本案做，但文件要留下）：
  ① **封閉網路客戶只能用本機路徑**，但目前沒有把 profile 檔送進 agent container 的機制
  ② **私有 repo 無憑證路徑**——`params.profile` 是非 secret 純文字欄位，沒地方放 token

⚠️ **文件類工作要分段寫檔**：先 Write 骨架再多次 Edit，**不要一次寫完整份**
（本專案已三次遇到一次寫大檔時 API 中斷）。

---

## §3 Session B：T-3.3 — Windows 最小 Demo profile（Notion CM-979）

**前置**：Session A 的 T-3.1 已完成並經協調者放行（profile 下拉選項需含本棒產出的 Demo profile 路徑，
若順序上有相依，回報協調者協調）。

一份 **Windows 最小 Demo profile**（InSpec profile 格式，Ruby DSL）：

- **驗收條件是「鏈路可運作」不是「涵蓋多少規則」**（D7 明確定案——**這不是 content 工程**）
- **選題必須落在 `HKLM\Software\Policies` 正規政策區**——避開 **tattoo settings 陷阱**：
  非政策區的設定在套用前不會被清空、會殘留舊值，讀到殘留值會**誤判為通過**，稽核情境屬嚴重問題
- **放置位置**：**不可打包進 agent image**（D7 約束）。放在 repo 內當範例檔或另存可對外取用之處，
  由 `params.profile` 指向——**放哪裡要先想清楚並在回報中說明你的選擇與理由**
- **端到端實跑驗證**：對 **192.168.50.160**（Windows / WinRM，憑證已在設定頁）派工執行 →
  證據進證據池 + **summary 有數字**

> 🔴 **驗收要看統計數字，不要看到「有證據進池」就算過**——報告結構不符時會**統計全零但證據照常上傳**
> （這是刻意的容錯，也是本案最不明顯的陷阱）。

---

## §4 共通環境與鐵則

### 環境

| 項目 | 值 |
|------|-----|
| DEV agent | `192.168.50.123`，容器名 `deploy-guidant-ai-agent-1`，目前 **`0.2.17`**（含 CINC + git + xsltproc） |
| 測試目標（Linux） | `192.168.50.151`——`audit-scan` 帳號已設 NOPASSWD sudo |
| 測試目標（Windows） | `192.168.50.160`——WinRM 憑證已在設定頁 |
| BE | 本機 port 8000（`main_app.py`；`main_socketio.py` 是 socket 8002 不是 API 入口）；**重啟必先 `kill -9`** |
| agent 測試 | 必帶 `PYTHONPATH=.`（repo 缺 `conftest.py`），基線 **407 passed, 1 skipped** |

### 鐵則

- 三 repo 皆在 `feature/FR-058`，**不切 branch、不 push**
- **顯式 `git add` 檔名，禁 `-am`**——BE working tree 有 `CLAUDE.md` / `.claude/skills/...` 兩個無關 modified
  與一批 untracked docs，**絕不可帶進**
- **各 repo 分開 commit**，message `feat(cm-977): ` / `docs(cm-978): ` / `feat(cm-979): ` 開頭中文說明，
  結尾帶 `Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>`
- **憑證禁入版控**——migration 內不可出現密碼，只寫帳號 / host / port / db 名
- BE 若改了 service / serializer → **提醒重啟**
- **agent 若有 code 改動不要自行 bump 版號與重建 image**，回報協調者統一安排（昂貴前置只付一次）
- **不動 Notion、不寫 spec、不收尾**——Notion 回寫由協調者另外安排
- **每棒完成後停下回報**，等協調者放行才做下一棒（人工監控，不做鏈式自動接力）

### 回報格式

| 棒 | 要回報什麼 |
|----|-----------|
| **T-3.1** | migration 檔名與流水號；三環境套用結果（各環境 `SELECT` 出的 gcb 那列）；factory 是否需改（查證結果）；**profile 下拉選項的最終形式與實跑比較依據**；commit hash |
| **T-3.2** | 文件改動落點、寫了哪幾段、commit hash |
| **T-3.3** | Demo profile 選了哪個基準項目與理由（**如何確認在政策區**）；放置位置與理由；**端到端實跑的 summary 實際統計數字**；commit hash |

---

## §5 派發方式

### 5.1 為什麼切成兩個 session

| Session | 內容 | 理由 |
|---------|------|------|
| **A** | T-3.1 + T-3.2 | 兩者共用同一批脈絡——T-3.1 的 `setup_guide` 要寫 content 來源說明，T-3.2 正是把那份說明寫進 design.md。同一個 session 做，第二棒幾乎零額外理解成本。兩棒都不重、合計仍在單 session 舒適範圍 |
| **B** | T-3.3 | 性質不同：要寫 Ruby DSL、查 Windows 政策區註冊表項目、跑端到端實測。與 A 的 SQL / 文件工作沒有共用脈絡，混在一起只會讓 context 變雜 |

**不建議三棒一個 session**：T-3.3 的實跑除錯可能拉很長（Windows 政策區選題若踩到 tattoo settings 要重挑），
context 爆掉會連累前兩棒已完成的脈絡。

### 5.2 派發用的短 prompt

**Session A**：

```
接手 FR-058.3 GCB 的 T-3.1（seed）+ T-3.2（文件）兩棒。

派工單：docs/features/FR-058-2607-detection-tools-expansion/handoff/2026-07-31-fr058-batch4-gcb-dispatch.md
先讀該文的 §0 必讀、§1 三個既成事實、§2（你的工作內容）、§4（共通環境與鐵則）。
§3 是另一個 session 的工作，不用讀。

T-3.1 做完先停下回報，等放行才做 T-3.2。
```

**Session B**（等 A 的 T-3.1 放行後才派）：

```
接手 FR-058.3 GCB 的 T-3.3——Windows 最小 Demo profile。

派工單：docs/features/FR-058-2607-detection-tools-expansion/handoff/2026-07-31-fr058-batch4-gcb-dispatch.md
先讀該文的 §0 必讀、§1 三個既成事實、§3（你的工作內容）、§4（共通環境與鐵則）。
§2 是另一個 session 已完成的工作，需要時再看。

做完停下回報，不要自動往收尾跑。
```

### 5.3 協調者的放行節奏

```
T-3.1 完成 → 協調者抽查（三環境 DB gcb 那列、profile 欄位確實變 select_or_text、factory 查證結果）
   ↓ 放行
T-3.2 完成 → 協調者抽查（design.md 實際內容）
   ↓ 放行（此時可派 Session B）
T-3.3 完成 → 協調者抽查（Demo profile 的註冊表路徑真在政策區、實跑 summary 統計數字非零）
   ↓
GCB 三棒收口 → 全案最終端到端驗收（§4.3 of 交接文件）
```
