檢測工具管理(Detection Tool Management)
事實基準:2026-08-01 從 FE
src/views/plugin/ToolPluginManage.vue(846 行)+ BEapp/detection_tools/全模組 + DEVconfig.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 型別區別、寫入行為告知與收緊模式做法),status 轉
available——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
gcb,available 由兩款增為六款)。平台能力:①
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 | 上線第二款檢測工具
OpenSCAP(connection_type='SSH',第三種連線型態);config_field_schema
的 type 擴充
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 序)——七筆
available:OpenVAS(網路弱點掃描)、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)與平台層
status(available/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 | 啟用 / 停用 | 已有設定的工具可切換
status(enabled/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_values →
POST(新增)或 PUT(編輯)→ 成功關閉 Dialog
並重整清單。
憑證部分更新採 merge 語意(FR-058,BE
24dba59f):FE 只送「有填值」的 secret 欄位(UI 承諾「留空=沿用原值」),BEupdate_tenant_config帶credentials時先解密既有密文、以新 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 解密該租戶已存憑證 →
挑一台本租戶啟用中、capabilities 含
detection_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),不互等。
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_403022(GRC_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-34、ToolPluginManage.vue::isFieldVisible:173(委派
utils/detectionFieldValidation.js) |
tool.requires_target_host === true(FR-058,取代原
connection_type === 'SSH' 硬判) |
按「測試連線」不直接打 API,先彈 Dialog 要求輸入測試主機(見 UC-TPM-02) | ToolPluginManage.vue::testDialogNeedsHost:283、onTestConnectionCard:315-328 |
tool.credential_group_schema.groups 非空(FR-058) |
① 設定 Dialog 依 field.group
把欄位切成獨立面板分區呈現;② 按「測試連線」先彈 Dialog
要求選一組憑證 |
ToolPluginManage.vue::groupedFieldSections:192-197、testDialogNeedsGroup: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):
📸 實機截圖待補:工具卡片 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
落單」,窄螢幕自動降單欄。做成獨立面板而非只用一條分隔線,是因為「這兩組是分開的、只需填要掃的那一組」正是要傳達的核心訊息,一條細線在並排時讀起來仍像同一張連續表單。沒有
group 或 group
對不到任何宣告群組的欄位一律降級放最前面的無分區區塊(絕不靜默丟掉——使用者填不到欄位遠比排版不完美嚴重)。分區純屬排版:送出一律以扁平
config_field_schema
為準(buildPayload),分組不參與 payload
計算。出處:ToolPluginManage.vue::credentialGroups:182/ungroupedFields:186-189/groupedFieldSections: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-50、copyCodeBlock: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?}]——type
為
text/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/gcb
為 true |
| credential_group_schema | object|null | (FR-058
新增)互斥憑證組別宣告,形狀見下方專表。null=無組別,設定頁與測試連線行為與加此欄前相同;DEV
現況僅 inspec/gcb 有值 |
| status | string | available / coming_soon |
| enabled | bool | 平台層總開關(list_tools 以
get_tools(enabled=True) 過濾;coming_soon
仍會回傳,由 FE 灰化) |
config_field_schema 各欄位屬性:
| 屬性 | 型別 | 說明 |
|---|---|---|
| key / label / type | string | 欄位鍵 / 顯示標籤 / 渲染型態 |
| required | bool | 是否必填——不受 condition
隱藏影響時才生效:欄位因 condition
不符而不可見時一律跳過必填驗證(不可見分支不該擋送出) |
| secret | bool | true 進
credentials(加密存放);false 進
field_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 預設 22、winrm_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.group;label/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.py(DetectionToolResponse,FR-058
新增 requires_credentials /
requires_target_host /
credential_group_schema)、route
DetectionToolsRoute、service
detection_tool_service.py::list_tools(get_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 Token(squ_
前綴);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_key皆required=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}-*.sql、2026-07-31-fr058-{9,10,...,19}-*.sql、2026-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_configs 依
detection_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-40(TenantDetectionToolConfigResponse.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_400002(DETECTION_TOOL_NOT_AVAILABLE)。出處:api/detection_tools/serializers/detection_tool.py:43-47(TenantDetectionToolConfigCreateRequest)、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.py(TenantDetectionToolConfigUpdateRequest)、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_values;credentials 物件若無任何 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
TenantDetectionToolConfigTestConnectionRoute(api/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.py(PROBE_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.json(plugin_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.py
→
infra/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.py
→
infra/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_tools(uq_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_tools(uq_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 欄位遮罩 | DetectionConfigField 的 hasExistingValue
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
通道(AgentProbeClient,mode=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_params 內
secret:true 欄位,如 ZAP
登入後掃描的測試密碼)——同一把金鑰、不同機制(JSONB
內挑欄位加密的自我描述 envelope),詳見 任務配置頁 |
| jedi-* 套件 | 無直接依賴(本模組為 FR-056 全新自研,未借用既有 jedi-* 套件) |
| 系統參數 | DETECTION_TOOL_ENCRYPTION_KEY(環境變數,非 DB feature
flag) |
12. 邊界情況與已知坑
- 寫入守門復用
plugin.update,非獨立的detection-tools-manage.*capability:v1.12.0 守門下放(見 §3)選擇復用 tool-plugin-manage 頁既有的plugin.*capability(三環境已 seed 已配角色,零 migration),而非另 seed 一組 detection-tools 專屬能力點——語意上「檢測工具管理頁的 update 權」與「工具設定寫入權」目前是同一顆勾,日後若要拆分頁面可見性與設定寫入權,需另開 capability。 - 測試連線 / 查引用數完全無角色守門:僅
@jwt_required(),任何登入者理論上都能對已知 config uid 呼叫測試連線——與寫入動作(含停用,走 PUT 已納plugin.update守門)形成不一致的守門粒度,改動時勿混為一談。 - 停用後任務配置頁下拉未過濾
status:config.tenant_detection_tool_configs.status='disabled'後,任務配置頁的工具下拉來源是GET /detection-tools(工具目錄,非租戶設定),本身不檢查租戶設定狀態——理論上使用者仍可能選到一個已停用設定的工具,實際派工時會因缺憑證(_resolve_credentials找不到enabled設定)失敗。此為現況行為,未做前端過濾。 config_field_schema(連線設定)與param_schema(任務參數)是兩層不同 schema:命名相近但用途、消費頁面都不同(見 §9.3 附註),維護時勿混淆——改一邊不會影響另一邊。- 憑證合併邏輯:測試連線時
field_values(如base_url)與解密後的credentials(如password)需合併才是完整連線資訊(test_connection:212),單看其中一邊資訊不全——早期版本曾漏合併(b26f83f1修正)。 credentials全空時整個欄位省略,非傳空物件:FEbuildPayload()若無任何 secret 欄位有值,credentials設為undefined(非{})——若改成送空物件{},BEcreds = payload.get("credentials")會判定為 truthy(非 None)而觸發加密覆寫,把既有密文洗成加密後的空字串,是需要留意的坑(現況實作正確,記錄供未來重構參考)。coming_soon工具無法被選為連線設定或任務綁定:create_tenant_config明確擋status != 'available'(DETECTION_TOOLS_400002),FE 也把按鈕全部隱藏——nessus目前只是目錄佔位,尚無 Agent connector 實作(sonarqube已於 FR-058.5 上架轉available,僅 DEV)。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 型)。- SSH 型工具的憑證=租戶層一組共用稽核帳號:所有目標主機須用同名帳號 + 同一把私鑰/密碼登入(Tenable 業界慣例),非每台各自帳密——host inventory(每台各自憑證)是明列的未來範圍,本版不支援。CINC Auditor / GCB 的 WinRM 組同理(一組 Windows 管理員帳密掃全部 Windows 目標)。
- 憑證組別「不猜」是刻意設計(FR-058):宣告了
credential_group_schema的工具,測試連線一律要求使用者明確選一組,不做自動偵測、不預選第一組。「填了哪組就用哪組」在兩組都填齊時(客戶同時有 Linux 與 Windows 目標)猜不出來,猜錯產生的正是本案要消滅的誤導訊息。日後若有人想「優化成自動判斷」,先看這條。 - CINC Auditor / GCB 的
config_field_schema逐字相同是刻意的:兩者同一顆引擎、同一組連線參數,seed 時刻意保持逐字一致(含hint文案),讓日後改一邊時 diff 能一眼看出另一邊是否漏改。改任一邊務必同步另一邊。 - 憑證分區只是排版,payload 走扁平 schema:FE
buildPayload()遍歷的是扁平config_field_schema、不看group;分區與送出兩條路徑不會分歧。group對不到任何宣告群組的欄位會降級顯示在無分區區塊(不靜默丟掉)——若看到某欄位跑到最上面沒有分區標題,多半是 seed 的field.group與credential_group_schema.groups[].key拼錯。 credential_group_schema的probe_param_key/probe_param_value會整包 dump 給 FE:serializer 是fields.Raw(allow_none=True)原樣輸出,FE 契約上只准回傳groups[].key。若日後改由 FE 直接送 probe 參數,等於讓瀏覽器指定送進 agent connector 的參數,是注入面——設計已明確排除,勿回頭走。- 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'時。 config.detection_tools沒有 i18n 機制(平台級缺口,FR-056 建表即存在):name/description/setup_guide/config_field_schema與param_schema的label、hint、options[].label全是中文寫死在 DB,切英文介面時本頁工具卡片與所有動態表單欄位仍是中文。FR-058 大幅擴充描述文案與 hint 之後,缺口的可見面積更大。已知並暫緩處理,非本輪範圍。- ⚠️ STG / POC 的工具目錄領先其 agent 版本(2026-07-31
實查):FR-058 共 13 支 migration,前 11
支已誤套進三個環境(違反環境異動鐵律,事故已記錄於
CLAUDE.md與sql-migrationskill),最後兩支(fr058-12描述文案擴充、fr058-13GCB 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.updatecapability 的帳號(角色權限矩陣「檢測工具管理」有 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-0572026-07-28-fr057-1-openscap-seed.sql、FR-058 共 13 支2026-07-3{0,1}-fr058-*.sql(DEV 全數已套,STG/POC 見 §12 坑 14)。測試連線需本租戶已部署具detection_scancapability 的 Agent(見 檔案 Agent 管理 §12 坑 10——capabilities 欄位目前僅能直接改 DB 設定);各工具目標端前提差異大,一律先看該工具卡片的「部署前提說明」(setup_guide)——OpenSCAP 需目標主機已裝openscap-scanner+ SSG content;CINC Auditor / GCB 引擎裝在 Agent 端主動連出、目標主機不需裝掃描程式(與 OpenSCAP 相反);Nmap 需執行主機(非掃描目標)自行安裝 nmap;ZAP 需客戶自備可連線的 ZAP daemon - E2E:
compliance-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