| 項目 | 內容 |
|---|---|
| 交接日期 | 2026-07-27 |
| 緣由 | 中繼交接(context 已長,arc 未完)——CM-929 三輪修正已完成待複測,後面還有任務 |
| Branch(三 repo 同名) | feature/scan-plugin-integration(不可切 branch) |
| Notion case | CM-929 3aa346da-4cd0-8191-9fba-c4fb2474820f,狀態 修正待驗證 |
| 現況一句話 | CM-929 本體 + 五條驗收回饋(#1~#5)全數實作完成並各自 commit;唯一擋住最終驗收的是「123 那台 agent 尚未重 build」(Claude 無 SSH 權限) |
| 下一棒主要任務 | ① 等 user 重 build agent 後複測 ② push 決策 ③ 後續 user 指派的新任務 |
| 接手前必讀 | 本文件 §0 讀序;Notion CM-929 卡(含五條回饋原文 + 三輪回報) |
這件事要解決什麼問題:檢測工具(OpenVAS)的「測試連線」功能,原本是雲端後端自己用 httpx.head 直連掃描器。兩個致命錯:
http:// 前綴,使用者填「192.168.50.123」直接報 missing protocol。而真實掃描的 connector 早就在 agent 端(客戶內網,走 python-gvm)——等於「測試連線」跟「真實掃描」是兩套不同的連線邏輯,違反單一真相原則:測得通不代表掃得動,反之亦然。
目標模型(2026-07-27 user 拍板案 1「雲端直推」):
UI 按「測試連線」
→ BE 解密該租戶憑證
→ 挑該租戶有 detection_scan capability 的 agent
→ mTLS POST https://<agent>/detection/probe { tool 設定, credentials }
→ agent: OpenVasConnector.probe() = TLSConnection + gmp.authenticate(不建 target、不掃描)
→ 同步回 { success, message }(1~3 秒)
→ BE record_test_result + 回 UI
刻意不走任務化(不動 agent_tasks schema、不加 kind 欄位、不縮心跳):任務化鏈路是為長時掃描設計的,probe 是秒級互動操作,走 FR-039 既有的即時 mTLS 通道即可。當初 case 內文原本寫的是任務化方案,因心跳間隔 300 秒(按下去最壞等 5 分鐘)而改案。
本棒在大圖的位置:FR-056(檢測工具整合平台)子需求 56.1~56.4 已全數驗收放行;56.5 是端到端實測時發現的架構缺陷修正,屬 FR-056 收尾前的最後一塊。
🔒 需求 gate(全讀,擺在機械步驟之前)
3aa346da-4cd0-8191-9fba-c4fb2474820f — 含背景 / 目標 / 設計 / 驗收 / 五條驗收手測回饋原文 / 三輪完成回報docs/features/FR-056-2607-detection-tool-integration/handoff/2026-07-27-fr0565-probe-and-e2e-handoff.md — 前一棒交接(FR-056 整體脈絡、部署現況、累積收尾待辦)再讀實作 4. app/detection_tools/service/detection_tool_service.py::test_connection — 雲端 probe 入口 5. infra/detection_tools/connector/agent_probe_client.py — 雲端→agent mTLS client(本 arc 新增) 6. ~/Projects/Billows/Audit-Manager/evidence-agent/api/detection/routes/detection_route.py — agent probe 端點(本 arc 新增) 7. ~/Projects/Billows/Audit-Manager/evidence-agent/core/task_executor_connectors/openvas.py — probe() 與 run() 共用連線邏輯 8. app/grc/service/task_execution_service.py::_auto_dispatch_detection_scans — #5 發佈時自動派掃描
probe() 與 run() 為何一定要共用 _resolve_connection_settings / _gmp?| # | 內容 | Repo | Commit | 狀態 |
|---|---|---|---|---|
| 本體 | 測試連線改走 agent + 移除 OpenVasProbe |
BE | cadec5a5 |
✅ 已 push |
| 本體 | agent probe() + /detection/probe 端點 + python-gvm 25.1→27.5 |
agent | 3ed125f |
✅ 已 push |
| 本體 | FE 顯示 agent 回傳失敗原因 + 兩個實測 bug fix | FE | 6380818 |
✅ 已 push |
| #1 | 移除設定 dialog 內測試連線按鈕(誤導性),只留卡片 | FE | dbea4a5 |
⏳ 未 push |
| #2 | probe 失敗訊息去技術化(翻人話 + 未知留原文) | agent | 6df02e2 |
⏳ 未 push |
| #3 ⛔ | 派工憑證 fallback 反查(原本真實掃描必失敗) | BE | a0d593ab |
⏳ 未 push |
| #4 | MyTasksView detection badge + 完成條件 tooltip | FE | b56580e |
⏳ 未 push |
| #5 ⭐ | 規劃頁發佈時自動派第一次掃描 | BE | 538d8da0 |
⏳ 未 push |
三 repo working tree 皆乾淨(無未 commit 改動)。
python-gvm 版本不相容:123 的 Greenbone community stack 講 GMP 22.7,agent 原 pin 的 python-gvm 25.1 只認到 22.5,一連上去就 GvmError: unsupported version of GMP。這條連真實掃描一起堵死,不只 probe。已 bump 到 >=27.5,<28.0(27.x 起才有 GMPv227),並對 123 的真實掃描器實測 authenticate 成功。
| 項目 | 方法 | 結果 |
|---|---|---|
agent probe() 對真實 OpenVAS |
本機以新 connector 直連 123(經 socat TLS bridge:9390) | 成功登入 |
| probe route 四情境 | Flask test_client + 真實憑證打真實掃描器 | 正確憑證 ✅ / 錯密碼「Authentication failed」/ 連不到「Network is unreachable」/ 未支援工具明確訊息 |
| BE→agent mTLS 通道 | BE 起服務打真實 API | 2 秒內走到 123 的 agent |
agent /health /agent-info |
以 BE 憑證 mTLS 直打 | 200(證明 mTLS 鏈路本身沒問題) |
| #3 憑證 fallback | DEV 真實資料唯讀查(全程 rollback) | job 13342 / 13362 兩筆 tenant_config_id=NULL 皆解出完整 base_url/port/username/password;未設定工具回空並記 warning |
| #5 狀態可見性 | DEV 真實資料,壓回 TODO→activate→同 transaction 重查(全程 rollback) | 讀得到 PROCESSING ✅(若讀到舊狀態,自動派工會 100% 被狀態檢查擋掉) |
| DI 循環相依 | 實際 boot app 後解 service | 兩方向都解得出、Singleton 共用同一實例 |
| user 手測測試連線 | user 自行操作 | DB tenant_detection_tool_configs.last_test_result = success |
唯一缺口:從 UI 完整走一遍。 123 上跑的仍是 0.2.0 舊映像檔,沒有 /detection/probe 端點。
/definitely/not/a/route 對照確認),不是 404。# 若回 500 → 還沒重 build;回 200/400 → 已重 build(400 = 缺參數,代表端點存在)
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be && source .venv/bin/activate
python - <<'EOF'
import sys; sys.path.insert(0,'.')
from dotenv import load_dotenv; load_dotenv('.env')
import httpx
from common.util.agent_auth.settings import get_agent_auth_settings
from common.util.agent_auth.tls import build_cloud_mtls_context
from common.util.agent_auth import jwt_util
s = get_agent_auth_settings()
FP = "8af59700811b14da49afe4dbfe4c8a3e1e2fccb59d23602a22b2ce0d3d06c520"
tok = jwt_util.mint(agent_uid="f8136df9-c062-45dd-8f39-ba91fc5e6e3a",
op="POST /detection/probe", tenant_id=102, bound_fp=FP)
with httpx.Client(verify=build_cloud_mtls_context(s), timeout=20) as c:
r = c.post("https://192.168.50.123:8443/detection/probe", json={},
headers={"Authorization": f"Bearer {tok}"})
print("status:", r.status_code, r.text[:200])
EOFrebuild.sh。三 repo 各有未 push commits(見 §1)。push 永遠等 user 明確指示,不自動 push。
前提:123 的 agent 已重 build(rebuild.sh)。 BE 已重啟、FE 熱更新。
| # | 操作 | 預期 |
|---|---|---|
| 本體 | 檢測工具管理頁卡片按「測試連線」 | 2 秒內顯示連線成功 |
| #2 | 故意打錯密碼 | 顯示「認證失敗,請檢查帳號密碼」,不再有 GvmResponseError 字樣 |
| #2 | 位址改成不存在 IP(如 192.168.50.199) | 「無法連線至檢測工具,請檢查位址與埠號」 |
| #1 | 開設定 dialog | 裡面沒有測試連線按鈕;卡片上那顆還在 |
| #4 | 「我的任務」頁看檢測工具任務 | 類型欄顯示紫色盾牌「檢測工具」badge(以前空白) |
| #4 | 尚無報告時滑過完成按鈕 | tooltip「尚未有成功的掃描報告,請先執行檢測工具掃描」 |
| #5 ⭐ | 規劃頁按「開始執行任務」 | detection 任務自動出現派工(不必進抽屜按) |
| #5 | 再按一次「開始執行任務」 | 不應對同一任務重複派工(冪等) |
| #5 | 混合場景(general + survey + detection 同批) | 只有 detection 派掃描,其他不受影響 |
| 回歸 | 抽屜手動「開始執行」按鈕 | 仍在、仍可用(重掃入口) |
| 回歸 | base_url 填「192.168.50.123」不加 http:// |
能通(原 case 死因之一) |
| 回歸 | port 欄位 | 顯示 9390 不是 9,390 |
| 回歸 | 已存過密碼的欄位留空存檔 | 不跳必填紅字 |
#5 不需等重 build 就能驗(派工是雲端行為):
-- 按下「開始執行任務」後查,應新增列且 _credentials 有值
SELECT id, uid, status, detection_tool_id,
params->'_credentials' ? 'base_url' AS has_base_url,
params->'_credentials' ? 'password' AS has_password
FROM compliance.agent_tasks ORDER BY id DESC LIMIT 5;
SELECT id, job_execution_uid, status, agent_task_uid
FROM compliance.detection_executions ORDER BY id DESC LIMIT 5;# 1. 三 repo branch 必須都是 feature/scan-plugin-integration(不對就停下問 user,不要自己切)
for d in compliance-manager-be evidence-agent compliance-manager-fe; do
printf "%-26s " "$d"; git -C ~/Projects/Billows/Audit-Manager/$d branch --show-current
done
# 2. working tree 應乾淨(除 docs/ 未追蹤檔)
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-be status --short | grep -v '^??'
# 3. BE 是否在跑(port 8000)
lsof -ti:8000 || echo "BE 未啟動 → cd BE && source .venv/bin/activate && nohup python main_app.py >/dev/null 2>&1 &"
# 4. 測試 smoke
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be && source .venv/bin/activate
python -m pytest test/test_task_execution_service.py test/test_detection_orchestration.py \
test/test_detection_tool_connection.py test/test_agent_probe_client.py \
test/test_remote_agent_capability_filter.py -q | tail -3 # 應 87 passed 那組的子集
cd ~/Projects/Billows/Audit-Manager/evidence-agent && PYTHONPATH=. poetry run pytest test/ -q | tail -3 # 27 passed⚠️ 全樹 pytest 有 115 個既有失敗(test-isolation 債,前一棒 handoff 已載明)+ 9 個 collection error(ai_dashboard / module_frame 模組)。這些不是本 arc 造成的 —— 本 arc 有做過 before/after 逐項比對,零新增失敗。不要花時間追。
probe() 與 run() 必須共用連線邏輯(_resolve_connection_settings / _gmp)——這是本 case 的核心價值:「測得通 = 掃得動」。若日後有人為 probe 另寫一套連線,等於把已修好的問題重新製造一次。
probe 失敗回 200 + success=false,不回 5xx —— 連不通是「探測結果」不是伺服器錯誤。回 5xx 會讓雲端只看到通用錯誤、使用者無從判斷。
/detection 必須列入 agent 資料面受保護前綴(core/data_plane_auth.py 的 _PROTECTED_PREFIXES)—— 這條會收到租戶明文憑證,漏掉等於把「拿憑證連內網掃描器」的能力對外裸奔。已有測試守著(test_detection_path_is_data_plane_protected)。
#3 採 A 案(查詢時 fallback)而非 B 案(綁定時寫入) —— 使用者常「先建任務、後設工具憑證」,綁定當下 config 未必存在。job_execution_detection_tools.tenant_config_id 這個欄位從來沒有人寫入過,是否退役留待 FR-056 收尾討論。
#5 每筆派工包 SAVEPOINT 不是可有可無 —— @transaction 是 reentrant(共用同一 session),start_execution 拋錯會讓外層 transaction 進 aborted 狀態;只用 try/except 的話,後續任務與整批發佈會一起陪葬。
#5 失敗的任務不自動重派 —— 重試是抽屜按鈕的職責。自動重派會讓每按一次發佈就在掃描器疊一份。
DI 循環相依用「宣告後回頭 override」 —— detection_tools 與 remote_agent 互相需要(前者測連線要找 agent、後者心跳要憑證解密 D9)。已驗證兩方向都解得出且 Singleton 共用。
tenant_config_id 欄位退役 —— 留 FR-056 收尾討論src/ 內無任何元件連入),v2 正式入口 ProjectPlanningView 已完整支援。依回饋指示不盲目加my-tasks.json 整檔不存在,屬既有整體缺漏,不單點補after_request api_log update failed: cannot adapt type 'dict' —— 既有無關 bug(api_logs 寫入 dict 塞 VARCHAR),洗 log,另案feature/scan-plugin-integration,branch 不對停下問 usergit add 檔名、禁用 -ampython main_app.py,port 8000,log 在 log/app.log);FE 熱更新| 項目 | 值 |
|---|---|
| Notion CM-929 | 3aa346da-4cd0-8191-9fba-c4fb2474820f(狀態:修正待驗證) |
| Notion 母案 CM-907 | 3a9346da-4cd0-81a5-be6f-f0ddd6d770c6 |
| 任務清單 data source | collection://23c346da-4cd0-8041-955e-000bb6976dd2 |
| DEV DB | psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev(密碼查 BE .env DB_SECRET) |
| agent 主機 | 192.168.50.123(ubuntu-lab-03),agent uid f8136df9-c062-45dd-8f39-ba91fc5e6e3a,base_url https://192.168.50.123:8443 |
| agent 指紋 | 8af59700811b14da49afe4dbfe4c8a3e1e2fccb59d23602a22b2ce0d3d06c520 |
| OpenVAS | 123 上 Greenbone community docker stack,GMP 經 socat TLS bridge 對外開 9390(9392 是 GSA Web UI、3000 是 openvasd HTTP API,都不是我們走的) |
| 租戶工具設定 | config.tenant_detection_tool_configs id=8(tenant 102, openvas, last_test_result=success) |
| 相關 job | 13342(auto, PROCESSING)、13362(manual, PROCESSING,已有 detection_executions id=1 running) |
| BE 起服務 | cd BE && source .venv/bin/activate && python main_app.py(8000) |
| FE dev server | 5180(HMR) |
接手 CM-929 / FR-056.5(檢測工具「測試連線」改走 Agent)。
1. 先讀 docs/features/FR-056-2607-detection-tool-integration/handoff/2026-07-27-cm929-fr0565-mid-arc-handoff.md
—— 從「🧭 原始需求 / WHY」讀起,讀完先回答 §0 的冷接自檢 4 問,答不出來回去讀,別碰 code。
2. 跑 §5 pre-flight,再跑 §3 步驟 2 確認 123 的 agent 是否已重 build。
agent 回 500 = 還沒重 build(預期,非 bug)→ 不要去 debug probe 邏輯,提醒 user 跑 rebuild.sh。
3. 五條回饋(#1~#5)都已實作 commit 完,狀態「修正待驗證」,等複測。
三 repo 各有未 push commits —— push 等我明示,不要自動 push。
不切 branch、收尾等我下令。