FR-058 協調者中繼交接 — 第一批已完成、第三批全數完成、第二批剩 GCB 三棒(2026-07-31)

🔄🔄 2026-07-31 第三次更新(最新,本段優先於下方兩段)。本輪的變化:

  • 新增一批平台級能力:互斥憑證組別(BE 1d23082b / CM-985 + FE 37967b4)——config.detection_tools 新增 credential_group_schema JSONB,測試連線改由使用者明確選一組憑證、設定頁依宣告分區顯示。migration 2026-07-31-fr058-9-* 三環境已套(實查:僅 inspec 有宣告,其餘六筆 NULL=行為與現況相同)。詳見新增的 §1.7
  • 🟢 實測有實質進展(本輪最大的好消息)——§5 第 0 項那條「零實跑驗證」的風險已部分消解DEV agent 已是 0.2.14 且 CINC 確實裝進去了/usr/bin/cinc-auditor 存在,T-2.2 最大的未驗證假設證實正確)、WinRM 測試連線已對真實 Windows 主機(192.168.50.160)通過SSH 側卡在目標主機的 sudo 權限設定(環境問題,非 code 問題)。尚未實跑過 run(),只驗到 probe。詳見新增的 §1.8
  • §2 新增一條教訓(2.7):改 serializer / model 後 BE 沒重啟 → 部分功能生效、部分沒有。症狀辨識法見該節
  • agent 087fa41:Nmap 證據改存人可讀 HTML(容器內 xsltproc + 官方 nmap.xsl)——這是實作 session 自行做的改案,未經派工,需決策者追認(見 §5 新增項)
  • §7 新增三件裁示(7.4 T-3.2 縮成「驗證 + 寫文件」但非無條件、7.5 兩個 content 來源限制開後續卡、7.6 commit 標籤不一致不處理 / push 暫緩)
  • §5 新增四項待辦:「目標主機」文案語意模糊、use_sudo 不支援 sudo 密碼、Nmap HTML 改案待追認、兩個 content 來源限制
  • §1.1 註記更正:舊版說 BE working tree 有 pyproject.toml 誤加 zaproxy——實查已不存在(grep 零命中),該項風險已消失

🔄 2026-07-31 稍晚更新(本文首版 commit 於 d81067f5,之後實作 session 又跑完數棒)。本次更新的內容:

  • 第三批(Nmap)全數完成——T-4.2(BE 16ae4ff0)+ T-4.3(agent 883e5d1)都已 commit,第三批零剩餘
  • 第二批 T-2.3 完成(agent eb352a7)——InSpec/CINC run() 已寫完;第二批只剩 T-2.4(純 Notion 結案)與 GCB 三棒
  • agent 已 bump 0.2.146f97107,標註「未出貨,等全案端到端」;DEV 上跑的仍是 0.2.13
  • 🔴 §4 開工順位重大改寫——決策者已取消「先驗收 T-2.2 才放行 T-2.3」這道 gate,改為一路往下跑、驗收全部併到最後。舊版 §4.1 的 T-2.2 gate 已不存在,不要照著執行
  • §5 新增本案目前最大的風險:InSpec(T-2.1〜2.3)與 Nmap(T-4.1〜4.3)兩條線 code 全部完成,但從未對真實環境跑過任何一次
項目 內容
緣由 FR-058(檢測工具擴充)的第一批(ID 解耦 + 任務層敏感參數 + ZAP)已實質完成並實測驗收第三批(Nmap)三棒已全數完成第二批(InSpec/CINC → GCB)的 InSpec 段(T-2.1〜2.3)已完成,剩 T-2.4 與 GCB 三棒。前一棒協調者 session 的 context 將滿,需冷接續作。
前一棒 docs/features/FR-058-2607-detection-tools-expansion/handoff/2026-07-30-fr058-planning-complete-handoff.md(規劃完成交接)。本文是它的續作——那一份的 §3「三種情境」已走完情境 A,本文接續其後的所有事情。
Branch 三 repo 皆在 feature/FR-058全部未 push
本棒角色 協調、決策、派工、抽查。不寫 code、不跑測試。 執行類(跑測試 / 部署 / 重建 image)與文件類(Notion 回寫 / Artifact republish / spec 撰寫)工作全部派 subagent
接手前必讀 本文 §0 讀序(含硬 gate 與冷接自檢五問)
下一個動作 接續 InSpec + Nmap 的合併驗收(見 §4.1)。DEV 已建到 0.2.14、CINC 已確認裝好、WinRM probe 已通過;剩下三件卡點:① SSH 側等決策者在目標主機設 NOPASSWD sudo ② FE Dialog 兩欄改版完成後才驗收 ③ run() 從未實跑,才是驗收的主體。GCB 三棒等這輪過了才做
預估時間 理解現況並接住派工節奏:20–40 分鐘;接續合併驗收(image 已建好,剩實跑 run() + Nmap 掃描):另加 60–100 分鐘
HEAD(2026-07-31 實查) BE 1d23082b(領先 17)/FE 8d77d5e(領先 5)/agent 087fa41(領先 10)——三 repo 皆 feature/FR-058、皆未 push

🧭 原始需求 / WHY

決策者的原始需求(一字不改)

「目前的檢測工具管理 /plugin/tool-plugin-manage 還需要增加下面工具——OpenSCAP for Windows 解決方案 / Nmap / GCB / SonarQube。請幫我分析跟規劃,開成新的需求放到 Notion。」

需求的演變過程(這是理解本案的關鍵,不讀會誤解範圍)

原始四項工具,經過調研與決策者裁示後變成另外四項

階段 發生什麼 結果
起點 決策者列出四項:OpenSCAP for Windows / Nmap / GCB / SonarQube 四項
中途追加 決策者追加 ZAP(第五個工具) 五項
裁示① SonarQube 本期不做(日後另議) 剩四項
調研發現 「OpenSCAP for Windows」證實不可行——OpenSCAP 官方已放棄 Windows 支援(docs/windows.md 明文標示 no longer usable,引擎層無 WinRM transport、無 Windows OVAL probe)。改由 InSpec / CINC Auditor 承擔此需求 工具換人,需求不變
裁示② ZAP 優先上線,其餘分批做(取代原三線並行規劃) 分批出貨

最終四工具:ZAP(DAST 網頁動態掃描)/ InSpec·CINC Auditor(Windows + Linux 組態檢測)/ GCB(政府組態基準 TWGCB,引擎複用 CINC)/ Nmap(網路埠掃描)。

大圖定位(本案在哪一棒)

FR-056 檢測工具整合平台(v1.11.0 上線)
   └ tool-agnostic 地基:後端對具體工具零知識、前端純 schema 驅動、加工具原則上只要一條 SQL seed
        ↓
FR-057 OpenSCAP SSH connector(v1.12.0 上線,2026-07-30 全案結案)
   └ 第一個真實工具落地:補齊 SSH 連線型態、setup_guide 欄位、多檔證據回收、兩條「靜默假成功」防護通道
        ↓
FR-058(本案)一次規劃四個工具 + 補平台唯一的結構性缺口

本案要解決的兩件事

① 接入四個工具——涵蓋三種連線型態:

形態 已上線 本案新增
① 連遠端服務 API OpenVAS ZAP(FR-058.1)
② 遠端登入目標主機 OpenSCAP(SSH / Linux) InSpec·CINC(SSH + WinRM,FR-058.2)、GCB(複用 .2 引擎,FR-058.3)、Nmap(SSH,FR-058.4——2026-07-30 D9 改案後移入此列)
③ agent 本機 CLI 尚無 仍無——原定 Nmap 走此型態,D9 改案後 connection_type='CLI' 至今仍無實際使用者

② 補平台唯一的結構性缺口:任務層敏感參數(FR-058.0)——現有設計把憑證與參數分兩處放,而只有憑證那一條有加密

層級 存放位置 加密 適合放什麼
租戶層 tenant_detection_tool_configs Fernet 加密 ZAP 服務位址與 API key——全租戶共用、設定一次不動
任務層 job_execution_detection_tools.tool_params 明文 掃描目標、profile 這類非敏感參數
任務層敏感 原本不存在(本案補上) 「這次掃 A 網站用 A 的帳密,下次掃 B 網站用 B 的帳密」正好落在這一格

若直接把被掃網站的登入帳密塞進 tool_params,會發生兩件事:① 帳密明文躺在資料庫;② FE 執行紀錄視窗會顯示任務參數——BE 既有的 secret 剝除機制是針對租戶層設定寫的,任務層參數沒有這套保護,等於帳密直接顯示在畫面上。這不是 ZAP 專屬問題(GCB 每台主機帳密不同會撞同一格),因此當成平台級能力補上。

敏感參數的生命週期:資料庫為密文、僅在派工傳輸與 agent 執行期間為明文、agent 用完即丟不落地、FE 一律剝除。此能力已在第一批完成並實測(見 §3.4)。

本棒在大圖的位置

第一批已實測交付,第二批與第三批的實作已派給外部 session 並行進行中本棒是協調者與決策者——放行 gate、審核 subagent 自主決定、處理跨批協調、產文件。不是實作者,也不是測試執行者。


§0 接手讀序

0.1 🔒 先懂需求 gate(全讀,讀完才能碰任何東西)

  1. 本文「🧭 原始需求 / WHY」全段——特別是「需求的演變過程」那張表,不讀會搞不清楚為何最終工具清單跟決策者原話對不上
  2. 本文 §3(本棒完整經過)全讀——這是本文的核心。D4 與 D9 兩次改案、三個修掉的 bug、SPA 的營運級風險,全部發生在本棒任內,且都改變了原設計。只讀前一棒的交接文件會拿到過期的認知
  3. docs/features/FR-058-2607-detection-tools-expansion/design.md §2 決策表 D1–D12 全讀(512 行檔案,只讀 §2 那一段)——D1–D12 是本案所有取捨的依據。⚠️ D4 與 D9 已改案、D12 是本棒新增的,內容與前一棒交接時不同

0.2 現況與待辦

  1. 本文 §1(當前狀態盤點)→ §2(本棒教訓)→ §4(開工順位)→ §5(已知待辦與風險)
  2. Notion 母案 CM-957:https://app.notion.com/p/3ad346da4cd081859d2ed8b21ca2697c——末段「🚀 分批出貨計畫」含批次安排與測試紀律

0.3 需要細節才開(不要一開始就全讀,會燒 context)

  1. 兩份派工文件(要知道兩批各自被交代了什麼,或要回答實作 session 的提問時才開):
    • handoff/2026-07-30-fr058-batch2-dispatch.md(第二批 InSpec/CINC → GCB,約 460 行)
    • handoff/2026-07-30-fr058-batch3-nmap-dispatch.md(第三批 Nmap,約 1000 行,含 D9 改案的完整 NPSL 論證)
  2. 前一棒交接文件 handoff/2026-07-30-fr058-planning-complete-handoff.md——§6 pre-flight 指令與 §7 前置確認仍然有效可照抄,但 §1 狀態盤點與 §3 情境判斷已過期(情境 A 已走完)
  3. design.md §3(現況接入點盤點)/ §4(四工具各自的 param_schema 與 connector 要點)/ §5(拆分與 20 子任務)/ §6(端到端驗收九項)
  4. discussion.html(1060 行)——⚠️ 內容已多處過期,見 §5 風險表

0.4 ✅ 冷接自檢(五問,答不出來回去讀 §0.1,不要碰任何東西)

  1. 本案要解決什麼問題? 提示:不只是「多加四個工具」,還有一個平台級的結構性缺口,而那個缺口已經在第一批做完了。
  2. 第一批的三種掃描模式,各自驗收結果是什麼?為什麼是那個結果? 提示:其中一種是 ❌,而且失敗的方式比「掃不到東西」嚴重得多。
  3. D4 與 D9 兩次改案分別由什麼觸發?各自的依據是什麼? 提示:一個是官方 API 的能力邊界(有 issue 編號),一個是授權條款原文(有版本與章節)。兩者都不是「想改就改」。
  4. 為什麼 GCB 三棒要等 InSpec 那條線實機驗收過了才做? 提示:答案有兩層——一層關於 mock 測試蓋不到什麼,一層關於第二批的依賴結構。⚠️ 本題原問的是「為什麼 T-2.2 要驗收過才放行 T-2.3」,那道 gate 已被決策者取消(見 §4.1 開頭),但兩層理由原封不動地移到了 GCB 這道新 gate 上。
  5. 本棒的角色是什麼?哪三類事情不該自己做?

第 2 題是重點題:若答成「登入後掃描掃出空報告」,代表讀到的是已被更正前的錯誤記載,回去讀 §3.3。


§1 當前狀態盤點

⚠️ 本節數字為 2026-07-31 稍晚實查git log / psql / Notion fetch),已較本文首版(d81067f5)更新。實作 session 若仍在跑,commits 會持續進來——接手時務必先跑 §6 pre-flight 看實況,不要拿本節當現況。

1.1 三 repo git 現況(全部未 push)

⚠️ 本表為 2026-07-31 第三次更新的實查值(舊值 BE 15 / FE 3 / agent 8 已過期)。

Repo Branch 領先 origin HEAD 說明
BE compliance-manager-be feature/FR-058 17 1d23082b feat(cm-985): 互斥憑證組別平台能力(見 §1.7) working tree 有 CLAUDE.md + .claude/skills/big-feature-workflow/SKILL.md 兩個 modified,皆與 FR-058 無關,不要 commit 進本案
FE compliance-manager-fe feature/FR-058 5 8d77d5e fix(fr058): 檢測工具摘要卡分開顯示執行主機與掃描目標 ⚠️ working tree 有 src/views/plugin/ToolPluginManage.vue 未提交——那是進行中的 Dialog 兩欄改版(§5 新增項),是別的 session 的活,不要動也不要 commit
agent evidence-agent feature/FR-058 10 087fa41 feat(fr058): Nmap 證據改存人可讀 HTML(未經派工的自主改案,待追認 working tree 乾淨

本輪(前次更新之後)新增:BE 2 個2858b447 前次文件更新 → 1d23082b 憑證組別)、FE 2 個37967b4 憑證分組渲染 → 8d77d5e 摘要卡 hosts/targets 分離)、agent 2 個2c64a3b probe transport 端到端釘樁 → 087fa41 Nmap HTML)。

⚠️ agent 的 HEAD 仍非 bump commit——pyproject.toml 版號維持 0.2.14,之後進來的三個 commit 都未再 bump(符合「未出貨、等全案端到端」裁示)。DEV 上實跑的已是 0.2.14(本輪已建並部署,見 §1.5)。

✅ 舊版風險項已消解:前一版 §1.1 記載「BE pyproject.toml 誤加了 zaproxy 相依,待決策者確認是否還原」——本輪實查該相依已不在 pyproject.tomlgrep zaproxy 零命中),working tree 也不再有 pyproject.toml 的 modified。§5 第 2 項的風險隨之消失,不需再處理

另有一批與 FR-058 無關的既有 untracked 檔案(v1.9-bugfix handoff、v1.8.0 交付 docx、ddd-layer-audit/security-audit-report-2026-07-17.htmlvariants.png 等)——那是別的 arc 留下的,不要清理、不歸本棒管

1.2 三批進度總表

批次 內容 卡號 狀態
第一批 ID 解耦(FR-058.X)+ 任務層敏感參數(.0)+ ZAP(.1) CM-958〜970 實質完成,已實測驗收(三種掃描模式結果見 §3.4),DEV agent 已部署 0.2.13
第二批 InSpec / CINC(.2)→ GCB(.3) CM-971〜979 🔄 InSpec 段 code 全數完成:T-2.1 ✅(4d5226fa)、T-2.2 ✅(dcedb4f)、T-2.3 ✅(eb352a7),三張卡皆「修正待驗證」;剩 T-2.4(純 Notion 結案 CM-953)+ GCB 三棒(T-3.1 / T-3.2 / T-3.3)未開始
第三批 Nmap(.4) CM-980〜983 三棒全數完成:T-4.1 ✅(b9520f7b)+ requires_target_host ✅(9a15db96 + FE 2fe1ce6)、T-4.2 ✅(16ae4ff0)、T-4.3 ✅(agent 883e5d1 + bump 6f97107)。零剩餘,全部待實機驗收

剩餘子任務:第二批 4 棒(T-2.4 / T-3.1 / T-3.2 / T-3.3)。第三批已無剩餘。另有一批第三次更新新增的平台級能力(§1.7)與 FE Dialog 改版(§5)不在原 20 棒編號內。

⚠️ 「完成」在此指 code 已 commit + mock 測試綠,不等於已驗證2026-07-31 第三次更新的修正:這句在 InSpec 側已部分不成立——DEV 已建到 0.2.14、CINC 確認裝好、WinRM probe 已對真實 Windows 主機通過(§1.8)。run()(真正的掃描)仍從未跑過一次,Nmap 整條線也仍零實跑。風險降級但未消除,見 §5 第 0 項與 §4.1。

1.3 三環境 config.detection_tools 實況(2026-07-31 實查,三環境完全一致)

id code connection_type status requires_credentials requires_target_host
1 openvas API available
2 nessus API coming_soon
3 sonarqube API coming_soon
4 openscap SSH available
5 zap API available
6 inspec SSH available
7 nmap SSH available

DEV(188/guidant_ai_dev)、STG(188/guidant_ai_stg)、POC(189/guidant_ai_poc)三環境 id 與旗標完全對齊,無 drift。

nmaprequires_credentials=TRUE 正是 D9 改案的落地證據——改案前它應為 FALSE。 inspecconnection_type='SSH' 是刻意的:該欄位語意實為「要不要問測試主機」,不對使用者顯示,真正的 transport 選擇放在 param_schema(見 §7.1)。

1.4 已套用的 SQL migration(scripts/sql/九支,三環境皆已套)

檔案 內容
2026-07-30-fr058-1-zap-seed.sql ZAP 工具目錄 + param_schema + setup_guide(T-1.1)
2026-07-30-fr058-2-fix-zap-login-required-flags.sql ZAP 登入四欄改條件必填(§3.2 修正②)
2026-07-30-fr058-3-zap-setup-guide-spa-limitation.sql setup_guide 補 SPA 限制說明
2026-07-30-fr058-4-zap-setup-guide-spa-shutdown-correction.sql 更正:SPA 登入掃描會打掛共用 ZAP(§3.3)
2026-07-30-fr058-5-detection-tools-requires-credentials.sql requires_credentials 宣告欄位(T-4.1,D9 平台能力)
2026-07-30-fr058-6-inspec-seed.sql InSpec / CINC 工具目錄(T-2.1)
2026-07-30-fr058-7-detection-tools-requires-target-host.sql requires_target_host 宣告欄位(解 FE 對 connection_type 的耦合)
2026-07-30-fr058-8-nmap-seed.sql Nmap 工具目錄(SSH 型,D9 改案後,T-4.2)
2026-07-31-fr058-9-detection-tools-credential-group-schema.sql (第三次更新新增,第九支) credential_group_schema JSONB 宣告欄位 + 回填 InSpec 的憑證組別宣告 + config_field_schemagroup / hint(§1.7)。三環境已套並實查inspec 有宣告、其餘六筆 NULL

1.5 Agent 部署現況(只有 DEV 是新版,這是刻意的

主機 角色 部署版本 說明
192.168.50.123 DEV **0.2.14(2026-07-31 第三次更新已建並部署) 含 Nmap connector + InSpec run()。image build 通過、/usr/bin/cinc-auditor 實查存在**——T-2.2 最大的未驗證假設已證實(§1.8)
192.168.50.122 STG 0.2.11 刻意未更新——決策者裁示 DEV 驗完才輪 121/122,不重複付部署成本
192.168.50.121 POC 0.2.11 同上

agent 版號沿革:0.2.11(FR-057 出貨)→ 0.2.12(FR-058 第一批:ZAP connector + factory code 解耦)→ 0.2.13(ZAP 主動掃描修正,=目前 DEV 實跑版)→ 0.2.146f97107,第三批 Nmap connector;版號四處已同步:pyproject / config / docker-compose 兩處 / rebuild.sh)。

⚠️ 舊記載「0.2.14 只入版控、未出貨、三台都沒有」已過期——2026-07-31 第三次更新時 DEV(123)已建好並部署 0.2.14。121 / 122 仍停在 0.2.11(刻意,等全案驗收)。0.2.14 這個版號同時涵蓋 Nmap connector、InSpec run()、probe transport 釘樁與 Nmap HTML 改案(後三者都未再 bump)。

1.6 Notion 卡片索引

母案:CM-957https://app.notion.com/p/3ad346da4cd081859d2ed8b21ca2697c

子需求卡 標題 Notion URL 子任務卡
CM-958 FR-058.X _TOOL_ID_TO_CODE 解耦(D11) https://app.notion.com/p/3ad346da4cd08164b0f9f05776a88562 CM-959、CM-960
CM-961 FR-058.0 任務層敏感參數 https://app.notion.com/p/3ad346da4cd0810fae51e7f192d5ad85 CM-962〜965
CM-966 FR-058.1 ZAP https://app.notion.com/p/3ad346da4cd081f48410d617dee61ba9 CM-967〜970
CM-971 FR-058.2 InSpec / CINC Auditor https://app.notion.com/p/3ad346da4cd0811faa85fd15a38df059 CM-972〜975
CM-976 FR-058.3 GCB https://app.notion.com/p/3ad346da4cd08120b9f1cf9b1f976847 CM-977〜979
CM-980 FR-058.4 Nmap https://app.notion.com/p/3ad346da4cd081159daae65d4b08c80d CM-981〜983
CM-984 (新增)FR-058 後續:ZAP 登入後掃描支援 SPA https://app.notion.com/p/3ad346da4cd08101984bd520657eadd2 無(後續另案,Not started)

⚠️ Notion 為 free plan,不支援 SQL 查詢資料源query-data-sources 對此 DB 回空陣列)。要查卡片狀態一律用 notion-search 找到卡再 notion-fetch 開,或直接開母卡看子卡清單。

子任務卡狀態(2026-07-31 稍晚 fetch 實查)

狀態 備註
CM-974(T-2.3 InSpec run() 修正待驗證 已回寫完整白話說明 + 五條「未經實跑驗證的假設」對照表(reporter json 輸出位置 / 報告結構 / 退出碼語意 / exec 參數形式 / SIGTERM 行為)。驗收時逐條對照
CM-982(T-4.2 Nmap seed) 修正待驗證 已回寫,含三環境套用結果與 live API 實查
CM-983(T-4.3 Nmap connector) 修正待驗證 已回寫,含 68 項單元測試 + 12 輪突變測試,並列出四項待端到端驗證

⚠️ 子需求母卡(CM-971 / CM-976 / CM-980)狀態仍是 Not started——實作 session 只更新自己那張子任務卡,不動母卡。母卡狀態不代表進度,看進度要開子任務卡或看本文 §1.2。這是既有慣例,不是遺漏。母案 CM-957 本身狀態也是 Not started(2026-07-31 fetch 實查),同理不代表進度。

新增卡 CM-985(互斥憑證組別平台能力,見 §1.7)——不在原 20 棒編號內,是實測過程中暴露的平台缺口另開的。


1.7 🆕 新增的平台級能力:互斥憑證組別(CM-985)

2026-07-31 第三次更新新增。BE 1d23082b + FE 37967b4 + migration fr058-9(三環境已套)。

這不是 InSpec 專屬修補,是平台級能力。 InSpec / CINC 是平台第一個「一個工具帶兩組互斥憑證」的工具(SSH 憑證用於 Linux 目標、WinRM 憑證用於 Windows 目標,使用者通常只填打算掃的那一組),GCB 會是第二個——所以做成宣告驅動的平台能力,而非在 code 裡寫 InSpec 特例。

關掉的兩個缺口

# 缺口 症狀 解法
測試連線不知道該用哪組憑證 BE test_connection() 下發的 probe 參數只有 {"host": ...}不含 transport;agent connector 的 _resolve_transport() 未指定時預設 SSH。只填了 WinRM 憑證的使用者按「測試連線」,收到「本任務的連線方式為 SSH(Linux 目標),但未填寫 SSH 稽核帳號」——訊息本身很清楚,但它回答的是使用者沒問的問題 新增 credential_group_schema 宣告欄位,FE 在測試連線對話框讓使用者明確選一組
設定頁 11 個欄位平鋪一列,看起來全部必填 使用者看不出「這 6 個一組、那 5 個一組,只填一組就夠」 config_field_schema 逐欄加 group + hint,FE 依宣告分區渲染

兩個關鍵設計決定(後續有人要改時要知道理由)

  1. 不做自動偵測,由使用者明確選。 「看使用者填了哪組就猜」在兩組都填齊時無從分辨——而那是真實情境(客戶同時有 Linux 與 Windows 目標)。猜錯產生的正是本案要消滅的誤導訊息。多問一題的代價遠低於答錯一題。 未選定時測試連線鈕保持 disabled,不落回預設值;宣告了組別卻沒選 / 選了不存在的 key 一律明確回失敗,不預設挑第一組,也不記 last_test_result(沒真的測過)。
  2. FE 只送組別 key,probe 參數由 BE 依自己的 DB 宣告組出。 request body 只收 credential_groupFE 不得帶 probe 參數的 key 或 value——probe 參數會一路流到 agent connector 決定程式路徑(其他工具則用來組檔案路徑),讓客戶端自由命名參數等於開一個注入面。FE 側也不硬寫任何協定字面值(transport / SSH / WinRM),全部由後端宣告驅動。

Schema 形狀config.detection_tools.credential_group_schema JSONB NULL,{probe_param_key, prompt_label, groups:[{key, label, description, probe_param_value}]}

為什麼不塞進 config_field_schema:那是一個 JSONB 陣列,加頂層 metadata 會把形狀從陣列變成物件,所有讀取端都要跟著改

零影響保證NULL / 缺席=該工具無互斥組別,測試連線與設定頁行為與今日完全相同。三環境實查:只有 inspec 有宣告,其餘六筆(openvas / nessus / sonarqube / openscap / zap / nmap)全為 NULL——既有工具零影響。

agent 側零 code 異動——_resolve_transport() 本來就吃 probe params,缺的只是 BE 沒傳。agent 2c64a3b 只補了端到端釘樁測試防迴歸。

1.8 🟢 實測進展(2026-07-31 第三次更新,本輪最重要的一節)

§5 第 0 項那條「InSpec 與 Nmap 兩條線零實跑驗證」的風險,本輪已部分消解。尚未實跑過真正的掃描(run()),只驗到 probe(測試連線)

項目 結果 意義
DEV agent 已建到 0.2.14 並部署 image build 通過
CINC 確實裝進 image/usr/bin/cinc-auditor 實查存在) T-2.2 最大的未驗證假設已證實正確 Dockerfile 的 CINC 安裝指令從沒 build 過、omnitruck 腳本參數與安裝路徑都是照官方文件推測的——§5 第 0 項的假設 ① 已消除
WinRM 測試連線通過(對 192.168.50.160 Windows 主機) D6 雙 transport 的 WinRM 半邊已驗證——連線、認證、憑證解析整條 probe 鏈路可運作
SSH 測試連線卡在 sudo ⚠️ 環境問題,非 code 問題 錯誤訊息:sudo: I'm sorry audit-scan. I'm afraid I can't do thatSSH 連線與認證都已通過,卡在目標主機的 audit-scan 帳號沒有 NOPASSWD sudo 權限。決策者正在目標主機上設定
run()(真正的掃描) 從未跑過 這才是驗收的主體——CM-974 卡上那五條未驗證假設(reporter json 輸出位置 / 報告結構 / 退出碼語意 / exec 參數形式 / SIGTERM 行為)全部仍未驗證。尤其第 2 條「報告結構不符會統計全零但證據照常上傳」,只有實跑才看得出來
Nmap 整條線 仍零實跑 connector 與 seed 都完成,但沒對真實網段掃過

接手時的正確認知probe 通過 ≠ 這條線可用。 probe 只驗了「連得上、認證過、引擎在」;run() 才驗「profile 跑得動、報告解得開、統計數字對、證據上得去」。不要因為看到「WinRM 測試連線成功」就把 InSpec 當成驗完了。


§2 本棒的教訓(可複用,不是流水帳)

2.1 subagent 自報完成不等於正確

本棒每一次都實際開檔 / 查 DB / fetch Notion 抽查,而且每次都抓到東西:漏傳 code 的第二條路徑、required 旗標與 agent 端檢查不一致、SPA 後果記載與實測不符。

「Notion 卡改成修正待驗證」與「commit 進來了」都只證明有人做了事,不證明做對了。 抽查的成本遠低於錯誤流到下一批的成本——修正① 那個漏掉的 probe 路徑若沒抽到,會在第二、三批各自的測試連線功能上重現一次。

2.2 推測要標明是推測,並容許被實測推翻

does_not_exist 那次,主 session 的初始假設是「contextid 不存在」,被實作 session 的實測推翻了(真根因是爬取狀態誤判的三層鏈,見 §3.2 修正③)。

那是對的做法。 協調者離現場遠、看到的是二手轉述,猜錯很正常;問題只在「有沒有把猜測講成結論」。派工時把假設標明為假設、要求對方以實測為準,比堅持自己的判斷有價值得多。

2.3 「錯誤延後到最貴的地方才爆」是本案反覆出現的模式

三個修正都是同一個形狀:

問題 錯誤原本在哪裡爆 修正後在哪裡爆
ZAP 登入四欄 required 不一致 agent 執行期(派工後 5 分鐘) FE 表單存檔當下
probe 漏傳 tool code 測試連線時靜默走 fallback payload 缺欄位即可查
does_not_exist 三層鏈 查狀態時回一個看不懂的字串 scanAsUser 回非數字即刻拋錯

每次修正都一併補上「在發生當下就明確報錯」的機制,不是只把當次症狀壓掉。這個模式在第二批的 T-2.2 也被延續了——connector 的 probe() 第 ① 段就是憑證完整性檢查,訊息指名道姓說出缺哪個 transport 的哪一欄(見 §7.3)。

這是本案最該帶進第二、三批的一條:審核任何實作時都問一句「這個錯誤最早能在哪裡被發現?現在是在那裡被發現的嗎?」

2.4 文件與實測不符時要主動更正,不能留著

SPA 那次,原記載「掃出空報告」與實際「打掛共用 ZAP」的嚴重度差了一整個等級——前者是報告品質問題,後者是營運級風險。不改的話會在交付時給客戶錯誤資訊。

發現既有記載被實測推翻,當下就更正 design.md / setup_guide / Notion 三處,不要留到收尾一起做——中間任何人讀到那份文件都會拿到錯的認知。

2.5 非決策類工作一律派 subagent

本棒自己只做:讀 / 判斷 / 拍板 / 派工 / 抽查。以下全部派出去:

  • 跑測試、重建 image、部署 agent、套 migration
  • 寫文件(design.md 改案段、派工交接文件、discussion.html 更新)
  • Notion 回寫(卡片狀態、「已完成修正」補充說明)
  • Artifact republish

派 subagent 時一律不帶 model 參數(繼承 1M context model);文件產出類必須在派工單就寫明「分段寫檔:先 Write 骨架再多次 Edit,不要一次寫完整份」——本專案已三次遇到 subagent 一次寫大檔時 API 中斷。

2.6 昂貴前置只付一次(本棒沿用並強化的紀律)

重建 agent image + 部署 + 等 300 秒心跳是整個流程最貴的動作。本棒的做法:

  • 第一批驗收只部署 DEV(123),121/122 留到全案驗完再一起更(見 §1.5)
  • 第二、三批的端到端驗收整批延後到全案最後,做中只做便宜檢查(import / 語法 / mock 單元測試 / SQL 套 DEV 後 SELECT)

唯一的例外是 T-2.2——見 §4.1,那是刻意破例,理由是地基風險不對稱。

2.7 🆕 「部分功能生效、部分沒有」=新舊欄位混合的徵兆,先查 BE 有沒有重啟

2026-07-31 第三次更新新增。這是本輪排查花掉最多冤枉時間的一次。

經過:§1.7 的憑證分組功能做完後,畫面上分組標題沒出現。查了 FE(渲染邏輯正確)、DB(credential_group_schema 有值)、migration(三環境都套了)——全部正常

真根因:BE 行程沒重啟。 credential_group_schema 是當天 10:51 才加進 serializer 的,而 BE 行程是前一晚 23:58 起的。main_app.pyuse_reloader=False不會自動重載——跑的還是舊 serializer,API response 裡根本沒有那個欄位。

症狀特徵非常有辨識度,值得記住

現象 讀哪個欄位 舊 serializer 有嗎
hint 有顯示 config_field_schema(既有欄位,本次只加了 group / hint 兩個 key 進去) 有 → 照常回
分組標題沒顯示 credential_group_schema本次新增的欄位 沒有 → response 缺這個 key

可複用的判斷法同一個功能「部分生效、部分沒生效」,而兩者的差別剛好是「讀既有欄位 vs 讀新增欄位」——先去看 BE 有沒有重啟,不要先懷疑 FE 或 DB。 純新功能整個沒反應反而容易想到重啟;這種半生效的形狀最會誤導人往下游查。

紀律改 serializer / ORM model / entity / mapper 之後,BE 一定要重啟kill -9 舊 pid 再起,orphan pid 會卡 port 8000)。這條在 CLAUDE.md 已有規範,本輪是實際踩到的案例。


§3 本棒完整經過(決策脈絡,讀懂了才接得住)

本節是本文最重要的一段。本棒沒有寫任何一行 code,做的全是判斷與拍板;但這些判斷改了設計、改了文件、也改了下一批的做法。冷接時若只看 git log 會完全看不出這些

3.1 D4 改案:ZAP 證據由 PDF 改 HTML

觸發點:agent 側實作 ZAP connector 時,實作 session 回報原定案的 reports.generate 走不通——該 API 只把報告檔案寫進 ZAP daemon 主機的磁碟、回傳一個路徑字串,官方沒有「把檔案內容回傳給呼叫端」的端點(ZAP issue #7821 明確記載)。

為什麼這是硬阻礙:D3 已定案 ZAP 走「客戶自備 daemon、agent 只負責連上去」的遠端部署模型。在那個模型下,報告落在 ZAP 主機的檔案系統上,agent 根本拿不到

拍板:改走 core.htmlreport() + core.jsonreport() 雙格式——兩者都回傳 bytes,agent 拿得到。HTML 上傳當證據(檔名 ZAP掃描報告_<target>_<date>.html),JSON 只在記憶體解析 summary 不上傳。精神對齊 OpenVAS connector 既有模式,ZAP 端零設定,D3 部署模型不動。

被排除的方案

方案 排除理由
PDF + 要求客戶開檔案傳輸通道(SMB / SFTP 取 ZAP 主機檔案) 違反 D3 部署模型——把「只要能連上 API」變成「還要開一條檔案通道」,增加客戶部署負擔與資安面
檔案傳輸為主、HTML 退回 雙路徑的維護與測試成本,換來的是一條罕用的退路,不划算

接受的代價:HTML 證據可下載、不可預覽(證據池的預覽器不吃 HTML)。第一批以此為出貨標準;日後若要預覽,可在 agent 端用既有 LibreOffice 轉 PDF 補上。

已同步:design.md D4 + 變更紀錄、discussion.html、Notion CM-957/966/969、Artifact 線上版。

3.2 第一批端到端驗收與過程中修掉的三個問題

兩個實作 session 完成後,重建 agent image 0.2.12只部署 DEV(123)——決策者裁示 DEV 驗完才輪 121/122,不重複付部署成本(見 §1.5)。驗收過程中發現並修掉三個問題:

修正① probe 漏傳 tool code(BE 082a02d8

T-X.1(派工 payload 夾帶 detection_tool_code)只改了心跳派工那一條路徑,漏了「測試連線」這第二條——雲端直推 agent 的 agent_probe_client.py。結果是測試連線時 agent 收不到 code,退回 id fallback。

通則化教訓:雲端 → agent 有三條通道——① 心跳領工、② probe 直推、③ cancel 直推。往派工 payload 加欄位時要逐條檢查,不能只改最顯眼的那一條。

修正② ZAP 登入四欄 required 與 agent 端檢查不一致(BE 2d14ccb7

seed 把登入四欄(login_url / login_username / login_password / logged_in_indicator)標成 required: false,但 agent 執行時把它們當必填擋。使用者在 FE 表單留空可以存檔、可以派工,要等到 agent 跑起來才爆

改法:改為條件必填(靠 condition 控制——選了「登入後主動」才變必填)。三環境已套(fr058-2 migration)。FE 那側同時補了任務參數存檔的必填驗證(FE 8220852),把錯誤從 agent 執行期提前到表單。

修正③ ZAP 主動掃描 does_not_exist(agent 1feb6c7

這是本棒最有價值的一次追查,而且推翻了主 session 自己的初始假設。

主 session 看到 does_not_exist 的第一反應是「contextid 不存在」。實作 session 實測後回報不是,真根因是一條三層鏈:

發生什麼
ajaxSpider.status全域狀態、不吃 scan id。發出爬取指令後、ZAP 還沒把狀態翻成 running 的空檔,connector 讀到的是上一次殘留的 stopped,於是誤判「已經爬完了」
爬取實際上沒跑,站台樹是空的。此時呼叫 scanAsUser 會回 HTTP 200 + 一個錯誤字串(不是拋例外、不是非 200)
那個錯誤字串被當成 scan id 收下,拿去查狀態 → 回 does_not_exist

修法:白名單式回傳值驗證——scan id 只接受純數字,非數字一律當錯誤即時拋出。

附帶抓到的第二個 bugsetForcedUserModeEnabled(True) 開了沒關,而那是 ZAP daemon 的全域開關,會造成跨任務污染(下一個任務莫名以某個 user 身分發請求)。一併修掉。

修正後 bump 0.2.13 並重新部署 DEV。

3.3 SPA 登入掃描的設計缺口(D12)——本棒發現的最嚴重問題

第一階段發現(設計缺口):實測揭露 param_schema傳統表單登入模型對 SPA 天生不成立,三個原因彼此獨立、必須同時解決才會通:

# 現象 根本原因 SPA 需要的做法
填了帳密但 ZAP 從未登入成功 SPA 的登入是 JS 呼叫 API 取 token,頁面上沒有傳統表單提交可供 ZAP 對付 json-based 認證
就算登入成功,後續請求仍是未登入身分 SPA 多用 JWT 存 localStorage、靠 Authorization header 帶;ZAP 預設 session 管理是 cookie-based script-based session management
ZAP 誤判未登入、反覆重跑登入 logged_in_indicator 比對的是 HTTP 回應的原始內容,SPA 初始 HTML 是空殼、登入後文字要 JS 渲染才進 DOM 改用 API 回應特徵等非 DOM 判定

拍板(D12):本案不做半套,列後續另案 Notion CM-984。理由是沒有中間地帶——只做 json 認證不做 session 管理,結果是認證送出去了但 token 帶不進後續請求,掃描結果與完全不做相同,卻已付出工程成本並在 UI 上留下「看起來支援了」的誤導。

第二階段:後果比原記載嚴重得多(BE 2581b4f6 更正)

原文件寫的是「掃描仍會完成、只是涵蓋範圍侷限於登入前頁面」。這是錯的。 後續實測發現第 ③ 項的重跑登入是無限迴圈,認證失敗持續累積,達到 ZAP 2.17.0 Insights 機制門檻後 ZAP daemon 主動關閉自己

Shutting down ZAP due to High Level Insight: HIGH : EXCEEDED_HIGH :
  http://<target> : insight.auth.failure : 100
→ Discard Session → ZAP 2.17.0 terminated. → zap exited with code 2 (restarting)

而 ZAP 是全租戶共用服務——單一 SPA 登入任務會連帶打斷同一台 ZAP 上其他正在執行的掃描(實測同時發生:另一任務在 ZAP 重啟空檔收到 Connection refused)。這已不是報告品質問題,而是營運層級風險

範圍界定(重要,不要誤擴大)僅限登入後掃描模式。被動與主動模式不建 context、不設認證、不比對特徵字串,不累積認證失敗,碰不到 Insights 門檻。

連帶處置setup_guide 從「登入後掃描僅支援傳統表單登入」改為明確的「請勿對 SPA 使用登入後掃描」(fr058-4 migration);design.md D12 補完整因果鏈與 log 摘錄。

connector 端自我保護(偵測認證失敗異常累積時主動中止)決策者裁示「只記錄不實作」——列為待辦,見 §5。

3.4 第一批最終驗收結果

掃描模式 結果 說明
被動掃描 ✅ 通過 HTML 證據正常進證據池,summary 有 alert 統計
主動掃描 ✅ 通過 修正③(does_not_exist 三層鏈)後重測通過
登入後掃描 ❌ 不適用 SPA 不支援,且會打掛共用 ZAP(§3.3)。已記錄為 CM-984 後續案

第一批實質完成。 任務層敏感參數(FR-058.0)的三處剝除、ID 解耦(D11)、既有工具迴歸皆已驗過。

3.5 產第二批與第三批派工文件,兩批並行派出

第一批收口後,產出兩份派工交接文件並同時派出:

  • handoff/2026-07-30-fr058-batch2-dispatch.md(InSpec/CINC → GCB,7 個子任務序列執行)
  • handoff/2026-07-30-fr058-batch3-nmap-dispatch.md(Nmap,3 個子任務)

兩份都帶了「第一批帶來的新事實」段(factory 已改依 code 取、payload 已夾帶 code、敏感參數平台能力已就緒、D4 教訓通則化),以及跨批共用檔的協調規則。

3.6 D9 改案:Nmap 由 CLI 型改 SSH 型

觸發點:第三批實作前發現原設計自相矛盾——D9 原定 Nmap 走 connection_type='CLI'(agent 本機執行子行程)、不 bundle 進 image、由客戶自備。但 agent 跑在 Docker container 內,看不到主機上安裝的 nmap(容器有獨立檔案系統)。「不 bundle」與「不能裝進容器」兩個條件互相矛盾,原設計在容器化部署下根本無法成立。

查證 NPSL 後確認不能 bundle,而且理由比原記載強得多。 原文件只記了「NPSL 授權」四個字。實際查 NPSL v0.95 §3(https://svn.nmap.org/nmap/LICENSE),衍生作品定義明文列舉這一條:

Is designed specifically to execute Covered Software and parse the results (as opposed to typical shell or execution-menu apps, which will execute anything you tell them to).

我們的 connector 正是「專門呼叫 nmap 並解析其 XML 輸出」,正中此條。因此 GPL 慣用的「只用子行程呼叫、不連結函式庫所以不算衍生」這個免責論點在 NPSL 底下不成立——該條款是特意加來堵掉這個論點的(NPSL 基於 GPLv2 但加了額外限制)。

但同一條款末段留了出口:軟體若執行的是「使用者早已安裝在自己系統上的 nmap」,授權方不主張控制(Licensor does not purport to control through this license any software which does not require the rights granted herein)。SSH 型正好落在這個描述裡——nmap 是客戶裝在自己主機上的,我們只是遠端下指令。

拍板:Nmap 改走 connection_type='SSH',與已上線的 OpenSCAP 同構。

被排除的方案

方案 排除理由
掛載主機 binary 進容器(-v /usr/bin/nmap:... + 共享函式庫目錄) nmap 非靜態連結,依賴 libssl / libpcap / liblua 一串共享函式庫;掛主機 lib 進容器是跟 glibc 版本賭運氣,還可能蓋掉容器自身函式庫把 agent 弄壞。架構也綁死 x86_64
客戶自建一層 image(以我方 image 為 FROM,自行 apt install nmap 技術與法律上都成立,但客戶每次 agent 升版都要改 Dockerfile 重 build,是持續性負擔;且「誰裝進去的」雖是法律關鍵,技術結果與我方 bundle 完全相同,這種形式上的區隔在交付溝通上彆扭
購買 Nmap OEM 授權 本案不採,未評估成本。若日後產品策略需要零客戶設定的 nmap 整合,這是唯一能 bundle 的合法途徑,列為備查

連帶影響:nmap 改為 requires_credentials=TRUE(DB 實查已確認,見 §1.3);T-4.1 的零憑證放行平台能力保留(是平台級能力,只是換掉第一個使用者);connection_type='CLI' 至今仍無實際使用者;agent connector 範本從「本機子行程」改為對照 openscap.py 的 SSH 多目標模式。

已寫進 design.md D9 + 變更紀錄(8ac863cf),第三批派工文件亦含完整論證。


§4 開工順位

🔴 本節於 2026-07-31 稍晚重大改寫。 舊版 §4.1 的「先人工驗收 T-2.2 才放行 T-2.3」已被決策者取消——改為一路往下跑、驗收整批併到最後。T-2.3 因此在未驗收 T-2.2 的情況下就已完成(eb352a7)。不要照舊版執行那道 gate

4.1 🔴 下一個動作:接續 InSpec + Nmap 合併驗收(通過才做 GCB 三棒)

🟢 2026-07-31 第三次更新:這一輪已經開始跑了,不是「尚待執行」。 已完成的部分見 §1.8——DEV 已建到 0.2.14、CINC 確認裝好、WinRM probe 已通過。下方的「環境資訊索取表」大部分已取得。

目前的三個卡點(接手就是處理這三件)

# 卡點 性質 處置
SSH 側 probe 卡在 sudo——sudo: I'm sorry audit-scan. I'm afraid I can't do that 環境設定問題,非 code 問題(SSH 連線與認證都已通過) 決策者正在目標主機上設 NOPASSWD sudo。設好後重測 probe 即可,不需改 code。⚠️ 順帶注意 §5 新增項:connector 的 use_sudo 只是布林、不支援 sudo 密碼,所以只能走 NOPASSWD
FE 測試連線 Dialog 兩欄改版進行中ToolPluginManage.vue working tree 未提交) 進行中的 UI 改版 改版完成並 commit 後才做驗收——否則驗的是中間態。詳見 §5 新增項
run() 從未實跑 這才是驗收的主體 probe 通過只證明連得上;CM-974 那五條假設全靠 run() 才驗得到

若決策者對某項環境資訊尚未提供,接手第一件事就是把它再提一次。

為什麼合併成一輪:InSpec 與 Nmap 的實機驗收共用同一批昂貴前置——重建 agent image(0.2.14 同時含兩者)、部署到 DEV、BE 重啟。兩條線在同一次部署裡就能測完,分兩次做等於把最貴的部分付兩遍(沿用 §2.6「昂貴前置只付一次」的紀律)。

為什麼 GCB 三棒要等這輪過了才做GCB(FR-058.3)完全建立在 InSpec 引擎上(D7:GCB 不另立引擎、不另寫 connector)。InSpec 那條線至今零實跑驗證,地基沒驗就往上蓋三棒,風險不對稱——驗一次的成本是一兩小時,地基有錯而三棒要重來的成本是好幾倍。這一層理由與舊版 §4.1 相同,只是 gate 的位置從「T-2.2 之後」移到「InSpec 整條線之後」。

執行前需要決策者提供的環境資訊(沒有這些就跑不了)

多數已取得,本表改為現況對照(2026-07-31 第三次更新)。

需要什麼 用途 現況
一台 Linux 主機(IP + SSH 帳號 / 私鑰或密碼) InSpec SSH transport 實跑;也可兼作 Nmap 的執行主機(需裝 nmap) 已有,SSH 連線與認證已通過。⚠️ 卡在 audit-scan 帳號沒有 NOPASSWD sudo,決策者處理中
一台 Windows 主機(IP + WinRM 帳號密碼) InSpec WinRM transport 實跑 已有並已驗過——192.168.50.160,WinRM probe 通過
Nmap 掃描目標(可掃的內部 IP / 網段) Nmap run() 實跑 尚未取得 / 尚未實跑。⚠️ 只掃自己控制的內部網段,掃描會產生真實網路流量

⚠️ 憑證模型的澄清(決策者曾誤解,寫在這裡避免重複)一組憑證套用到所有目標主機——每台目標建同名帳號、放同一把公鑰、同樣的 sudoers 規則;任務的「掃描目標」欄位逗號分隔多台。這不是跳板模式:agent 直連每一台(OpenSCAP 與 InSpec 的 run() 都是 for host in hosts 逐台連,中間沒有任何中繼主機)。

「每台主機帳密不同」的情境要走 FR-058.0 任務層敏感參數本案未做(D6 定案:預設走租戶層共用一組)。這也是 Tenable 官方《Credentialed Checks on Linux》的業界標準做法,FR-057 母卡已有記載。

驗收要點(依 Notion 卡自報的「未驗證假設」逐條對照)

InSpec / CINC(CM-973 T-2.2 + CM-974 T-2.3)

  • image build 是否過已驗(§1.8)——0.2.14 build 通過、/usr/bin/cinc-auditor 實查存在。這條原本是全案最大的推測項,已證實正確
  • container 內 cinc-auditor 可執行,且版本輸出確認是 CINC 而非 Chef InSpec(授權紅線 D5,不要只看「裝得起來」就過)—— ⚠️ 仍要確認版本字串,「檔案存在」不等於「是 CINC 不是 Chef」
  • 測試連線四情境各回不同訊息(憑證缺漏 / 引擎缺失 / 連不上 / 認證失敗)—— 🟡 部分已驗:WinRM 側通過(§1.8);SSH 側卡 sudo(環境問題)待重測
  • 🔴 run() 是本輪驗收的主體,至今零實跑——下方那條「CM-974 五條假設」全部靠它
  • CM-974 卡上列了五條未實跑驗證的假設,逐條對照。其中第 2 條最危險:報告結構若不符,統計數字會全零但證據照常上傳(刻意的容錯)——這條最可能出錯又最不明顯,驗收時務必看數字對不對,不要看到「有證據進池」就算過
  • probe() 不在目標主機留下殘留檔案;/dev/shm 暫存檔用完即刪

Nmap(CM-983 T-4.3)——這條線是 D9 改案後全新寫的 SSH 型,同樣零實跑:

  • 手動派工掃真實網段 → XML 報告進證據池、summary 開放埠數不是 0 / 不是空
  • 執行主機未安裝 nmap 時,測試連線回明確訊息(不是 exit code 127
  • 執行中按取消能即時中止,遠端不留孤兒行程與暫存檔
  • 兩台執行主機其中一台連不上 → 另一台仍成功,失敗台被明確回報(非靜默假成功)
  • 檢查 Dockerfile 內確實沒有 nmap(NPSL 授權紅線)
  • 🆕 證據是人可讀 HTML 而非 XML——agent 087fa41 已改(容器內 xsltproc + 官方 nmap.xsl 轉換,XML 僅在記憶體算 summary)。此改案未經派工、需決策者追認(§5 新增項);驗收時確認 ① HTML 在證據池可下載 ② summary 的開放埠統計仍正確(改版後 summary 改吃記憶體中的 XML,是新路徑)

🆕 併進本輪的第三件事:T-3.2 的 content 來源實跑驗證(§7.4 裁示)——T-3.2 已縮成「驗證 + 寫文件」,但不是無條件:agent image 沒裝 git,「裸 GitHub URL 走 tarball 還是 git fetcher」從未驗證過。這件事要在本輪一起實跑掉,不要等 T-3.1 才發現走不通。

通過後:才放行 GCB 三棒(T-3.1 → T-3.2 → T-3.3)。

4.2 剩餘四棒與執行順序

決策者裁示:人工監控,不做鏈式自動接力。 每一棒完成後由協調者抽查 + 放行下一棒,不設自動觸發。

內容 前置
T-2.4 結案 Notion CM-953(純 Notion 動作,無 code) T-2.3 ✅ 已完成,隨時可做,不必等驗收
T-3.1 GCB seed(工具目錄 + param_schema + setup_guide) 建議等 §4.1 驗收過
T-3.2 GCB content 外部載入接口已縮成「驗證 + 寫文件」(§7.4 裁示;CINC 原生支援三種來源,不需另做抽象層)。但實跑驗證併進 §4.1 那一輪,不是無條件放行 T-3.1(驗證部分提前到 §4.1)
T-3.3 Windows 最小 Demo profile T-3.2

GCB 三棒序列不可對調(.3 硬依賴 .2 的 connector)。抽查重點沿用 §2.1〜2.3:實際開檔看、對照卡片驗收條件逐條核、問「這個錯誤最早能在哪裡被發現」。

4.3 全案完成後的最終端到端驗收

§4.1 那一輪是針對 InSpec + Nmap 兩條線的地基驗證,不取代全案最終驗收。全案(含 GCB)完成後仍要:

  • 三環境套齊所有 migration(目前九支已完成,見 §1.4——接手時仍要重查是否有新的 migration 未套
  • 重建 agent image 到屆時版號(目前 0.2.14,GCB 完成後可能再 bump),部署三台(121 POC / 122 STG / 123 DEV)
  • BE 重啟、FE 部署
  • 跑 design.md §6 的端到端驗收九項

指令可直接照抄前一棒交接文件的 §6 pre-flight 與 §3 情境 A 的 A.1 前置環境準備handoff/2026-07-30-fr058-planning-complete-handoff.md)——那些指令仍然有效。§4.1 那一輪也用同一批指令,只是部署範圍可先限縮到 DEV 一台。

4.4 收尾項(全案驗收通過、決策者下令才做)

項目 內容 Repo
T-9.1 WorkflowSetupEditor.vue 的硬編死碼工具清單 toolsMenu = ["Nessus","Nmap","OWASP ZAP","Wireshark"](與 detection_tools 完全脫鉤;本案加入 ZAP 與 Nmap 後畫面上兩處都出現,其中一處是死的) FE
T-9.2 docs/claude/database-schema.md 的 config schema 與 detection 三表記載(目前 grep 零命中) BE
agent 部署 121 POC / 122 STG 補到最新版(目前停在 0.2.11 部署
push 三 repo 全部未 push,等決策者明示 三 repo
discussion.html 更新 內容已多處過期,見 §5 BE

§5 已知待辦與風險

# 項目 嚴重度 說明與處置
0 🟡 InSpec 與 Nmap 的實跑驗證——已部分完成,run() 仍零實跑(2026-07-31 第三次更新降級,原為「高、零實跑」) 中高(原為高) ✅ 已消除的假設 Dockerfile 的 CINC 安裝——image build 通過、/usr/bin/cinc-auditor 實查存在(§1.8),這條原本是全案最大的推測項;WinRM probe 也已對真實主機通過。🔴 仍未驗證的 CINC 的 --reporter json 輸出結構與 CLI 行為,T-2.3 的解析全建立在假設上(CM-974 卡列了五條,第 2 條「報告結構」出錯時會統計全零但證據照常上傳,最不明顯)——run() 從未跑過,這五條一條都沒驗到 Nmap connector 走 SSH 型是 D9 改案後全新寫的,同樣沒對真實網段跑過。處置:§4.1 那一輪繼續跑完,重點已從「連得上嗎」移到「掃得對嗎」
1 三 repo 全部未 push BE 17 / FE 5 / agent 10 個 commit 領先 origin(2026-07-31 第三次更新實查)。決策者已明確裁示:push 暫緩到全案驗收通過(§7.6)。風險是本機硬碟成為唯一副本——全部實作成果目前只存在本機
2 BE pyproject.toml 多了 zaproxy 相依 已消失 2026-07-31 第三次更新實查:pyproject.toml 已無 zaproxy(grep 零命中),working tree 也不再有該檔的 modified。本項不需處理
3 connector 端 ZAP 自我保護未實作 低(已知) 偵測認證失敗異常累積時主動中止掃描,避免打掛共用 ZAP(§3.3)。決策者裁示「只記錄不實作」——目前靠 setup_guide 的「請勿對 SPA 使用登入後掃描」防守
4 CM-984(SPA 登入掃描支援)為後續需求 Not started。需要「json 認證擴充 + script-based session 管理 + SPA 測試站台」三件事。⚠️ 實作時注意 ZAP script engine:Oracle Nashorn 在 JDK 15 後已移除、新版預設 Graal.js,舊參考碼 zap_auth.pyjava_script() 還停在 Nashorn
5 **DEV 主機 docker-compose.yml 第 14 行 fallback 停在 0.2.8 極低 實際版本由 .envAGENT_IMAGE 決定(實查 DEV .env0.2.13、實跑也是 0.2.13),無實質影響**。但過時的 fallback 值有誤導風險,日後順手更新即可
6 FE 必填驗證的 falsy 邊界 極低(已註記) helper compliance-manager-fe/src/utils/detectionFieldValidation.js 空值判斷用 !value,刻意與 DetectionConfigField.showError 同源。目前 param_schema 只有字串型必填欄位,不含 number / boolean,故不會誤殺 0 / false。⚠️ 日後若出現 required 的 number / boolean 欄位就會誤判為缺漏——檔頭第 34–37 行已有註解記載
7 121 / 122 agent 停在 0.2.11(123 DEV 已更新到 0.2.14 低(刻意) 決策者裁示 DEV 驗完才輪,不重複付部署成本。第三次更新已把 DEV 建到 0.2.14(舊記載「三台都沒有 0.2.14」已過期);121 / 122 等全案驗收時一併更新(§4.3)
8 discussion.html 內容多處過期 實查:D12 零命中、SPA 零命中、requires_target_host 零命中,NPSL 僅 1 處(D9 改案前的舊記載)。即第一批實測發現與 D9 改案完全未反映。更新時 ⚠️ 不要動 mermaid 圖首行的 %%{init:...}%%(那是三次踩坑後的解,Artifact 雲端不執行頁面 script,只有內嵌 init 字串有效)
9 有一個 session-only 的凌晨排程在檢查 T-2.2 進度 已失效 2026-07-31 稍晚更新:此條已無意義。 決策者已取消 T-2.2 的驗收 gate(改為一路往下跑、驗收併到最後),T-2.3 也已完成。該排程隨 session 關閉消失,不需處理
10 _pick_agent 無負載平衡 / tenant_config_id 從未被寫入 / 證據關聯靠 description 字串前綴 低(既有技術債) 本案不處理,加工具不會惡化。記在 design.md §3 技術債表
11 🆕 「目標主機」文案語意模糊——使用者分不清主動方是誰 (實測當場發生) CINC 是 agent 主動連出(agent 裝引擎 → 連到目標主機執行),與 OpenSCAP 引擎裝在目標主機的模型相反。實測時決策者實際誤填了 agent 自己的 IP(123)而非要掃的目標(151)——這不是使用者疏忽,是文案沒說清楚主動方。兩處都要改寫:① 測試連線對話框的說明文字 ② 錯誤訊息「檢測引擎連線 X 失敗」——這句聽起來像「引擎在 X 上出問題」,實際語意是「從 agent 連到 X 失敗」。尚未修,待排
12 🆕 **FE 測試連線 Dialog 呈現改版進行中(未提交) 中(進行中) 決策者拍板把憑證分組從垂直堆疊改成左右並排**(Dialog 加寬約 52rem、兩欄 grid、窄螢幕 fallback 單欄)。FE session 進行中compliance-manager-fe working tree 的 src/views/plugin/ToolPluginManage.vue 就是這個。接手時不要動那個檔、不要 commit。⚠️ §4.1 的驗收要等這個改版完成才做,否則驗的是中間態。排除了 Tab 方案,理由記在 §7 之後的小節
13 🆕 connector 的 use_sudo 只是布林,不支援 sudo 密碼 只能走 NOPASSWD sudoCINC 本身支援 sudo_password,是我們的 schema 沒開這個欄位。企業稽核帳號通常就是設 NOPASSWD(業界標準做法),故不緊急;但客戶環境若不允許 NOPASSWD 就會卡住。本案不做,記錄待日後評估。⚠️ §1.8 的 SSH probe 卡點正是這個限制的直接後果
14 🆕 Nmap 證據改存 HTML——未經派工的自主改案,待決策者追認 中(流程項) agent 087fa41:改存人可讀 HTML(容器內 xsltproc + 官方 nmap.xsl 轉換),XML 僅在記憶體算 summary。技術方向與 D4(ZAP 證據 PDF→HTML)同精神——證據要人可讀,合理。但這是實作 session 自行決定做的,協調者沒派過這一棒接手時提請決策者確認是否追認;若追認,需一併確認 ① 是否要比照 D4 在 design.md 記一筆改案 ② 是否要開 Notion 卡。驗收要點見 §4.1
15 🆕 **GCB content 來源的兩個限制(已裁示開後續卡,不在本案做) 低(已裁示) ① 封閉網路客戶只能用本機路徑**,但目前沒有把 profile 檔送進 agent container 的機制;② 私有 repo 無憑證路徑——params.profile非 secret 的純文字欄位,沒地方放 token。兩項都不在本案 scope(§7.5 裁示),開後續卡記錄即可

§6 Pre-flight Command(必跑)

# ① 三 repo branch / 領先數 / HEAD(⚠️ 兩批實作 session 仍在跑,數字一定與 §1.1 不同)
for r in compliance-manager-be compliance-manager-fe ../evidence-agent; do
  d=~/Projects/Billows/Audit-Manager/$r
  [ -d "$d" ] || d=~/Projects/Billows/Audit-Manager/evidence-agent
  echo "=== $d ==="
  git -C "$d" branch --show-current
  git -C "$d" rev-list --left-right --count origin/feature/FR-058...HEAD   # 左=origin 領先、右=本地領先
  git -C "$d" log --oneline origin/feature/FR-058..HEAD | head -20
  git -C "$d" status --short | head -10
done
# 三者都應為 feature/FR-058;左邊一律 0(沒人 push)

# ② 三環境 detection_tools 對照(確認七筆、三環境 id 與旗標一致)
#    密碼請查 .env 的 DB_SECRET 或部署文件
for db in "192.168.50.188|guidant_ai_dev" "192.168.50.188|guidant_ai_stg" "192.168.50.189|guidant_ai_poc"; do
  h=${db%%|*}; n=${db##*|}
  echo "=== $n @ $h ==="
  psql -h $h -p 25432 -U cmmgr -d $n -c \
    "SELECT id, code, connection_type, status, requires_credentials, requires_target_host
       FROM config.detection_tools ORDER BY id"
done
# 基線(2026-07-31 實查):1 openvas / 2 nessus / 3 sonarqube / 4 openscap / 5 zap / 6 inspec / 7 nmap
# 🆕 第三次更新加查 credential_group_schema(§1.7):三環境皆「只有 inspec 非 NULL、其餘六筆 NULL」
#   SELECT id, code, (credential_group_schema IS NOT NULL) AS has_cred_grp FROM config.detection_tools ORDER BY id;

# ③ 已套 migration 清單(對照 §1.4;若有新檔案要確認三環境都套了)
ls ~/Projects/Billows/Audit-Manager/compliance-manager-be/scripts/sql/ | grep fr058

# ④ 三台 agent 部署版本(預期 123=0.2.14、121/122=0.2.11,後兩台刻意未更新)
#    ⚠️ 舊版此處寫 123=0.2.13 已過期——第三次更新時 DEV 已建並部署 0.2.14(§1.5 / §1.8)
for h in 192.168.50.121 192.168.50.122 192.168.50.123; do
  echo "=== $h ==="
  ssh -o ConnectTimeout=6 jedi@$h \
    "docker ps --filter name=guidant-ai-agent --format '{{.Image}}\t{{.Status}}'"
done

# ⑤ BE 服務是否在跑(port 8000)
lsof -i :8000 | head -3
# 沒有 listener 時:
#   cd ~/Projects/Billows/Audit-Manager/compliance-manager-be && nohup python main_app.py > /dev/null 2>&1 &
# ⚠️ main_socketio.py 是 socket(8002),不是 API 入口;重啟必先 kill -9(orphan pid 會卡 port)

# ⑥ BE log 掃一眼
tail -200 ~/Projects/Billows/Audit-Manager/compliance-manager-be/log/app.log \
  | grep -i 'Traceback\|ERROR' | tail -20

# ⑦ agent 測試(⚠️ 必須帶 PYTHONPATH=.,repo 缺 conftest.py)
cd ~/Projects/Billows/Audit-Manager/evidence-agent && PYTHONPATH=. poetry run pytest test/ -q | tail -5
# 基線:T-4.3 完成當下自報 342 passed, 1 skipped;T-2.3 完成當下自報「可收集的 181 項全綠」
# ⚠️ 兩個數字不可比:本機 paramiko / gvm 未安裝時,test_openvas/openscap/nmap/connector_factory
#    四支無法收集(既有環境問題,非本次異動)。裝了才收得到全部 342 項。

# ⑧ 規劃產出物完好(行數會隨改案增長,只確認檔案在)
wc -l ~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/FR-058-2607-detection-tools-expansion/{design.md,discussion.html}
# 2026-07-31 實查:design.md 512 行、discussion.html 1060 行

Notion 查詢注意:free plan 不支援 SQL 查資料源notion-query-data-sources 對任務清單 DB 回空陣列)。查卡片一律 notion-search 找到再 notion-fetch 開,或從母卡 CM-957 的子卡清單進入。


§7 第二、三批的協調裁示(已定,不要重新討論)

本節記錄本棒任內對兩批實作 session 提問所做的裁示。這些已經定案,接手後不要重新討論,但要知道理由才不會在後續實作中把它推翻。

7.1 InSpec 的 connection_typeSSH,transport 選擇放 param_schema

問題:InSpec 支援 SSH(Linux)與 WinRM(Windows)雙 transport(D6),detection_tools.connection_type 只能填一個值,該填什麼?

裁示:填 SSH。理由是該欄位的實際語意不是「這個工具怎麼連線」,而是「要不要在 UI 上問使用者測試主機」——它不對使用者顯示。真正的 transport 選擇放在任務層的 param_schemaparams.transport = ssh / winrm),因為那本來就是任務屬性而非工具屬性:同一租戶的 Linux 與 Windows 目標分屬不同任務(CM-953 已定的「一任務一工具、靠多任務處理異質環境」模型)。

連帶產物:這次討論暴露了 FE 在硬判 connection_type 來決定要不要顯示「測試主機」輸入框,語意耦合錯誤 → 促成 7.2。

7.2 requires_target_host 欄位由第三批做,第二批不重複走

問題:FE 判斷是否顯示「測試主機」輸入框時硬判 connection_type === 'SSH',語意錯誤且會隨工具增加而失準。要新增一個 requires_target_host 宣告欄位。這一棒該給誰?

裁示給第三批。理由是第三批的 T-4.1 剛走過 requires_credentials 的完整同構鏈(DB migration → ORM model → entity → mapper → serializer → orchestration service → FE),再走一次同形狀的鏈成本最低;第二批要從零理解那條鏈,成本反而高。

已完成:BE 9a15db96 + FE 2fe1ce6。三環境已套(fr058-7 migration),DB 實查已確認欄位存在且值正確(§1.3)。

7.3 第二批 T-2.1 的三個自主決定,經審核全部同意

實作 session 在 T-2.1(InSpec seed)中自主做了三個決定並回報請示,逐一審核結果:

# 自主決定 審核 理由
不新增 WinRM 值connection_type 枚舉 ✅ 同意 與 7.1 一致——該欄位語意是「要不要問測試主機」,WinRM 也要問,加一個值不會讓語意更準,只會多一個要維護的枚舉值
憑證欄位不做兩層條件顯示 ✅ 同意 FE 的 condition單層嚴格等值判斷。硬做兩層會導致「開關關掉時第二層仍依殘留值顯示」——使用者關掉 WinRM 卻仍看到 WinRM 的埠號欄位。這是 FE 實作的硬限制,不是實作偷懶
憑證一律非必填(SSH 一組、WinRM 一組都不強制) ✅ 同意**,但有配套** 哪一組是必要的取決於任務當下選的 transport,設定當下無從得知。硬性兩組都必填會逼只掃 Linux 的客戶填一組用不到的 Windows 帳密

③ 的配套要求(決策者明確加的,不是實作 session 自己想的)

缺哪一組憑證,必須由 T-2.2 的 probe() 回明確訊息(例如「本任務的連線方式為 WinRM,但檢測工具設定中未填寫 WinRM 帳號與密碼,請至檢測工具管理頁補齊」),不可退化成執行期才失敗

這個配套是 ③ 能成立的前提——沒有它,「設定時不擋」就等於「執行時才爆」,正是 §2.3 那個反覆出現的壞模式。

已落實:T-2.2(dcedb4f)的 probe() 第 ① 段即為憑證完整性檢查,訊息指名 transport 與欄位。connector 檔頭有完整註解記載此因果。後續若有人想「簡化」probe 的檢查順序,要知道第 ① 段是不能拿掉的。

7.4 🆕 T-3.2「content 外部載入接口」縮成「驗證 + 寫文件」——但非無條件

背景:D7 要求「content 不可硬編進 connector 或 agent image,必須可從外部載入」,原本規劃 T-3.2 要做一層載入接口。

裁示:不做抽象層,縮成「實跑驗證 + 寫文件」。 理由:CINC 原生就支援三種 content 來源——Git URL、本機路徑、Supermarket,而 params.profile直接進 exec 的 argv,等於外部載入能力已經在了,另做一層抽象只是把 CINC 的能力再包一次。

⚠️ 但這不是無條件放行——必須實跑證實才算數

  • agent image 沒裝 git
  • 「裸 GitHub URL 走 tarball fetcher 還是 git fetcher」從未驗證過——若走 git fetcher,沒有 git 就直接失敗

因此:實跑驗證併進 §4.1 那一輪(見該節「併進本輪的第三件事」),不要等 T-3.1 才發現走不通。驗完再寫文件。

7.5 🆕 content 來源的兩個限制:開後續卡記錄,不在本案做

7.4 的驗證會暴露兩個真實限制,兩者都不在本案 scope

# 限制 為什麼是真限制
封閉網路客戶只能用本機路徑,但目前沒有送檔進 container 的機制 「可以用本機路徑」這句話對封閉網路客戶是空的——檔案根本進不去
私有 repo 無憑證路徑 params.profile非 secret 的純文字欄位,沒地方放 token(要放就得走 FR-058.0 任務層敏感參數,那是另一件事)

裁示:開後續卡記錄即可,本案不做。 見 §5 第 15 項。

7.6 🆕 commit 標籤不一致不處理;push 暫緩到全案驗收通過

① commit 標籤不一致:本案的 commit message 標籤形式並不齊一(有的帶 cm-xxx、有的只帶 fr058,子任務編號標法也有出入)。裁示:已 commit 的訊息不改。 理由:rebase 改寫歷史的風險大於整齊帶來的收益——三 repo 都在同一個未 push 的 feature branch 上,改寫會牽動全部。日後的 commit 盡量對齊,但不回頭修。

② push 時機暫緩到全案驗收通過。這是對「push 永遠等決策者明示」的具體化——不是每一棒完成就 push,而是全案驗完一次推。接手時不要因為「commit 累積很多、怕硬碟壞」就自己 push(該風險已記在 §5 第 1 項,決策者知情並接受)。

7.7 🆕 測試連線 Dialog 為何用「左右並排」而非 Tab

決策者拍板:憑證分組從垂直堆疊改成左右並排兩欄(Dialog 加寬約 52rem,窄螢幕 fallback 單欄)。

明確排除了 Tab 方案,理由有二

  1. 兩組不是互斥選項,而是「填你需要的那些」。 混合環境的客戶(同時有 Linux 與 Windows 目標)兩組都會填。Tab 的視覺語意是「選一個」,與實際語意相反
  2. Tab 會把另一組藏起來,「填了沒」變成不可見。 使用者無法一眼確認自己填齊了哪些——而這正是 §1.7 缺口 ② 要解決的問題,用 Tab 等於換一種方式再犯一次。

⚠️ 注意這與「測試連線時要選一組」不衝突:設定頁是「填你需要的」(可兩組都填),測試連線是「這次要測哪一組」(必須擇一,因為一次 probe 只走一條 transport)。兩者的語意本來就不同,UI 也就不該用同一種形式。


§8 行為規範重要提醒

  • 不切 branch:任何 git checkout <branch> / git switch <branch> 一律不執行,永遠在 feature/FR-058 工作。發現 branch 不對停下問決策者,不自己 fix。「為了在正確 branch commit 而切 branch」也不允許
  • push 永遠等決策者明示,不自動 push(目前三 repo 全未 push)
  • 顯式 git add 檔名,禁用 -am——⚠️ 本案兩批實作 session 並行,且 BE working tree 有兩個不該一起進去的 modified(CLAUDE.md / pyproject.tomlzaproxy,見 §5 第 2 項),誤 add 風險特別高
  • 收尾必須等決策者下令:SPEC / SUMMARY / memory / Notion 母案收尾都是。plan approve ≠ 自動執行收尾
  • 憑證禁入版控:密碼、token、API key 絕不寫進任何會 commit 的檔案(含 SQL migration、docs、handoff)。需要連線資訊時只寫帳號 / host / port / db 名,密碼一律寫「請查 .env 或部署文件」
  • BE 出錯先看 log,不問決策者tail -200 log/app.log | grep -A 30 -i 'Traceback\|ERROR'
  • BE 起服務用 main_app.py(port 8000)main_socketio.py 是 socket(8002)不是 API 入口;重啟必先 kill -9
  • 文件產出類工作一律派 subagent,且派工單必寫「分段寫檔:先 Write 骨架再多次 Edit,不要一次寫完整份」(本專案已三次遇到一次寫大檔時 API 中斷)
  • 執行類工作發出去:跑測試、跑部署、重建 image 一律派 subagent,本棒不自己執行
  • subagent 一律用 1M context model不帶 model 參數
  • 測試一律 headless
  • 任務發佈後最長等 300 秒才會真的開跑——心跳週期造成的正常行為,不是故障。看到「按了沒反應」不要當 bug 追
  • SQL migration 鐵則:檔頭 -- Date:、每個語句加日期註解、新建 table 必加 GRANT ... TO cm_app + sequence 權限、收尾必 INSERT public.schema_migrations;套用一律 psql --single-transaction -v ON_ERROR_STOP=1 -f <檔>cmmgr三環境(DEV / STG / POC)都要套
  • 跨 repo 各自分開 commit,commit message 對應各自 repo 的脈絡
  • 不要晶晶體(中英夾雜的語法),不要用「速贏」這個詞
  • agent 測試必帶 PYTHONPATH=.(repo 缺 conftest.py
  • 重建 agent image 必指定 --platform linux/amd64(開發機是 Mac arm64、目標主機是 Linux amd64),build 完必 docker inspect ... --format '{{.Os}}/{{.Architecture}}' 確認

§9 收尾流程(全案完成後,等決策者下令才做)

⚠️ 本節列的是「等命令」的動作,不要主動執行。第二、三批各自完成不等於全案完成。

每批完成後的階段性動作

  1. 回寫該批 Notion 子任務卡狀態(派 subagent)
  2. commit(顯式 git add,不 push)
  3. 抽查通過後放行下一棒

全案完成後(三批都驗收通過、決策者下令才做):

  1. 最終端到端驗收(§4.3)——三環境 migration 對齊、重建 image 部署三台、跑 design.md §6 九項
  2. 收尾兩項未開卡的工作:T-9.1(清 FE 硬編工具清單)、T-9.2(補 database-schema.md 三表記載)
  3. 更新 discussion.html——反映 D4 改案、D12(含 SPA 打掛 ZAP 的更正)、D9 改案、requires_target_host(見 §5 第 8 項)。⚠️ 不要動 mermaid 的 %%{init:...}%%
  4. 更新 docs/specs/current/ 對應頁面 spectool-plugin-manage.md / project-task-edit.md / my-tasks.md)+ 檔頭「變更紀錄」加一行——SOP 走 writing-feature-specs skill
  5. 寫 SUMMARY 到 docs/features/FR-058-2607-detection-tools-expansion/handoff/
  6. Notion 母案 CM-957 + 六張子需求卡狀態同步;Artifact 線上版 republish
  7. memory feedback 沉澱
  8. 若要發版 → 走 version-bump skill(release note + pyproject.toml bump 成對必做 + FE 版號對齊)
  9. 三 repo push(等明示)

§10 不在本期 scope

項目 說明
SonarQube 本期不做,日後另議detection_toolsid=3 佔位列維持 status='coming_soon' 不動
ZAP 對 SPA 的登入後掃描 列為後續另案 CM-984(D12)。本案的 setup_guide 已明白標示「請勿對 SPA 使用登入後掃描」
ZAP connector 的自我保護 偵測認證失敗異常累積主動中止——決策者裁示只記錄不實作(§5 第 3 項)
macOS 15(TWGCB-01-015 不納入本案(D7)。基準 2026/6 才發布、官方部署資源頁無機器可讀檔案,現有 connector 未曾處理 macOS
GCB content 產製 逐條 TWGCB-ID 轉檢查規則(Windows GPO 產生器 / Linux 人工撰寫)不在本案。本案只做引擎 + 一份 Windows 最小 Demo profile
後台 content 更新機制 上傳 / 版更 / 套用的管理介面不在本案,日後另案。但 content 外部載入接口本案就要留(D7,T-3.2)
Nmap OEM 授權採購 本案不採,未評估成本。若日後產品策略需要零客戶設定的 nmap 整合,這是唯一能 bundle 的合法途徑,列為備查(D9 改案,§3.6)
_pick_agent 負載平衡 既有技術債,本案不處理
tenant_config_id 從未被寫入 既有技術債,永遠是 NULL,實際靠 (tenant_id, detection_tool_id) UNIQUE 回退查詢。本案不處理
connection_type='CLI' 型態 D9 改案後至今仍無實際使用者。不要為了「讓它有人用」而回頭改 Nmap

§11 本棒 commits 清單

本棒任內三 repo 的全部 commits(皆未 push,§7.6 裁示暫緩到全案驗收)。⚠️ 實作 session 若仍在跑,接手時 git log 會比本表多。2026-07-31 第三次更新(BE +2、FE +2、agent +2)。

BE compliance-manager-be(17 個,HEAD 1d23082b

Commit 說明 歸屬
1d23082b feat(cm-985): 互斥憑證組別平台能力——測試連線由使用者明確選一組、設定頁分組顯示(§1.7;migration fr058-9 三環境已套) 本輪新增平台能力
**2858b447 docs(fr058): 交接文件更新——第三批全數完成、第二批剩 GCB 三棒、驗收 gate 改為 InSpec+Nmap 合併一輪(=本文第二次更新**) 本棒收尾
d81067f5 docs(fr058): 協調者 session 中繼交接文件——即本文首版 本棒收尾
e1e5c795 docs(fr058): 補 T-2.2 揭露的架構事實——CINC 裝 agent 本機主動連出,與 OpenSCAP 相反 第二批
16ae4ff0 feat(cm-982): seed Nmap 工具目錄(SSH 型,D9 改案)(T-4.2) 第三批
9a15db96 feat(cm-981): detection_toolsrequires_target_host,解除 FE 對 connection_type 的耦合 第三批(§7.2 裁示)
8ac863cf docs(fr058): D9 改案——Nmap 由 CLI 改 SSH 型 + 補 NPSL 授權依據 本棒決策(§3.6)
4d5226fa feat(cm-972): seed InSpec / CINC Auditor 工具目錄(T-2.1) 第二批
b9520f7b feat(cm-981): detection_toolsrequires_credentials 宣告欄位(T-4.1,D9 平台能力) 第三批
2581b4f6 docs(cm-967): 更正 SPA 登入掃描的實際後果——會打掛共用 ZAP 而非產出空報告 本棒決策(§3.3)
f8b0a370 docs(cm-967): ZAP setup_guide 補登入後掃描的 SPA 限制說明 本棒決策(§3.3)
2d14ccb7 fix(cm-967): ZAP 登入四欄改條件必填——錯誤從 agent 執行期提前到 FE 表單 驗收修正②(§3.2)
0a9cde3c docs(fr058): D4 改版同步(ZAP 證據 PDF→HTML)+ 第二批派工交接文件 本棒決策(§3.1 / §3.5)
082a02d8 fix(cm-959): 測試連線 probe payload 補傳 detection_tool_code 驗收修正①(§3.2)
5151fb2c feat(cm-959,961-964): 派工帶 tool code + 任務層敏感參數加密鏈(T-X.1 / T-0.1〜0.3) 第一批(前一棒派出)
8f579c50 feat(cm-967): seed ZAP 工具目錄 + param_schema + setup_guide(T-1.1) 第一批
4b91138b docs(fr058): 討論稿補分批出貨計畫 前一棒尾聲

第三批派工文件(2026-07-30-fr058-batch3-nmap-dispatch.md)目前為 untracked,隨下一次 docs commit 一起進去。

FE compliance-manager-fe(5 個,HEAD 8d77d5e

Commit 說明
**8d77d5e fix(fr058): 檢測工具摘要卡分開顯示執行主機與掃描目標**——JobExecutionDrawer 原本只讀 params.hosts 一欄硬標「掃描目標」;openscap/openvas/inspec 這類「登進去掃自己」的工具剛好 hosts == targets 沒問題,nmap 是唯一兩者不同的工具(hosts=agent 執行主機、targets=掃描網段),導致執行主機被誤標成掃描目標
37967b4 feat(fr058): 憑證分組渲染 + 測試連線由使用者指定憑證組(§1.7 的 FE 半邊;FE 不硬寫任何協定字面值,全由後端宣告驅動;未選定則測試連線鈕 disabled、每次開窗重設)
2fe1ce6 refactor(cm-981): 測試主機輸入框改判 requires_target_host,不再硬判 connection_type
8220852 fix(fr058): 任務參數存檔補檢測工具參數必填驗證——錯誤從 agent 執行期提前到表單
992fd35 feat(cm-965): 任務參數 secret 欄位渲染 + condition 顯示修復(T-0.4)

agent evidence-agent(10 個,HEAD 087fa41

Commit 說明
087fa41 feat(fr058): Nmap 證據改存人可讀 HTML——容器內 xsltproc + 官方 nmap.xsl 轉換,XML 僅在記憶體算 summary。⚠️ 未經派工的自主改案,待決策者追認(§5 第 14 項)
2c64a3b test(fr058): probe 路徑 transport 端到端釘樁——§1.7 平台級缺口的防迴歸測試(agent 側零 code 異動_resolve_transport() 本來就吃 probe params,缺的是 BE 沒傳)
eb352a7 feat(cm-974): InSpec / CINC Auditor run()——逐台多檔證據 + JSON summary + 取消/逾時(T-2.3)——🔴 run() 至今零實跑,見 §5 第 0 項
6f97107 chore: bump 0.2.14——FR-058.4 Nmap connector(未出貨,等全案端到端;之後的 eb352a7 未再 bump,此版號同時涵蓋 Nmap 與 InSpec run()
883e5d1 feat(cm-983): Nmap connector——SSH 遠端執行 + XML 解析 + probe 四段分類(T-4.3)——零實跑驗證
dcedb4f feat(cm-973): InSpec / CINC Auditor connector 骨架 + probe(T-2.2)——✅ Dockerfile 的 CINC 安裝已 build 通過並實查存在(§1.8,原記載「從沒 build 過」已過期)
8185893 chore: bump 0.2.13——ZAP 主動掃描修正出貨版
1feb6c7 fix(zap): 主動掃描 does_not_exist——錯誤碼偽裝成 scan id 的三層遮蔽鏈(§3.2 修正③)
c775fc8 chore: bump 0.2.12——FR-058 第一批出貨版
500b6c7 feat(cm-968/969/970): ZAP connector——probe + 三種掃描模式 + 雙格式取報告

更早的 f17a311(factory 改依 tool code 取,T-X.2 / D11)已在 origin,不列入領先清單。


§12 給 fresh session 的超短 prompt

接手 FR-058(檢測工具擴充,四工具接入)的協調與決策工作。

完整讀序入口:
docs/features/FR-058-2607-detection-tools-expansion/handoff/2026-07-31-fr058-coordinator-midarc-handoff.md

先讀該文的「🧭 原始需求 / WHY」+ §0 讀序(含 §3 本棒完整經過與 design.md §2 的硬 gate),
讀完先回答 §0.4 的冷接自檢五問,再跑 §6 pre-flight。

現況:第一批(ID 解耦 + 任務層敏感參數 + ZAP)已實測完成;第三批(Nmap)三棒全數完成;
第二批的 InSpec 段(T-2.1~2.3)也全數完成,只剩 T-2.4(純 Notion 結案 CM-953)
與 GCB 三棒(T-3.1/3.2/3.3)。另外本輪加了一批平台級能力「互斥憑證組別」(CM-985,見 §1.7)。

實測進度(§1.8):DEV agent 已建並部署 0.2.14、CINC 確認裝進 image、
WinRM 測試連線已對真實 Windows 主機(192.168.50.160)通過。
⚠️ 但「真正的掃描」(run())從沒跑過一次——probe 通過不等於這條線可用。
CM-974 卡上那五條未驗證假設(reporter json 結構、退出碼語意等)一條都沒驗到,
其中「報告結構不符會統計全零但證據照常上傳」最不明顯。Nmap 也仍零實跑。

你的下一個動作是 §4.1——把合併驗收跑完。目前三個卡點:
  ① SSH 側 probe 卡在目標主機 audit-scan 帳號沒有 NOPASSWD sudo(環境問題,我在處理)
  ② FE 測試連線 Dialog 兩欄改版進行中(ToolPluginManage.vue 未提交),改完才驗收
  ③ run() 是驗收主體,還沒開始
另外 T-3.2 的 content 來源實跑驗證要併進這一輪(agent image 沒裝 git,
裸 GitHub URL 走哪個 fetcher 從沒驗過)。通過才放行 GCB 三棒。

⚠️ 兩件過期記載不要照做:舊版「先驗收 T-2.2 才放行 T-2.3」的 gate 已取消;
舊版說 BE pyproject.toml 誤加 zaproxy 待確認——實查已不存在,不需處理。

你的角色是協調、決策、派工、抽查。不寫 code、不跑測試——執行類與文件類工作全派 subagent
(不帶 model 參數,文件類必寫「分段寫檔」)。收尾類動作一律等我下令。
三 repo 皆未 push,我已裁示暫緩到全案驗收通過(§7.6),不要自己 push。

📌 寫完自檢:下個 session 只看這一份,能不能答出冷接自檢五問(懂 WHY 與兩次改案)、跑得動 pre-flight、知道下一個動作是接續 InSpec + Nmap 合併驗收(且知道 ① 舊的 T-2.2 gate 已取消 ② probe 已通過但 run() 從沒跑過 ③ 三個卡點是 sudo / FE 改版 / run())?——本文所有指令 / 路徑 / Notion URL 皆可直接複製貼上,不需回頭問決策者。

📌 本文與前一棒的關係2026-07-30-fr058-planning-complete-handoff.md 的 §6 pre-flight 與 §3 情境 A 的環境準備指令仍然有效可照抄;其 §1 狀態盤點與 §3 情境判斷已過期(情境 A 已走完)。有衝突時以本文為準