手冊首頁 / 合規稽核 / 檢測工具管理

檢測工具管理(Detection Tool Management)

功能群:系統管理|共用權限模型先讀 功能群總覽

事實基準:2026-08-01 從 FE src/views/plugin/ToolPluginManage.vue(846 行)+ BE app/detection_tools/ 全模組 + DEV config.detection_tools 實查掃出(FR-056 檢測工具整合平台 T-1.1~T-1.5 + FR-057 OpenSCAP SSH 連接器 + FR-058 檢測工具擴充四工具接入 + FR-058.5/.6/.7 SonarQube 三模式接入)

變更紀錄

日期 FR 內容
2026-08-01 FR-058.5/.6/.7 SonarQube 上架(第七款 available,原始碼安全檢測 SAST):FR-056 留下的目錄佔位列補上 config_field_schema(服務位址 + User Token 兩欄)、setup_guide(分模式說明,含 squ_ token 型別區別、寫入行為告知與收緊模式做法),statusavailable——seed 依環境異動鐵律僅套 DEV,STG/POC 等上版放行。任務層支援三種執行模式(pull 讀取既有結果/scan 掃描公開 Git repo/upload 上傳源碼壓縮包),參數與模式差異見 任務配置 §5工具卡描述改為第二版(八筆全改,以「能查出什麼、可作哪類控制項證據」為主,授權與安裝前提資訊移出、僅存 setup_guide);GCB 的 profile 任務參數選項由 1 筆示範擴為 8 支 TWGCB 作業系統類基準(詳見任務配置頁 §5)
2026-07-31 FR-058 工具目錄擴充到八款(新增 ZAP zap/CINC Auditor inspec/Nmap nmap/政府組態基準 GCB gcbavailable 由兩款增為六款)。平台能力:① credential_group_schema 互斥憑證組別——設定 Dialog 依宣告把欄位切成左右並排的獨立面板、Dialog 寬度依組數動態調整(≥2 組給 64rem),測試連線改由使用者明確選一組(不做自動偵測,未選不得送出);② 憑證部分更新改 merge 語意(多 secret 欄位工具不再被整包覆蓋洗掉未動的憑證);③ 新增 requires_credentials / requires_target_host 兩個宣告欄位,解除 FE 對 connection_type 的硬判耦合。UI:部署前提說明 Dialog 加寬 64rem每段程式碼區塊各自可複製(原本整份合併複製,Linux/Windows 兩套互斥腳本會混在一起)、工具卡同列等高 footer 貼底、卡片依「啟用→停用/未設定→敬請期待」排序、八個工具描述文案全面擴充(132–179 字)、profile 任務參數欄改 select_or_text
2026-07-30 v1.12.0 寫入守門下放:新增 / 編輯 / 重置憑證原為 service 層帳號級 require_super_admin()(FR-056 過渡守門,只有系統層 super_admin 能操作),改為 route 層 @require_capability("plugin.update")——角色權限矩陣「檢測工具管理」列有 update 勾的角色即可操作,super_admin 保留 break-glass 放行;復用既有 plugin.* capability,無 migration(BE fabf974e,未另開卡、隨 v1.12.0 release note §3 記載)
2026-07-29 FR-057 上線第二款檢測工具 OpenSCAPconnection_type='SSH',第三種連線型態);config_field_schematype 擴充 textarea/boolean/select_or_text,新增 condition(欄位依賴顯示)與 default(預設值)語意;新增 setup_guide(部署前提說明 + 一鍵複製準備腳本,工具卡片 overflow menu 開 Dialog);SSH 型工具測試連線改為先輸入測試主機、逐台彙總結果
2026-07-27 FR-056 全面改寫:本頁自 T-1.5 起已從前端 mock 占位頁改為完整接後端功能——工具目錄(config.detection_tools)+ 租戶設定 CRUD(含加密憑證)+ 測試連線(雲端直推 Agent)+ 動態參數 schema + D6 引用計數軟提醒 + 重置金鑰;舊版「hardcoded 工具清單、無 API」的紀錄已完全過時

1. 功能描述

檢測工具管理是租戶層級的外部資安檢測工具設定介面:管理平台工具目錄中已啟用的檢測工具,供租戶填寫連線資訊(主機位址、帳密、SSH/WinRM 憑證等)、測試連線、並在 任務配置 頁把工具綁定到「檢測工具執行」型任務上。

現況工具目錄共八筆(DEV 實查 config.detection_tools,依 id 序)——七筆 availableOpenVAS(網路弱點掃描)、OpenSCAP(SCAP 組態合規稽核)、SonarQube(原始碼安全檢測 SAST,FR-058.5 起上架,三種執行模式見任務配置頁)、ZAP(網頁 DAST 動態掃描)、CINC Auditor(組態合規檢測引擎,SSH/WinRM 雙 transport)、Nmap(網路埠與服務探測)、政府組態基準(GCB)(依 TWGCB 檢測主機組態,與 CINC Auditor 共用引擎、差別在檢測內容,D7);一筆 coming_soon 佔位:Nessus。SonarQube 的 available 目前僅 DEV(seed 依環境異動鐵律只套 DEV),上版後全環境生效。

平台維護的「工具目錄」(config.detection_tools)是 DB 驅動而非程式寫死:每筆工具定義代碼、顯示名稱、說明、連線類型(API/CLI/SSH)、設定欄位結構config_field_schema,動態表單 JSON)、互斥憑證組別宣告credential_group_schema,FR-058)、行為宣告欄位requires_credentials / requires_target_host,FR-058)、部署前提說明(setup_guide)與平台層 statusavailable/coming_soon)。本頁的設定表單、任務配置頁的掃描參數表單,皆完全依 BE 回傳的 schema 動態渲染——FE 對工具型別零硬編,新增工具只需目錄補資料 + Agent 端補 connector,前端不用改代碼。

FR-058 一次接入四款工具,是對這個 schema-driven 架構的壓力測試,也逼出了三個原本埋在架構裡的耦合:① FE 硬判 connection_type === 'SSH' 來決定要不要問測試主機——CINC Auditor 同時支援 SSH 與 WinRM,connection_type 只能填一個值,行為判斷改由 requires_target_host 宣告;② 憑證整包覆蓋——CINC Auditor 有三個 secret 欄位(ssh_private_key/ssh_password/winrm_password),FE 只送有填值的欄位,BE 原本整包 encrypt 會洗掉沒動的憑證,改 merge 語意;③ 派工靠 tool id 硬編映射——agent factory 原以 _TOOL_ID_TO_CODE 固定表認 connector(只涵蓋 id 1–4),新工具會被誤判為「尚無 connector 實作」,改由派工 payload 夾帶 detection_tool_code(D11)。

主要使用者:持有 plugin.update capability 的角色(角色權限矩陣「檢測工具管理」列有 update 勾,v1.12.0 起;系統層 super_admin break-glass 放行,見 §3)。

角色速覽

角色 一句話
plugin.update 的角色(+super_admin break-glass) 本頁唯一使用者——新增/修改工具設定、測試連線、停用、重置金鑰
(Agent 本身) 不是本頁使用者,而是「測試連線」與真實掃描的實際執行者;透過雲端 mTLS 直推指令運作,不經過本頁 UI

1.1 功能總覽(本頁全部功能)

# 功能 說明 位置 詳述
1 工具目錄清單 卡片呈現平台工具目錄(GET /detection-tools,僅回 enabled=true 者;coming_soon 仍會回、由 FE 灰化);卡片依「啟用 → 停用/未設定 → 敬請期待」排序cardRank,FR-058),同列卡片等高、footer 貼底 主畫面 Card grid §6.2
2 搜尋工具 依工具名稱前端本地過濾(searchedTool 搜尋框 純前端
3 待啟用工具灰化 status==='coming_soon' 的工具卡片降低透明度 + 顯示「敬請期待」Tag,動作按鈕全部隱藏 工具卡片 §5
4 設定 / 編輯連線資訊 開 Dialog,依 config_field_schema 動態渲染欄位(含 secret 遮罩、hint 填寫指引);宣告了 credential_group_schema 的工具(CINC Auditor / GCB)欄位切成左右並排的獨立面板,Dialog 寬度依組數動態調整(FR-058);首次設定按鈕文案「設定」,已有設定後文案「編輯」 Dialog UC-TPM-01
5 測試連線 已存檔設定值,透過雲端直推內網 Agent 實際連線工具端驗證。開窗條件為兩軸的聯集(FR-058):requires_target_host=true → 要求填測試主機(可多台、逐台並發彙總);有 credential_group_schema → 要求明確選一組憑證(不預選、未選不得送出);兩者皆否則直接測 工具卡片按鈕(僅已設定才顯示) UC-TPM-02
6 啟用 / 停用 已有設定的工具可切換 statusenabled/disabled),採樂觀更新 + 失敗回滾;停用前查詢引用任務數(D6 軟提醒,不擋) 工具卡片 overflow menu UC-TPM-03
7 重置金鑰 清空該工具設定的加密憑證,需重新輸入才能再用 工具卡片 overflow menu(僅已設定才顯示) UC-TPM-04
8 部署前提說明(FR-057,FR-058 改版) setup_guide 的工具卡片 overflow menu 出現「部署前提說明」,開 Dialog 渲染 markdown(前提說明 + 目標主機準備腳本)。FR-058 改為每段程式碼區塊各自帶一顆複製鈕(原本整份合併複製),Dialog 加寬至 64rem 工具卡片 overflow menu → Dialog §5

UC(§2)展開本頁所有具實質後端寫入/呼叫邏輯的功能:新增/編輯設定(4,UC-TPM-01)、測試連線(5,UC-TPM-02)、停用(6,UC-TPM-03)、重置金鑰(7,UC-TPM-04)。純顯示/前端過濾類(1 目錄清單、2 搜尋、3 灰化、8 部署前提說明)於 §5 說明。

2. Use Case

角色速覽:見 §1。

流程圖視覺慣例:菱形 = 判斷、橘底 = 例外/擋下、紅框 = 錯誤(標 error code)、綠框 = 成功終點、虛線 = 可選路徑。

UC-TPM-01 新增 / 編輯工具連線設定

項目 內容
角色 plugin.update capability 的角色(super_admin break-glass)
前置條件 該工具目錄項 status==='available'(非 coming_soon
產出 / 後置條件 新增:config.tenant_detection_tool_configs 新增一列;編輯:更新既有列(secret 欄位留空=不動既有密文;多 secret 欄位工具採 merge,FR-058)

流程:開 Dialog(依 config_field_schema 動態渲染;有 credential_group_schema 者切成左右並排面板)→ 必填欄位未填且已 touched → 顯示「{欄位名} 為必填」→ 送出時先跳過 condition 不成立的隱藏欄位(不送未選分支的殘留值),secret 欄位分流進 credentials(有值才帶)、其餘進 field_valuesPOST(新增)或 PUT(編輯)→ 成功關閉 Dialog 並重整清單。

憑證部分更新採 merge 語意(FR-058,BE 24dba59f:FE 只送「有填值」的 secret 欄位(UI 承諾「留空=沿用原值」),BE update_tenant_configcredentials先解密既有密文、以新 key 逐個蓋上去再重新加密,而非整包覆蓋。單一 secret 欄位的工具(OpenVAS / ZAP)merge 是等價操作、行為不變;多 secret 欄位工具(CINC Auditor 三個)若沿用舊的整包覆蓋,只改 SSH 私鑰會把 WinRM 密碼一併洗掉(實測踩過)。merge 語意下「清空單一 secret」不支援——整組清空走 UC-TPM-04 重置金鑰。出處:app/detection_tools/service/detection_tool_service.py::update_tenant_config:92-116

UC-TPM-02 測試連線

項目 內容
角色 任何登入者(BE 無角色守門,實務上為持 plugin.update 的管理者)
前置條件 該工具已有設定(config 非 null)且已存檔
產出 / 後置條件 無寫入設定內容;僅更新 last_tested_at / last_test_result

流程:按「測試連線」→(前置條件 Dialog,開窗與否見下)→ BE 解密該租戶已存憑證 → 挑一台本租戶啟用中、capabilitiesdetection_scan 的 Agent → 透過既有 FR-039 mTLS 通道推送 POST /detection/probe(帶解密後憑證 + detection_tool_code + 憑證組別對應的 probe 參數,要主機者另帶 host)→ Agent 用與真實掃描相同的連線方式實連驗證(OpenVAS:python-gvm GMP over TLS;OpenSCAP:SSH 連線 + 認證 + oscap 指令存在性 + SCAP content 存在性四段檢查;ZAP:API 連線;CINC Auditor / GCB:依選定組別走 SSH 或 WinRM;Nmap:SSH 登入執行主機;SonarQube:兩段式——api/system/status 免認證驗連通後,帶 token 呼叫 api/authentication/validate 驗 token 有效性,不讀取任何專案資料、不觸發掃描,FR-058.5)→ 結果同步回傳 → 記錄 last_tested_at/last_test_result

前置條件 Dialog 的兩軸(FR-058,彼此獨立可任意組合)——FE onTestConnectionCard 取兩者聯集決定要不要開窗,Dialog 標題隨實際要問的內容切換(testDialogHeader 三種文案):

觸發條件 問什麼 為何需要
目標主機 requires_target_host === true(OpenSCAP / CINC Auditor / Nmap / GCB) 一或多台測試主機(逗號/空白/分號分隔) 租戶層憑證是跨主機共用的稽核帳號、不含 host(D1),probe 需另外指定
憑證組別 credential_group_schema.groups 非空(CINC Auditor / GCB) SelectButton 選一組(不預選,未選不得送出) 兩組憑證互斥、使用者只填打算掃的那組;兩組都填齊時無從分辨,猜錯會給出誤導性的失敗原因

憑證組別為何不做自動偵測:「填了哪組就用哪組」在「客戶同時有 Linux 與 Windows 目標、兩組都填齊」時猜不出來,而猜錯產生的正是本案要消滅的那種誤導訊息(只填 WinRM 卻收到「本任務的連線方式為 SSH,但未填寫 SSH 稽核帳號」——訊息清楚但回答的是使用者沒問的問題)。BE _resolve_credential_group_params() 對「宣告了組別卻沒選 / 選了不存在的 key」一律明確回失敗、不派 probe、也不寫 last_test_result(沒真的測過就不該把結果蓋成 fail)。FE 只送組別 key,probe 參數的 key 與 value 由 BE 依 DB 宣告自行組出——參數會一路流到 agent connector 決定走哪條程式路徑,讓瀏覽器指定等於開一個注入面。

四種失敗原因分開呈現(皆 success=false,非 HTTP 錯誤):①未設定憑證 ②本租戶無可用 detection_scan Agent ③憑證組別未選/不存在/宣告不完整(FR-058)④Agent 連得到但工具端連不通/帳密錯(訊息由 Agent 回傳原樣顯示)。多台測試(FR-057 T-2.3-fix):FE 拆開並發,每台各發一次 POST test-connection(body 帶單台 host),BE 逐台呼叫 probe 並各自回傳,FE 逐列即時更新狀態(testing/ok/fail),不互等。

tpm_test_connection start 按「測試連線」 POST /detection-tools/configs/{uid}/test-connection checkcred 該設定有 credentials_encrypted? start->checkcred nocred success=false message=detection_probe_no_credentials checkcred->nocred pickagent 挑本租戶 enabled 且 capabilities 含 detection_scan 的 Agent checkcred->pickagent noagent 無可用 Agent success=false message=detection_probe_no_agent pickagent->noagent 查無 decrypt 解密憑證 + 合併 field_values (base_url 等非機敏欄位) pickagent->decrypt 找到 push mTLS 直推 Agent POST /detection/probe (AgentProbeClient,短效 JWT) decrypt->push probe Agent:python-gvm 實連工具端 (與真實掃描相同連線方式) push->probe ok 連線成功 success=true 記錄 last_tested_at=now / last_test_result=success probe->ok bind/連線成功 fail 帳密錯 / 逾時 / 不可達 success=false message=Agent 回傳原始訊息 記錄 last_test_result=fail probe->fail 失敗
UC-TPM-02 流程:按測試連線→BE 解密憑證→挑 detection_scan agent(無則回②)→ mTLS 推 /detection/probe → Agent 走 python-gvm 實連 → 回傳成功/失敗原因 → 記錄 last_tested_at

UC-TPM-03 停用工具設定

項目 內容
角色 plugin.update capability 的角色(停用走 PUT 端點,v1.12.0 起納入守門)
前置條件 該工具已有設定且目前為 enabled
產出 / 後置條件 status 改為 disabled;停用後任務配置頁該工具仍列在下拉(下拉來源未过滤 status,見 §12 坑 3)

流程:按「停用」→ 先查詢 count_referencing_tasks(該工具目錄項被幾個 job_execution_detection_tools 綁定引用)→ 引用數 >0 時 confirm 訊息加註「有 {count} 個任務正使用此工具設定,仍要停用嗎?」,=0 時純確認訊息 → 不論引用數多少,確認後一律直接停用(D6 軟提醒,非阻擋)→ PUT 更新 status

UC-TPM-04 重置金鑰

項目 內容
角色 plugin.update capability 的角色(super_admin break-glass)
前置條件 該工具已有設定(config 非 null)
產出 / 後置條件 credentials_encrypted 清空為 NULL;field_values(非機敏欄位)不受影響

流程:按「重置金鑰」→ confirm(「確定要重置 {name} 的憑證嗎?重置後需重新設定才能使用。」)→ 確認 → POST /detection-tools/configs/{uid}/reset → 成功後重整清單,該工具的機敏欄位回到未設定狀態(下次開 Dialog 不再顯示 •••• 遮罩)。

3. 權限矩陣

操作 FE 判定 BE 強制 BE 檢查位置
進入本頁 ui_routes web-menu 可見性 N/A(僅 JWT)
讀工具目錄 / 讀租戶設定清單 @jwt_required() api/detection_tools/routes/detection_tool_route.py::DetectionToolsRoute / TenantDetectionToolConfigsRoute
新增 / 編輯(含停用)/ 重置金鑰 無額外前端角色判斷 route 層 @require_capability("plugin.update")(v1.12.0 起)——角色權限矩陣「檢測工具管理」列有 update 勾即可;系統層 super_admin break-glass 放行;未持有 → GRC_403022GRC_CAPABILITY_REQUIRED api/detection_tools/routes/detection_tool_route.py::TenantDetectionToolConfigsRoute.post / TenantDetectionToolConfigDetailRoute.put / TenantDetectionToolConfigResetRoute.post
測試連線 / 查引用數 @jwt_required()無角色守門 TenantDetectionToolConfigTestConnectionRoute / TenantDetectionToolConfigRefCountRoute

守門演進(v1.12.0 下放,BE fabf974e:FR-056 上線時因本模組租戶層 capability 尚未 seed,寫入動作以 service 層帳號級 require_super_admin() 過渡守門(見舊版 §3 附註),導致只有系統層 super_admin 能存設定。v1.12.0 改為 route 層 @require_capability("plugin.update")——復用 tool-plugin-manage 頁對應的既有 plugin.* capability(三環境已存在且已配角色,無需新 seed / migration),符合 FR-048 授權守門雙軌規範的「主體域守門走 route decorator」形式;service 層的 require_super_admin() 已移除。停用因走同一 PUT 端點,一併納入守門。測試連線 / 查引用數仍完全無角色檢查,只靠 RBAC 選單擋入口——與寫入動作的守門粒度不一致,屬現況已知狀態(見 §12 坑 2)。

4. 狀態機與前置條件

本頁無輪次 / 階段狀態機,僅有工具目錄與租戶設定各自獨立的狀態:

條件 效果 出處
detection_tools.status === 'coming_soon' 工具卡片灰化(opacity-60),動作按鈕全部隱藏(v-if="tool.status !== 'coming_soon'" ToolPluginManage.vue:377,395
detection_tools.status === 'available' 才可新增設定(create_tenant_config 檢查,否則 DETECTION_TOOL_NOT_AVAILABLE detection_tool_service.py:75-77
tenant_detection_tool_configs.status enabled:可被任務綁定使用;disabled下拉未過濾,仍可能被選中(見 §12 坑 3)
Dialog:currTool.config 存在 「設定」按鈕文案變為「編輯」;onOpenConfigDialog 用既有 field_values/has_credentials 預填表單(無值則帶 field.default,FR-057) ToolPluginManage.vue:95-106
欄位 field.secret && hasExistingValue 該欄位 placeholder 顯示「••••(已設定,留空不變更)」,不回顯明文 DetectionConfigField.vue:33-38
欄位 field.condition(FR-057) 該欄位只在「另一欄位(condition.field)目前值等於 condition.value」時才顯示;不可見時跳過必填驗證(不可見的分支不該擋送出),送出時也不進 payload DetectionConfigField.vue::visible:23-27 / showError:31-34ToolPluginManage.vue::isFieldVisible:173(委派 utils/detectionFieldValidation.js
tool.requires_target_host === true(FR-058,取代原 connection_type === 'SSH' 硬判) 按「測試連線」不直接打 API,先彈 Dialog 要求輸入測試主機(見 UC-TPM-02) ToolPluginManage.vue::testDialogNeedsHost:283onTestConnectionCard:315-328
tool.credential_group_schema.groups 非空(FR-058) ① 設定 Dialog 依 field.group 把欄位切成獨立面板分區呈現;② 按「測試連線」先彈 Dialog 要求選一組憑證 ToolPluginManage.vue::groupedFieldSections:192-197testDialogNeedsGroup:286
groupedFieldSections.length > 1(FR-058) 設定 Dialog 寬度 64rem(≥2 組要並排),否則維持 32rem——沒宣告群組的工具(OpenVAS / OpenSCAP / ZAP / Nmap)欄位平鋪且皆 w-full,固定放寬會把輸入框拉成一整條橫線 ToolPluginManage.vue::configDialogWidth:205
欄位 field.hint(FR-058) 欄位標籤下方顯示一句填寫指引;沒有 hint 的欄位不多出任何節點 DetectionConfigField.vue:50

5. UI 設計

版面骨架(Card grid + 設定 Dialog):

Header:搜尋框(searchedTool,純前端本地過濾工具名稱) 開啟:§6.2 工具目錄 / 租戶設定清單 工具卡片 Grid:目錄(GET /detection-tools)+ 租戶設定(GET /detection-tools/configs)合併 available 顯示狀態 Tag(啟用/停用);coming_soon 灰化 + 「敬請期待」,動作按鈕全隱藏 → §6.2(點我開啟) 開啟:UC-TPM-01 新增/編輯工具連線設定 設定 / 編輯 Dialog 依 config_field_schema 動態渲染欄位 secret 欄位遮罩「••••(已設定,留空不變更)」 POST 新增 / PUT 更新 → UC-TPM-01(點我開啟) 開啟:UC-TPM-02 測試連線 測試連線按鈕 雲端解密憑證 → mTLS 直推 Agent /detection/probe Agent 用 python-gvm 實連工具端驗證 回 success/message,記錄 last_tested_at → UC-TPM-02(點我開啟) 開啟:UC-TPM-03 停用工具設定 停用按鈕 先查 referencing-tasks-count(D6 軟提醒) 不論引用數多少,確認後一律直接停用(不擋) → UC-TPM-03(點我開啟) 開啟:UC-TPM-04 重置金鑰 重置金鑰按鈕 confirm 二次確認 POST reset → credentials_encrypted 清空為 NULL → UC-TPM-04(點我開啟) 彩色=主要互動區塊(連對應 UC / §6 API)|灰=本頁純結構|虛線框=dialog
檢測工具管理版面:搜尋框 + 工具卡片 grid(每卡:名稱/說明/狀態 Tag + 設定·測試連線·overflow menu 按鈕)+ 設定 Dialog(動態欄位渲染)

📸 實機截圖待補:工具卡片 grid(八張卡、含等高與排序)、設定 Dialog(單欄版:secret 遮罩 + textarea 私鑰欄 + auth_method 條件顯示)、設定 Dialog(雙欄版:CINC Auditor 的 SSH/WinRM 並排面板)、測試連線前置條件 Dialog(憑證組別 SelectButton + 測試主機 + 逐台結果列)、部署前提說明 Dialog(逐段複製鈕)。

狀態呈現:每張工具卡片右上角狀態 Tag——coming_soon 顯示「敬請期待」(secondary);有設定則依 config.status 顯示綠色「啟用」或紅色「停用」。設定 Dialog 標題固定為「啟用檢測工具」(t('lang.plugin_manage.active_plugin'),即使是編輯既有設定也沿用此標題,屬既有文案非新坑)。無 socket;設定儲存 / 重置後重打 fetchAll() 重新整理整頁資料;啟用 / 停用改樂觀更新 + 失敗回滾(先改本地 config.status,PUT 失敗才還原並顯示錯誤)。

卡片排列與等高(FR-058):卡片依 cardRank 排序——啟用(0)→ 停用/未設定(1)→ coming_soon(2)壓底。容器 align-items-stretch 讓同一列卡片拉成該列最高者的高度,卡片內部 card → p-card-body → p-card-content 逐層 flex: 1 把多出來的高度吃進內容區,footer 因此貼底對齊。兩段缺一不成立:只有前者則外框等高但按鈕列仍跟著內容浮動、只有後者則卡片本身沒被拉高無空間可分配。內容區另設 min-height: 8rem 當最短卡地板(描述文案由後端填,將來若有工具只寫一句話不會縮成細片)。出處:ToolPluginManage.vue::cardRank:78-81<style scoped> .custom-card 區塊。

卡片動作配置(FR-057 改版):常用動作(設定 / 編輯、測試連線)留在卡面;次要 / 危險動作(部署前提說明、啟用 / 停用、重置金鑰)收進卡片右下角 overflow menu(pi-ellipsis-v 按鈕開 PrimeVue Menu popup),避免多按鈕擠壓換行跑版(ToolPluginManage.vue::getCardMenuItems:435-465)。

設定 Dialog 的憑證分區(FR-058):宣告了 credential_group_schema 的工具,欄位依 field.group 對應宣告的 groups[].key 切成分區;每組做成獨立面板(完整外框 + 有底色的抬頭列 + 該組的 description 說明),排版用 CSS Grid repeat(auto-fit, minmax(20rem, 1fr))——欄數由可用寬度自算,兩組剛好兩欄、三組以上不會排成「2 + 1 落單」,窄螢幕自動降單欄。做成獨立面板而非只用一條分隔線,是因為「這兩組是分開的、只需填要掃的那一組」正是要傳達的核心訊息,一條細線在並排時讀起來仍像同一張連續表單。沒有 groupgroup 對不到任何宣告群組的欄位一律降級放最前面的無分區區塊(絕不靜默丟掉——使用者填不到欄位遠比排版不完美嚴重)。分區純屬排版:送出一律以扁平 config_field_schema 為準(buildPayload),分組不參與 payload 計算。出處:ToolPluginManage.vue::credentialGroups:182ungroupedFields:186-189groupedFieldSections:192-197.credential-group-grid style。

部署前提說明 Dialog(FR-057 建立,FR-058 改版):工具目錄項有 setup_guide(TEXT,markdown)時,overflow menu 出現「部署前提說明」項。FR-058 兩處改動:

  • 逐段複製取代整份複製splitSetupGuide()marked.lexer() 把 markdown 拆成「說明段落」與「程式碼區塊」交替的片段,每個 code block 各自帶一顆複製鈕(複製後圖示短暫變勾勾,讓回饋落在按下的那顆按鈕上)。動機:同一份說明內含 Linux(SSH)與 Windows(WinRM)兩套互斥的準備腳本,使用者只需要其中一套;併成一大段複製等於逼他自己剪裁,貼進 shell 還是錯的。
  • Dialog 加寬至 64rem(同雙欄設定 Dialog,加 960px 窄螢幕 fallback):說明內含終端機指令與對照表,窄版會讓指令頻繁折行、表格被擠壓。

消毒鏈:說明段落走 marked.parser()DOMPurify.sanitize()v-html(信任來源仍過濾,防禦性一致);程式碼區塊改由 Vue 文字插值輸出(自動跳脫),完全不經過 v-html,也不把內容拼進 HTML 字串。切段時把 tokens.links 帶進每段 prose,否則文件層級的參考式連結([x]: url)在切段後解不出來。出處:ToolPluginManage.vue::splitSetupGuide:28-50copyCodeBlock:57-70

6. API 規格

Envelope:成功 {"code": 1, "data": …}、失敗 {"code": 0, "msg": "…"}return_response)。

6.1 總清單(本頁呼叫的全部 endpoint)

分類 Method + Path 說明 完整規格
目錄 GET /detection-tools 工具目錄清單(僅回平台層啟用者) §6.2
目錄 GET /detection-tools/{uid} 單筆工具目錄項(本頁未直接用,供他頁/除錯) GAI-SD-02
目錄 GET /detection-tools/{uid}/param-schema 取工具當前生效版本的任務參數 schema(本頁不用,供 任務配置頁 動態渲染掃描參數) GAI-SD-02
租戶設定 GET /detection-tools/configs 本租戶所有工具設定清單 §6.2
租戶設定 POST /detection-tools/configs 新增租戶工具設定(含加密憑證) §6.3
租戶設定 PUT /detection-tools/configs/{uid} 更新租戶工具設定(含停用切換) §6.3
租戶設定 POST /detection-tools/configs/{uid}/reset 重置憑證(清空為 NULL) §6.4
租戶設定 POST /detection-tools/configs/{uid}/test-connection 測試連線(雲端直推 Agent) §6.4
租戶設定 GET /detection-tools/configs/{uid}/referencing-tasks-count 停用/重置前查引用任務數(D6 軟提醒) §6.4

任務執行相關端點(/detection-tools/jobs/{job_uid}/execute.../cancel(FR-058 新增)、.../executions)屬 任務執行抽屜 功能,非本頁呼叫,列在該頁 spec。

6.2 工具目錄 / 租戶設定清單

[GET] /detection-tools

無 query。Response data[]DetectionToolResponse):

欄位 型別 說明
uid / code / name / description string 工具識別與顯示資訊(description FR-058 全面擴充至 132–179 字,說明用途、連線方式、目標端前提與可作為哪類控制項的證據)
connection_type string API / CLI / SSH(FR-057 新增;CLI 尚未實際使用,見 §12)。FR-058 起不再作為 FE 行為判斷依據——CINC Auditor 同時支援 SSH 與 WinRM,此欄只能填一個值,行為改由 requires_target_host / credential_group_schema 宣告
config_field_schema array 動態表單欄位定義:[{key, type, label, secret, required, options?, condition?, default?, group?, hint?}]——typetext/password/number/select/textarea/boolean/select_or_text(後三者 FR-057 新增,見下方型態說明)
setup_guide string|null (FR-057 新增)部署前提說明 + 目標主機準備腳本,markdown 格式;FE 渲染成 Dialog + 逐段複製(見 §5)。null 或空字串=該工具不顯示「部署前提說明」選單項
requires_credentials bool (FR-058 新增)該工具是否需要租戶層憑證。false=零憑證工具,派工時 start_execution() 不擋空憑證。預設 true(往嚴的方向失敗);DEV 現況八筆皆 true
requires_target_host bool (FR-058 新增)測試連線是否需使用者指定一台目標主機(租戶層憑證不含 host 的工具為 true)。預設 false(忘了宣告不會多問一個使用者答不出來的問題);DEV 現況 openscap/inspec/nmap/gcbtrue
credential_group_schema object|null (FR-058 新增)互斥憑證組別宣告,形狀見下方專表。null=無組別,設定頁與測試連線行為與加此欄前相同;DEV 現況僅 inspec/gcb 有值
status string available / coming_soon
enabled bool 平台層總開關(list_toolsget_tools(enabled=True) 過濾;coming_soon 仍會回傳,由 FE 灰化)

config_field_schema 各欄位屬性:

屬性 型別 說明
key / label / type string 欄位鍵 / 顯示標籤 / 渲染型態
required bool 是否必填——不受 condition 隱藏影響時才生效:欄位因 condition 不符而不可見時一律跳過必填驗證(不可見分支不該擋送出)
secret bool truecredentials(加密存放);falsefield_values
options array|undefined select/select_or_text 用:[{label, value}] 下拉選項
condition object|undefined (FR-057 新增){field, value}——此欄只在「另一欄位 field 目前值等於 value」時才顯示(如 ssh_private_key 只在 ssh_auth_method==='private_key' 時出現)
default any|undefined (FR-057 新增)欄位預設值,開 Dialog 時若無既有值則帶入(如 ssh_port 預設 22winrm_port 預設 5985
group string|undefined (FR-058 新增)該欄位歸屬的憑證組別 key,對應 credential_group_schema.groups[].key;FE 據此分區排版。對不到宣告群組 → 降級放無分區區塊
hint string|undefined (FR-058 新增)欄位標籤下方的一句填寫指引(如「使用 HTTP 時為 5985;改用 HTTPS 時請一併改為 5986」);沒有則不渲染任何節點

credential_group_schema 形狀(FR-058):

屬性 型別 說明
groups array [{key, label, description, probe_param_value}]——key 對應各欄位的 field.grouplabel/description 是分區面板的抬頭與說明(如「Linux 目標(SSH)」/「掃描 Linux 主機時填這一組。若貴公司只掃 Windows 主機,這一組可以整組留空。」)
prompt_label string 測試連線 Dialog 的提問文案(如「要測試哪一組憑證?」);FE 無值時退回 i18n 預設
probe_param_key string 選定組別後要塞進 probe 的參數名(CINC Auditor / GCB 皆為 transport)。BE 專用——FE 不讀不送,只回傳 groups[].key

probe_param_key / probe_param_value 不外流給 FE 使用:serializer 雖整個 credential_group_schema 原樣 dump,但 FE 契約上只准回傳選中的 key,probe 參數由 BE 依 DB 宣告自行組出。probe 參數會一路流到 agent connector 決定走哪條程式路徑(其他工具則是組出哪個檔案路徑),讓客戶端自由命名參數等於開一個注入面。

型態渲染對照(DetectionConfigField.vue):text→InputText、password→Password(toggleMask)、number→InputNumber、select→Dropdown、textarea→Textarea(autoResize,SSH 私鑰欄用)、boolean→InputSwitch、select_or_text→PrimeVue editable Dropdown(可選常用選項、也可直接輸入清單外的自由字串,如 profile 欄)。

出處:api/detection_tools/serializers/detection_tool.pyDetectionToolResponse,FR-058 新增 requires_credentials / requires_target_host / credential_group_schema)、route DetectionToolsRoute、service detection_tool_service.py::list_toolsget_tools(enabled=True))。

現況種子資料(2026-08-01 DEV 實查 config.detection_tools,八筆):

id code 顯示名 connection_type status req_creds req_host 憑證組別 setup_guide config_field_schema 欄位
1 openvas OpenVAS API available 4:base_url/username/password(secret)/port
2 nessus Nessus API coming_soon
3 sonarqube SonarQube API available(僅 DEV,FR-058.5) 2:base_url/token(secret)——token 必須是 User Tokensqu_ 前綴);sqp_/sqa_ analysis token 只能推分析、不能讀結果,填錯測試連線會失敗(setup_guide 有型別對照表)
4 openscap OpenSCAP SSH available 6:username/auth_method(select)/password(secret, cond)/private_key(textarea secret, cond)/ssh_port(default 22)/use_sudo(boolean default true)
5 zap ZAP API available 2:base_url/api_key(secret)
6 inspec CINC Auditor SSH available ✅ SSH/WinRM 11:SSH 組 6(ssh_username/ssh_auth_method/ssh_private_key(secret,cond)/ssh_password(secret,cond)/ssh_port/ssh_use_sudo)+ WinRM 組 5(winrm_username/winrm_password(secret)/winrm_port(default 5985)/winrm_ssl/winrm_self_signed
7 nmap Nmap SSH available 6:username/auth_method(select)/private_key(textarea secret, cond)/password(secret, cond)/ssh_port(default 22)/use_sudo(boolean default false)
8 gcb 政府組態基準(GCB) SSH available ✅ SSH/WinRM 11:與 inspec 逐字相同(同一顆引擎、同一組連線參數,刻意保持逐字一致讓日後 diff 一眼看出是否漏改)

CINC Auditor / GCB 的欄位全部 required=false:兩組互斥憑證只需填要掃的那一組,任一欄設必填都會擋住「只掃 Windows 的客戶」。缺欄位的錯誤落在派工/測試連線時由 connector 回報(訊息指名缺哪個欄位)。與 OpenSCAP 的「條件必填」(password/private_keyrequired=true,靠 condition 決定套不套驗證)是兩種不同策略。

connection_type 對 CINC Auditor / GCB 只是形式值:兩者同時支援 SSH 與 WinRM,欄位填 SSH 純為滿足 NOT NULL 約束,實際 transport 由使用者在任務參數選(transport)或測試連線選憑證組別決定。相關 seed migration:scripts/sql/2026-07-30-fr058-{1,5,6,7,8}-*.sql2026-07-31-fr058-{9,10,...,19}-*.sql2026-08-01-fr058-{20,21}-*.sql(sonarqube 上架=fr058-17、描述文案 v2=fr058-15、GCB 8 支 TWGCB profile=fr058-18;全數已套 DEV,STG / POC 依環境異動鐵律等上版放行)。

八筆工具描述為 2026-07-31 第二版fr058-15):決策者裁示描述以「主要功能可以幹嘛」為主——每則涵蓋「查出什麼/對應哪類控制項證據」,授權與商用性質、來源維護者、安裝部署前提三類內容全數移出(該資訊已在各工具 setup_guide 完整載明,卡片不重複)。coming_soon 者(Nessus)句尾保留「此工具尚在規劃中、目前無法使用,敬請期待。」狀態句。

[GET] /detection-tools/configs

無 query。Response data[]TenantDetectionToolConfigResponse):

欄位 型別 說明
uid string 設定識別碼
detection_tool_id int config.detection_tools.id
detection_tool_code string|null 服務層補算(list_tenant_configsdetection_tool_id 對照目錄),供 FE 依 code 合併進工具卡片
field_values object 非機敏欄位值(如 base_url
status string enabled / disabled
has_credentials bool 是否已設定機敏欄位——絕不回傳憑證明文/密文,只回布林
last_tested_at / last_test_result datetime|null / string|null 最近一次測試連線時間與結果

出處:api/detection_tools/serializers/detection_tool.py:17-40TenantDetectionToolConfigResponse.dump_entity 手動補 has_credentials)、service detection_tool_service.py:58-69::list_tenant_configs。FE 合併邏輯:ToolPluginManage.vue::tools computed:57-67(依 detection_tool_code === tool.code 配對)。

6.3 新增 / 更新設定

[POST] /detection-tools/configs

Request:

{
  "tool_uid": "<detection_tools uid>",
  "credentials": {"password": "..."},
  "field_values": {"base_url": "https://...", "username": "...", "port": 9390},
  "status": "enabled"
}
欄位 型別 必填 說明
tool_uid string 目標工具目錄項
credentials object 機敏欄位(field.secret===true)→ 加密後存 credentials_encrypted;FE 全部留空則整個 key 省略
field_values object 非機敏欄位(如 base_url
status string 預設 disabled

工具目錄項 status !== 'available'DETECTION_TOOLS_400002DETECTION_TOOL_NOT_AVAILABLE)。出處:api/detection_tools/serializers/detection_tool.py:43-47TenantDetectionToolConfigCreateRequest)、route TenantDetectionToolConfigsRoute.post、service detection_tool_service.py:72-90::create_tenant_config(route 層另有 @require_capability("plugin.update") 守門,見 §3)。

[PUT] /detection-tools/configs/{uid}

Request(全部選填,partial-update 語意——None 欄位不更新):

欄位 型別 說明
credentials object 有值時走 merge 語意(FR-058):先解密既有密文得舊 dict,新 key 逐個蓋上去後重新加密——只更新有送的欄位,未送的既有 secret 原封保留。FE 不帶(機敏欄位皆留空)→ None → repo update() skip,保留既有密文(幽靈覆寫防護)
field_values object 覆寫非機敏欄位
status string 單獨送 {status: "disabled"} 即可只切換啟用狀態(本頁「停用」按鈕即此用法)

merge 而非整包覆蓋(FR-058,BE 24dba59f:FE 只送有填值的 secret 欄位(UI 承諾「留空=沿用原值」)。舊實作把送來的 credentials 整包 encrypt 覆蓋,多 secret 欄位的工具部分更新時會洗掉沒動的憑證——CINC Auditor 三個 secret(ssh_private_key/ssh_password/winrm_password),實測「只存 SSH 私鑰 → WinRM 密碼遺失」。單一 secret 工具(OpenVAS / ZAP)merge 是等價操作,行為不變。merge 下「清空單一 secret」不支援(FE 留空不會送 key)——這是刻意的,整組清空走 §6.4 reset。

出處:api/detection_tools/serializers/detection_tool.pyTenantDetectionToolConfigUpdateRequest)、service detection_tool_service.py::update_tenant_config:92-116(merge 邏輯於 :102-107)(route 層另有 @require_capability("plugin.update") 守門,見 §3)。

FE 送出邏輯(ToolPluginManage.vue::buildPayload:151-170):遍歷扁平的 config_field_schema(憑證分區純屬排版、不參與 payload 計算),先依 isFieldVisible()condition 判斷)跳過不可見欄位(FR-057,避免未選分支殘留值送出),值為 null/undefined/空字串一律跳過(不塞進 payload);secret 欄位分流進 credentials,其餘進 field_valuescredentials 物件若無任何 key 則整個欄位設為 undefined(axios 序列化時省略),確保「全部留空=不動既有密文」。

6.4 重置 / 測試連線 / 引用計數

[POST] /detection-tools/configs/{uid}/reset

無 body。Response data{"success": true}。清空 credentials_encrypted 為 NULL(專用 clear_credentials 方法,區別於 update()None=skip 語意——重置要的正是清空,不能被 skip 邏輯擋住)。出處:service detection_tool_service.py:106-109::reset_tenant_config_key(route 層另有 @require_capability("plugin.update") 守門,見 §3)。

[POST] /detection-tools/configs/{uid}/test-connection

Request(全部選填,FR-057 新增):

欄位 型別 說明
host string|undefined requires_target_host=true 的工具(OpenSCAP / CINC Auditor / Nmap / GCB)指定測試主機——租戶層憑證不含 host(D1 決策),probe 需另外指定。可填多台(逗號/空白/分號分隔),BE 逐台各發一次 probe 並彙總(全部成功才算成功,訊息逐台列出);API 型工具(OpenVAS / ZAP)不需帶此欄
credential_group string|undefined (FR-058)宣告了 credential_group_schema 的工具(CINC Auditor / GCB)必填組別 key(如 "ssh" / "winrm"),未帶或不存在一律回失敗、不派 probe。BE 依該工具的 probe_param_key + 命中組別的 probe_param_value 自組 probe 參數(如 {"transport": "winrm"})。只收 key——FE 不得帶 probe 參數的 key 或 value

Response data{"success": bool, "message": string}

四種失敗訊息(皆 success=false,非 HTTP 錯誤):

情境 message(i18n key)
該設定未存憑證 detection_probe_no_credentials
本租戶無 detection_scan capability 的 Agent detection_probe_no_agent
憑證組別問題(FR-058) detection_probe_credential_group_required(宣告了組別卻未帶)/detection_probe_credential_group_unknown(帶了不存在的 key)/detection_probe_credential_group_schema_invalid(seed 宣告了 groups 卻缺 probe_param_key,屬資料缺陷非使用者可修)
Agent 連得到但工具端連不通/帳密錯 Agent 回傳的原始訊息(透傳)——OpenSCAP 分四段(連線失敗 / 認證失敗 / 未安裝 openscap-scanner / 缺少 SCAP content),任一段失敗即回該段訊息不續探

憑證組別失敗不寫 last_test_result:與「未設定憑證」「無可用 Agent」兩種前置失敗一致——沒真的測過,不該把 last_test_result 蓋成 fail 誤導後續判讀。

零回歸保證:無宣告組別的工具(八筆中的六筆)group_params 為空 → probe 呼叫完全不帶 params,形式與加入本機制之前逐字相同(硬性要求,不只是效果相同)。

出處:route TenantDetectionToolConfigTestConnectionRouteapi/detection_tools/routes/detection_tool_route.py:122-142,收 host + credential_group)、service detection_tool_service.py::test_connection:161-host 逐台 probe 彙總 FR-057;credential_group 解析 FR-058)、_resolve_credential_group_params:124-159;憑證合併邏輯(field_values + 解密後的 credentials)於 :212;派工帶 detection_tool_code(D11,CM-959)於 :219;實際 mTLS 直推見 infra/detection_tools/connector/agent_probe_client.pyPROBE_PATH = "/detection/probe")。

[GET] /detection-tools/configs/{uid}/referencing-tasks-count

無 query。Response data{"count": int}——D6 軟提醒,不擋停用/重置動作,僅供 FE 組確認訊息文案。出處:service detection_tool_service.py:169-180::count_referencing_tasks(解出 tenant_config → detection_tool_id 後查 job_execution_detection_tools 引用數)。

7. 前端檔案地圖(compliance-manager-fe/)

檔案 角色
src/views/plugin/ToolPluginManage.vue 主檢視(846 行):目錄+設定合併與排序(cardRank)、搜尋、設定 Dialog(FR-058:憑證組別分區並排 + 寬度動態)、啟用/停用(樂觀更新+回滾)、測試連線(FR-057 多台測試主機逐台彙總;FR-058 憑證組別選擇 + 兩軸聯集開窗)、重置金鑰、部署前提說明 Dialog(FR-058 逐段複製 + 加寬 64rem)、卡片 overflow menu 收納次要動作
src/components/detection-tools/DetectionConfigField.vue 動態欄位渲染元件(128 行):依 field.type 渲染 InputText/Password/InputNumber/Dropdown/Textarea/InputSwitch/editable Dropdown(後三者 FR-057 新增,對應 textarea/boolean/select_or_text),secret 遮罩邏輯 + condition 依賴顯示(FR-057)+ hint 填寫指引(FR-058)。group 欄位本元件不理,交父層排版
src/utils/detectionFieldValidation.js (FR-058)isDetectionFieldVisible() / findMissingRequiredDetectionFields()——condition 可見性與必填檢查抽成共用 util,讓本頁設定表單、任務配置頁掃描參數表單、DetectionConfigField 三處同源,不再各判一套
src/service/DetectionToolService.js API 包裝(75 行):listTools / listConfigs / createConfig / updateConfig / testConnection(body 帶 host / credential_group)/ getReferencingTaskCount / resetConfig / getParamSchema
src/config/router/index.js:614-627 route tool-plugin-manage,path /plugin/tool-plugin-manage
src/config/api/api.js:341-347 DETECTION_TOOLS / DETECTION_TOOL_CONFIGS / DETECTION_TOOL_TEST_CONNECTION / DETECTION_TOOL_REF_COUNT / DETECTION_TOOL_RESET / DETECTION_TOOL_PARAM_SCHEMA 常數
src/config/locales/i18n/{zh-tw,en}/pages.jsonplugin_manage namespace) 頁面 i18n:title/setup/coming_soon/field_required/secret_placeholder/reset_confirm/disable_with_refs 等 + 各工具說明(openvas_desc 等)
src/config/locales/i18n/{zh-tw,en}/menu.json 選單標題「檢測工具管理」——選單本身已完全啟用,非停用狀態(動態依帳號 permissions 顯示,非硬編停用清單)

8. 後端檔案地圖(本頁核心鏈路)

鏈路 Route App Service 底層
工具目錄 api/detection_tools/routes/detection_tool_route.py::DetectionToolsRoute(GET)/ DetectionToolDetailRoute app/detection_tools/service/detection_tool_service.py::list_tools / get_tool domain/detection_tools/service/detection_tool_domain_service.pyinfra/detection_tools/repository/detection_tool_repo_impl.py
租戶設定 CRUD TenantDetectionToolConfigsRoute(GET/POST)/ TenantDetectionToolConfigDetailRoute(PUT) DetectionToolService.list_tenant_configs / create_tenant_config / update_tenant_config(皆 @transaction domain/detection_tools/service/tenant_detection_tool_config_domain_service.pyinfra/detection_tools/repository/tenant_detection_tool_config_repo_impl.py
重置金鑰 TenantDetectionToolConfigResetRoute DetectionToolService.reset_tenant_config_key 同上 repo clear_credentials
測試連線 TenantDetectionToolConfigTestConnectionRoute DetectionToolService.test_connection infra/detection_tools/connector/agent_probe_client.py::AgentProbeClient(mTLS + 短效 JWT,直推 Agent)
引用計數 TenantDetectionToolConfigRefCountRoute DetectionToolService.count_referencing_tasks domain/detection_tools/service/job_execution_detection_tool_domain_service.py
參數 schema DetectionToolParamSchemaRoute(本頁不用,任務配置頁用) DetectionToolService.get_param_schema domain/detection_tools/service/detection_tool_param_schema_domain_service.py

DDD 提醒:route 不碰 DB、app service 全數 @transaction、domain service 不依賴 infra、repo 遵循既有分層。寫入端點(新增/編輯/重置)的守門在 route 層 @require_capability("plugin.update")(v1.12.0 起,主體域守門走 route decorator 屬 FR-048 允許形式,decorator 內委派 DI 注入的 guard service,route 本身不碰 session);測試連線/查引用數則完全無角色守門——改動時務必分開看待。

9. DB

9.1 資料表總清單(本頁讀寫的全部表)

讀/寫 說明 欄位詳述
config.detection_tools 平台工具目錄(種子資料,本頁不寫) §9.3
config.tenant_detection_tool_configs 租戶工具連線設定(加密憑證 + 非機敏欄位 + 狀態) §9.3
config.detection_tool_param_schemas 讀(間接,供 任務配置頁 工具任務參數 schema(版本化,is_current 標記生效版) §9.3
config.job_execution_detection_tools 讀(供引用計數) 任務↔︎工具綁定(本頁不寫,寫入在 任務配置頁 任務配置頁 §9.3

9.3 核心表欄位(取自 DEV DB dump)

config.detection_tools — 平台工具目錄

欄位 型別 說明
id bigint 內部主鍵(config.job_execution_detection_tools.detection_tool_id FK 目標)。FR-058(D11)起 id 不再是 agent 認 connector 的依據——派工 payload 改夾帶 detection_tool_code,agent factory 依 code 取 connector;舊的 _TOOL_ID_TO_CODE 固定映射(僅 id 1–4)退居 fallback,只在 payload 缺 code 的舊版 agent 情境生效
uid varchar(36) 對外識別碼
code varchar(50) 工具代碼(openvas/nessus/sonarqube/openscap/zap/inspec/nmap/gcb),FE 用來比對合併租戶設定、agent 用來取 connector
name / description varchar(255) / text 顯示名稱 / 說明(FR-058 全面擴充至 132–179 字)
connection_type varchar(20) API / CLI / SSH(DB comment:「決定 Agent executor 走哪條」)。FR-058 起不再作為 FE 行為判斷依據(見 §6.2 附註)
config_field_schema jsonb NOT NULL default [] 動態設定表單欄位定義:[{key, type, label, secret, required, options?, condition?, default?, group?, hint?}]condition/default FR-057,group/hint FR-058)
setup_guide text|null (FR-057 新增)部署前提說明 + 目標主機準備腳本,markdown
requires_credentials boolean NOT NULL default true (FR-058,2026-07-30-fr058-5)該工具是否需要租戶層憑證。false=零憑證工具,start_execution() 不擋空憑證。DB comment 明記「預設 TRUE(往嚴的方向失敗)」
requires_target_host boolean NOT NULL default false (FR-058,2026-07-30-fr058-7)測試連線是否需指定目標主機。DB comment 明記「取代 FE 原本硬判 connection_type=SSH 的耦合寫法;預設 FALSE(忘了宣告不會多問一個使用者答不出來的問題)」
credential_group_schema jsonb|null (FR-058,2026-07-31-fr058-9)互斥憑證組別宣告,形狀 {probe_param_key, prompt_label, groups:[{key,label,description,probe_param_value}]}。NULL=無組別,行為與加此欄前相同
status varchar(20) NOT NULL default coming_soon available / coming_soon
enabled boolean NOT NULL default true 平台層總開關

config.tenant_detection_tool_configs — 租戶工具連線設定

欄位 型別 說明
uid varchar(36) 對外識別碼
tenant_id bigint 租戶(RLS 隔離)
detection_tool_id bigint config.detection_toolsuq_tdtc_tenant_tool 唯一約束:每租戶每工具僅一筆設定)
credentials_encrypted text|null 機敏欄位加密後 JSON(對稱加密,金鑰 DETECTION_TOOL_ENCRYPTION_KEY 環境變數,不進版控)
field_values jsonb 非機敏欄位值(如 base_url
status varchar(20) enabled / disabled(預設 disabled
last_tested_at timestamp|null 最近一次測試連線時間
last_test_result varchar(20)|null success / fail

config.detection_tool_param_schemas — 工具任務參數 schema(版本化)

欄位 型別 說明
detection_tool_id bigint config.detection_toolsuq_dtps_tool_version 唯一約束:(detection_tool_id, version)
version int 版本號,遞增(如 OpenVAS v1→v2 新增 port_list_id 欄位)
param_schema jsonb 任務掃描參數欄位定義(供 任務配置頁 動態渲染)
is_current boolean 是否為當前生效版本(get_current_schema 依此篩選)

config_field_schema 的差異detection_tools.config_field_schema連線設定欄位(本頁用,如帳密/主機),detection_tool_param_schemas.param_schema任務掃描參數欄位(任務配置頁用,如 hosts/timeout_sec)——兩者是不同層次的 schema,命名相近容易混淆。

10. 頁面邏輯與資料對應

載入時序onMounted 平行觸發 listTools() + listConfigs(),FE 端依 detection_tool_code === tool.code 合併成 tools computed(工具卡片資料來源)。

關鍵欄位對應(畫面 ↔︎ API):

畫面元素 FE state API 欄位
工具卡片清單 tools(computed,目錄+設定合併) GET /detection-tools + GET /detection-tools/configs
設定 Dialog 欄位 form[field.key] tool.config_field_schema 動態產生,預填 tool.config.field_values
secret 欄位遮罩 DetectionConfigFieldhasExistingValue prop config.has_credentials
狀態 Tag 直接綁定 tool.config?.status(無設定 = 不顯示)
測試連線結果 toast test-connection 回傳 {success, message}

儲存流程onSaveConfig 先做 client 端必填檢查(略過已有憑證的 secret 欄位)→ buildPayload() 分流 credentials/field_values →建立走 POST、既有走 PUT → 成功後關閉 Dialog + fetchAll() 整頁重新整理(非局部更新)。

錯誤對應:BE error envelope → toast 顯示;本頁常見碼:DETECTION_TOOLS_400002(工具非 available 不可新增設定)、DETECTION_TOOLS_404002(設定不存在)。測試連線刻意不用例外,而是回 {success:false, message},避免整頁被連線失敗中斷。

11. 背景行為與外部依賴

類型 內容
通知 無——本頁不觸發、也不消費任何通知
Socket 無 socket / 輪詢;動作後皆整頁 fetchAll()
mTLS / Agent 直推 測試連線走 FR-039 既有 mTLS 通道(AgentProbeClientmode=full 時 mTLS client 憑證 + 短效 JWT;mode=none 裸 HTTP demo),與真實掃描派工共用同一認證機制。payload 一律帶 detection_tool_code(FR-058 D11/CM-959——probe 是心跳以外的第二條派工路徑,早期漏帶導致新工具被 fallback id 表誤判為「尚無 connector 實作」);要主機的工具多帶 host;宣告了憑證組別的工具多帶 params(如 {"transport": "winrm"}
憑證加密 DETECTION_TOOL_ENCRYPTION_KEY(BE 部署環境變數,非資料庫值,不進版控)——對稱加密租戶填寫的機敏欄位;api_log 對本模組請求 body 遮罩憑證欄位,不落明文(D9,e2eb1c2c 修正)。FR-058 另加任務層敏感參數加密tool_paramssecret:true 欄位,如 ZAP 登入後掃描的測試密碼)——同一把金鑰、不同機制(JSONB 內挑欄位加密的自我描述 envelope),詳見 任務配置頁
jedi-* 套件 無直接依賴(本模組為 FR-056 全新自研,未借用既有 jedi-* 套件)
系統參數 DETECTION_TOOL_ENCRYPTION_KEY(環境變數,非 DB feature flag)

12. 邊界情況與已知坑

  1. 寫入守門復用 plugin.update,非獨立的 detection-tools-manage.* capability:v1.12.0 守門下放(見 §3)選擇復用 tool-plugin-manage 頁既有的 plugin.* capability(三環境已 seed 已配角色,零 migration),而非另 seed 一組 detection-tools 專屬能力點——語意上「檢測工具管理頁的 update 權」與「工具設定寫入權」目前是同一顆勾,日後若要拆分頁面可見性與設定寫入權,需另開 capability。
  2. 測試連線 / 查引用數完全無角色守門:僅 @jwt_required(),任何登入者理論上都能對已知 config uid 呼叫測試連線——與寫入動作(含停用,走 PUT 已納 plugin.update 守門)形成不一致的守門粒度,改動時勿混為一談。
  3. 停用後任務配置頁下拉未過濾 statusconfig.tenant_detection_tool_configs.status='disabled' 後,任務配置頁的工具下拉來源是 GET /detection-tools(工具目錄,非租戶設定),本身不檢查租戶設定狀態——理論上使用者仍可能選到一個已停用設定的工具,實際派工時會因缺憑證(_resolve_credentials 找不到 enabled 設定)失敗。此為現況行為,未做前端過濾。
  4. config_field_schema(連線設定)與 param_schema(任務參數)是兩層不同 schema:命名相近但用途、消費頁面都不同(見 §9.3 附註),維護時勿混淆——改一邊不會影響另一邊。
  5. 憑證合併邏輯:測試連線時 field_values(如 base_url)與解密後的 credentials(如 password)需合併才是完整連線資訊(test_connection:212),單看其中一邊資訊不全——早期版本曾漏合併(b26f83f1 修正)。
  6. credentials 全空時整個欄位省略,非傳空物件:FE buildPayload() 若無任何 secret 欄位有值,credentials 設為 undefined(非 {})——若改成送空物件 {},BE creds = payload.get("credentials") 會判定為 truthy(非 None)而觸發加密覆寫,把既有密文洗成加密後的空字串,是需要留意的坑(現況實作正確,記錄供未來重構參考)。
  7. coming_soon 工具無法被選為連線設定或任務綁定create_tenant_config 明確擋 status != 'available'DETECTION_TOOLS_400002),FE 也把按鈕全部隱藏——nessus 目前只是目錄佔位,尚無 Agent connector 實作(sonarqube 已於 FR-058.5 上架轉 available,僅 DEV)。
  8. connection_type 不足以描述連線行為,勿再用它做判斷(FR-058):CINC Auditor / GCB 同時支援 SSH 與 WinRM 兩種 transport,但 connection_type 只能填一個值(現填 SSH 純為滿足 NOT NULL)。FE 原本硬判 connection_type === 'SSH' 決定要不要問測試主機,第二批 seed CINC Auditor 時實地撞到——需不需要問主機取決於「憑證含不含 host」,與走哪種協定無關。已改由 requires_target_host 宣告;credential_group_schema 則承載「有幾組互斥憑證」。新增判斷時一律加宣告欄位,不要回頭讀 connection_type。另有 CLI 型態值(本機執行、不經 SSH)已定義於 comment 但尚未有任何工具實際使用,屬未來擴充預留(Nmap 原規劃走 CLI,D9 改案後改 SSH 型)。
  9. SSH 型工具的憑證=租戶層一組共用稽核帳號:所有目標主機須用同名帳號 + 同一把私鑰/密碼登入(Tenable 業界慣例),非每台各自帳密——host inventory(每台各自憑證)是明列的未來範圍,本版不支援。CINC Auditor / GCB 的 WinRM 組同理(一組 Windows 管理員帳密掃全部 Windows 目標)。
  10. 憑證組別「不猜」是刻意設計(FR-058):宣告了 credential_group_schema 的工具,測試連線一律要求使用者明確選一組,不做自動偵測、不預選第一組。「填了哪組就用哪組」在兩組都填齊時(客戶同時有 Linux 與 Windows 目標)猜不出來,猜錯產生的正是本案要消滅的誤導訊息。日後若有人想「優化成自動判斷」,先看這條。
  11. CINC Auditor / GCB 的 config_field_schema 逐字相同是刻意的:兩者同一顆引擎、同一組連線參數,seed 時刻意保持逐字一致(含 hint 文案),讓日後改一邊時 diff 能一眼看出另一邊是否漏改。改任一邊務必同步另一邊
  12. 憑證分區只是排版,payload 走扁平 schema:FE buildPayload() 遍歷的是扁平 config_field_schema、不看 group;分區與送出兩條路徑不會分歧。group 對不到任何宣告群組的欄位會降級顯示在無分區區塊(不靜默丟掉)——若看到某欄位跑到最上面沒有分區標題,多半是 seed 的 field.groupcredential_group_schema.groups[].key 拼錯。
  13. credential_group_schemaprobe_param_key/probe_param_value 會整包 dump 給 FE:serializer 是 fields.Raw(allow_none=True) 原樣輸出,FE 契約上只准回傳 groups[].key。若日後改由 FE 直接送 probe 參數,等於讓瀏覽器指定送進 agent connector 的參數,是注入面——設計已明確排除,勿回頭走。
  14. ZAP 對單頁式應用(SPA)不可使用登入後掃描——營運級風險,非單純掃不到logged_in_indicator 比對的是伺服器回應的原始內容,SPA 的畫面文字是取得回應後才由瀏覽器產生,比對不到 → ZAP 判定尚未登入而反覆重試 → 認證失敗累積到 ZAP 2.17.0 的保護門檻後 daemon 主動停止自己;而 ZAP 是全租戶共用服務,一旦停止會連帶中斷其他租戶正在執行的掃描。本頁 ZAP 卡片的 setup_guide 已明白標示「請勿對單頁式應用使用登入後掃描」(2026-07-30-fr058-{3,4} 兩支 migration 補寫與更正)。被動 / 主動掃描不需登入、不受影響。設定連線資訊時的可控項只有 base_url/api_key,此限制實際發生在 任務配置scan_mode='authenticated' 時。
  15. config.detection_tools 沒有 i18n 機制(平台級缺口,FR-056 建表即存在)name / description / setup_guide / config_field_schemaparam_schemalabelhintoptions[].label 全是中文寫死在 DB,切英文介面時本頁工具卡片與所有動態表單欄位仍是中文。FR-058 大幅擴充描述文案與 hint 之後,缺口的可見面積更大。已知並暫緩處理,非本輪範圍。
  16. ⚠️ STG / POC 的工具目錄領先其 agent 版本(2026-07-31 實查):FR-058 共 13 支 migration,前 11 支已誤套進三個環境(違反環境異動鐵律,事故已記錄於 CLAUDE.mdsql-migration skill),最後兩支(fr058-12 描述文案擴充、fr058-13 GCB Demo profile 選項)只在 DEV。後果:STG / POC 的目錄同樣顯示八筆、四款新工具皆 available,但兩地 agent 版本尚無對應 connector——使用者若在那兩個環境設定憑證並派工,會拿到跑不動的結果(目前租戶設定 0 筆、派工 0 筆,尚無實害)。上版時須連同 agent 部署一併處理;在此之前不要以「三環境目錄一致」推論「三環境功能一致」。

13. 開發與驗證

  • 跑起來:BE python main_socketio.py(port 8000,log 在 log/app.log);FE 在 compliance-manager-fe/ 起 Vite dev server。BE 改 service code 後必須重啟(無 hot reload)
  • 測試帳號:dev 環境持 plugin.update capability 的帳號(角色權限矩陣「檢測工具管理」有 update 勾;系統層 super_admin 亦可 break-glass),密碼見 .env / 部署文件——新增/編輯/重置需此權限
  • 導航路徑:登入 → 合規稽核 → 「檢測工具管理」(/plugin/tool-plugin-manage
  • 前置資料config.detection_tools 需已 seed——FR-056 建表 scripts/sql/2026-07-26-fr056-1-detection-tools-config-schema.sql、FR-057 2026-07-28-fr057-1-openscap-seed.sql、FR-058 共 13 支 2026-07-3{0,1}-fr058-*.sql(DEV 全數已套,STG/POC 見 §12 坑 14)。測試連線需本租戶已部署具 detection_scan capability 的 Agent(見 檔案 Agent 管理 §12 坑 10——capabilities 欄位目前僅能直接改 DB 設定);各工具目標端前提差異大,一律先看該工具卡片的「部署前提說明」(setup_guide)——OpenSCAP 需目標主機已裝 openscap-scanner + SSG content;CINC Auditor / GCB 引擎裝在 Agent 端主動連出、目標主機不需裝掃描程式(與 OpenSCAP 相反);Nmap 需執行主機(非掃描目標)自行安裝 nmap;ZAP 需客戶自備可連線的 ZAP daemon
  • E2Ecompliance-manager-test/ repo(Cucumber + Playwright);以 檢測工具 / detection-tool / tool-plugin 搜尋
  • 相關文件:完整使用手冊見 docs/features/FR-056-2607-detection-tool-integration/user-manual.html;任務綁定與掃描參數見 任務配置與啟動;執行歷史與重新執行/取消機制見 任務執行抽屜;Agent capabilities 設定見 檔案 Agent 管理;FR-057 設計決策見 docs/features/FR-057-2607-openscap-ssh-connector/design.md;FR-058 決策表 D1–D34(四工具接入 D1–D12:含 ZAP 對 SPA 的營運級限制 D12、Nmap 改 SSH 型的 D9 改案與 NPSL 授權依據、GCB 複用 CINC 引擎的 D7;SonarQube 拉取 D13–D16、主動掃描 D17–D24、上傳掃描 D25–D34)見 docs/features/FR-058-2607-detection-tools-expansion/design.md §2 / §4.6–§4.8