這是 living 檔,就地 Edit 覆寫。 決策脈絡與每棒紀錄在
fr060-LOG.md(append-only)。 最後更新:2026-08-07(第 11 棒,全案結案) 收尾彙整見同資料夾2026-08-03-fr060-arc-SUMMARY.md。
design.md(同資料夾,1030 行)— 建卡只需讀 §3 決策定案 + §7 拆分 + §8 驗收;真正開工實作時才需要 §4 現況接入點 + §5 詳細設計硬 gate:讀完 §1 若答不出「為什麼一個瀏覽功能要順帶拆資料表」,回頭讀 CM-1054 母卡的「任務摘要」段。
決策者原話:
「目前只有項目,user 完全不知道這個東西會驗證什麼,我怎麼知道我要選什麼?哪些基準可以參考,我可以先請負責人去判斷、提前先處理,而不是等報告出來才去處理。」
FR-059 做完了「掃描設定檔管理」,但平台把 profile 當成不透明的二進位檔,完全不理解內容——使用者在管理頁與任務下拉看到的只有一個名字。
支撐急迫性的實測數字:TWGCB-01-014 共 234 條控制項,其中 199 條是人工待判項(impact 0.0,執行時直接 skip),實際自動檢查只有 35 條、覆蓋率 15%。使用者選了、掃了、拿到一份 85% 是 skip 的報告才發現——等於白等一輪掃描。
三個需求:①瀏覽 profile 檢驗內容(核心)②修改基本資料含改名 ③分類體系。
為什麼一個瀏覽功能要拆資料表:現行單表用 (detection_tool_id, tenant_id, name) 當唯一索引——拿 name 當身分,這正是「改名改不動、唯一改名途徑是 fork 複製」的根因;而分類三軸是「這支 profile 是什麼」的屬性、不是「這一版是什麼」的屬性。現在是最便宜的時機:DEV 僅 13 筆、FR-059 上線才兩天、沒有租戶真的在用。
DEV: cm1047 / fr060-1 / fr060-2 / fr060-3(param) / fr060-3(dpv)
STG: cm1047 / fr060-1b / fr060-2 / fr060-3(param) / fr060-3(dpv)
POC: cm1047 / fr060-1b / fr060-2 / fr060-3(param) / fr060-3(dpv)
差異僅在 DEV 用拆表 migration 原檔 fr060-1、STG/POC 用環境自適應版本 fr060-1b(原檔斷言寫死 DEV 筆數 13,另開一支環境自適應版本供 STG/POC 使用)——這是設計如此,不是落差。
🔴 POC 12 支公版控制項抽取仍是 follow-up:extraction_status 全部 pending,config.detection_profile_controls 為 0 筆。STG 已完成(10 支 succeeded/4,133 條控制項)。子表「開始解析」入口已就緒(CM-1096),管理員可在 POC UI 上直接逐支觸發,無需額外開發。追蹤卡:CM-1104(Not started,作業人員 雷門)。原因:登入 POC 需 captcha/Cloudflare Turnstile,AI 助手不處理密碼與人機驗證。
第 6 棒記載的「CM-1075 實作中異動卡在工作區、不可 git add -A」已解除——CM-1075 於 2026-08-04 完成並 commit(BE 6964c89f/FE 209bf88)。
工作區目前已追蹤的修改只有交接文件與卡片 md(第 9-10 棒的 cards/CM-1077-2-edit-and-delete.md+fr060-STATE.md+fr060-LOG.md,第 10 棒收尾時一併 commit),其餘皆為無關的 docx/png/其他 arc 的 handoff 等未追蹤檔——絕不可 git add -A。
⚠️ 但多 session 併發仍是本專案常態,commit 一律顯式 git add <檔名>、禁用 -am 的紀律不變。
design.md 1030 行已 commit(7e3e7b97)discussion.md + build 產物 discussion.html 已 commit(7124a473 補 D19)| 卡 | 內容 | commit |
|---|---|---|
| CM-1060 | T-1.1 三表 DDL + RLS 八段 + 13 筆搬遷 + 舊表 rename | BE d7cf9abc |
| CM-1061 | T-1.2+1.3 資料層三組 + domain/app service + 讀取端 API | BE 01d0909b |
| CM-1062 | T-1.4 派工鏈兩處破口 + 迴歸測試 | BE 40fcc38d |
| CM-1063 | T-2.1+2.2 分類 enum 表 + seed + 13 筆補登 + PUT 編輯 + 刪除保護 | BE a2f2512b/FE 28f061f |
| CM-1065 | T-3.2+3.3 抽取器註冊表 + InSpec extractor + 非同步管線 | BE ec4e70b7 |
| CM-1064 | T-2.3+2.4 管理頁重構(1,239→639,拆六支)+ 下拉分組 + fallback 攤平 | FE 97f9ac8 |
| CM-1066 | T-3.4 控制項詳細頁 + 摘要區 + 抽取狀態輪詢 | FE bbcb882 |
| CM-1072 | url 型基準支援內容抽取(BE 代下載 + SSRF 防護),延伸納入本 arc | BE 25045758 |
| CM-1075 | url 型開明細頁比對 ETag,有變更才重抽(甲案,先實測後實作) | BE 6964c89f/FE 209bf88 |
CM-1082(.1) |
使用判定服務(BE 唯讀,三來源 UNION ALL + 軟刪穿透) | BE 17e977eb 8 檔 +540 |
CM-1083(.2) |
修正來源 + 硬刪(BE 寫入端)+ 三個 409 error code | BE dddfe7cf 9 檔 +790/FE d6e71e1(i18n 三語系) |
CM-1084(.3) |
兩動作接進操作 menu(FE) | FE 88f2e13 8 檔 +818/-31 |
| CM-1093 | .2 迴歸測試整批跑 6 條 fail — 補 patch logger |
BE fe615d3e 1 檔 +17 |
分頁預設 10 → 20(決策者口頭交辦,無 Notion 卡):FE 247b6f5,DetectionProfileManageView.vue:77 的 pageSize = ref(10) → ref(20)。該頁 DataTable 本來就有 :rows-per-page-options="[10, 20, 50]"(L711),20 在清單內故 paginator 選擇器正常顯示。 ⚠️ 未經畫面驗證——下手當時 FE 工作區有 .3 做到一半的未 commit 內容,開頁只會看到半成品且可能干擾對方,故未驗。留給決策者手測時一併看。
手測後三支 FE 修正:07b8a7d 列表分類欄拆三欄/e4e7967 中繼資料標籤中文化/7274d13 修多列展開只剩最後一筆有資料。
✅ 第 3 棒記載的「BE 目前是壞的」已解除——CM-1061(01d0909b)完成資料層改寫後恢復正常。
主檔 11
版本 11
控制項 4,841
分類字典 13(target_type 8 + benchmark_family 5)
抽取 succeeded 11 全數抽完
抽取 failed 0 ← 原「SSRF」基準 v1/v2 已被 CM-1083 刪除驗收時刪乾淨
抽取 pending 0
🔴 這組數字正在變動中,不要當基準。第 10 棒同一分鐘內連查三次得到 14 → 12 → 11(決策者正在手測 CM-1084 的刪除功能)。要用數字時一律現查:
# 帳號 cmmgr,密碼查 BE .env 的 DB_SECRET
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -tAc "
SELECT '主檔='||count(*) FROM config.detection_profiles
UNION ALL SELECT '版本='||count(*) FROM config.detection_profile_versions
UNION ALL SELECT '控制項='||count(*) FROM config.detection_profile_controls
UNION ALL SELECT 'extr:'||extraction_status||'='||count(*) FROM config.detection_profile_versions GROUP BY extraction_status;"✅ 第 7 棒記載的 2 支 failed(決策者測 SSRF 防護時建的「SSRF」基準 v1/v2)已不存在——它們正是 CM-1083 的具體驗收目標(引用 0 次、要能被完整刪乾淨),已於 .2 實作時刪除並驗證三張表零殘留。
🔴 舊版本文件寫的「url 型無法抽取、failed 是設計內終態」已被 CM-1072(25045758)推翻:抽取時由 BE 代為下載(common/util/safe_http_fetch.py,SSRF 五道防護),拿到 bytes 後完全共用 file 型解析路徑。三條不變式——①掃描路徑完全不動(agent 仍原樣把 URL 交給 cinc-auditor exec,抓的是即時內容不是快照)②下載內容不落儲存(source_type 維持 url、file_id/sha256 維持 NULL)③下載必須在 session_scope() 之外(網路 IO 最多 60 秒)。完整脈絡見 SUMMARY §2.4。
人工待判 vs 自動檢查(收尾日實查,這正是本需求的 WHY):
| 基準 | 總數 | 人工待判 | 自動檢查 | 自動覆蓋率 |
|---|---|---|---|---|
| TWGCB-01-014 Ubuntu 22.04 | 234 | 199 | 35 | 15% |
| TWGCB-01-007 Win Server 2016 | 699 | 159 | 540 | 77% |
| TWGCB-Windows-2025 | 708 | 150 | 558 | 79% |
舊表 config.detection_tool_profiles_deprecated_20260803 未 DROP(觀察期後另案,design.md §8.3)。
🔴 STG/POC 完全未動——收尾日實查兩環境 config.detection_profile% 新表數皆 0,三支 migration 只套 DEV。
🔴 本表是 2026-08-04 第 10 棒的實查快照,不是即時狀態。 Notion 是多方(決策者手測、其他 session、實作 runner)都會改的外部真相——派工或驗收前一律現查,不要照抄本表。 第 9 棒實查發現本表前一版有大面積漂移(CM-1055~1057/CM-1060~1066 已全
Done,STATE 卻仍寫「子需求卡」「修正待驗證」「尚未回寫」),並據此寫進派工單交代 subagent「兄弟卡停在修正待驗證別動」——那份資訊本身就是過期的。
| 層級 | Case No | 狀態(2026-08-04 第 10 棒實查) |
|---|---|---|
| 母案 FR-060 | CM-1054 | ✅ Done(第 9 棒收口,內容全量重寫五段,含明列的「尚未做」七項) |
| FR-060.1 資料模型重構 | CM-1055 | ✅ Done |
| FR-060.2 分類體系+編輯 | CM-1056 | ✅ Done |
| FR-060.3 抽取+瀏覽 | CM-1057 | ✅ Done |
| T-1.1 migration | CM-1060 | ✅ Done |
| T-1.2+1.3 資料層/服務層 | CM-1061 | ✅ Done |
| T-1.4 派工鏈破口 | CM-1062 | ✅ Done |
| T-2.1+2.2 分類 BE | CM-1063 | ✅ Done |
| T-2.3+2.4 管理頁 FE | CM-1064 | ✅ Done |
| T-3.2+3.3 抽取 BE | CM-1065 | ✅ Done |
| T-3.4 詳細頁 FE | CM-1066 | ✅ Done(且早已完整回寫,含四支 commit 與 PrimeVue 展開列根因) |
| url 型支援內容抽取(延伸) | CM-1072 | ✅ Done(第 9 棒收,決策者手測通過;已補三條不變式與 SSRF 說明) |
| url 型 ETag 比對(甲案) | CM-1075 | 修正待驗證(待決策者手測) |
| 8 支基準批次抽取控制項 | CM-1076 | ✅ Done |
| 版本/基準的修正與刪除(未用過才可改可刪) | CM-1077 | Not started(母卡;三張子卡皆已落地,待決策者手測通過後才收) |
| ├─ CM-1077.1 使用判定服務(BE 唯讀) | CM-1082 | 修正待驗證(BE 17e977eb,11 條單元測試綠;⚠️ 卡內三條 DEV 實測斷言待手測) |
| ├─ CM-1077.2 修正來源 + 刪除(BE 寫入) | CM-1083 | 修正待驗證(BE dddfe7cf 9 檔 +790/FE d6e71e1 i18n;19 條測試) |
| └─ CM-1077.3 兩動作接進操作 menu(FE) | CM-1084 | 修正待驗證(FE 88f2e13 8 檔 +818/-31,小弟已在 DEV 走完 7 條手測) |
.2 迴歸測試整批跑 6 條 fail(補 patch logger) |
CM-1093 | 修正待驗證(BE fe615d3e 1 檔 +17,整批 failed 80 → 回基準 74) |
| DB schema 命名體系整理(母案) | CM-1094 | Not started(🔴 記錄用,現階段不做;決策者裁示「之後會再做一次大整理」) |
└─ config schema 更名為 detection(FR-060.2) |
CM-1095 | Not started(🔴 隨 FR-060 上版一起做,不單獨排;詳見 §4 第 4 項) |
| 清單操作按鈕 7 顆收進 menu | CM-1078 | 修正待驗證(第 8 棒完成並收尾;操作欄最終是單一 kebab,讀取類也收進去了) |
| 專案軟刪除後無法檢視或復原(follow-up) | CM-1079 | Not started(🔴 決策者裁示:優先權很後面,現階段不做,僅記錄) |
| 全部展開 + 展開列視覺降階(兩頁) | CM-1080 | 修正待驗證(第 8 棒,決策者當場追加) |
🔴 CM-1081 不屬於 FR-060,它是「升級迴歸」那條 arc 的母案(子卡 CM-1085~1092=T-0~T-6)。所以 CM-1077 三張子卡的 Case No 從 1082 起跳,不接在 1080 後面。 ⚠️ Notion 上現有兩條 arc 交錯編號,看卡號時不可依編號連續性推斷歸屬——1082/1083/1084 是 FR-060,1085~1092 是升級迴歸,1093 又回到 FR-060。
建卡採兩階段:先一次 create-pages 建薄卡鎖住連號,再逐張 update-page 填完整內容——這是第 7 棒本體一次送三份長內容撞 API Error 的對策,第 9 棒四次呼叫全成功。
🔴 CM-1077 與 CM-1078 動到同一個檔,CM-1078 要先做 → 已解除:CM-1078 已落地並收尾,CM-1077.3 可直接加 menu item,不需重構。
🔴 CM-1077.3 加 menu item 時必須照 CM-1078 定下的規則(見 spec §4 gate 表):這一列語意上沒有的動作才不放;存在但不能做的一律放 + disabled,整列唯讀的原因由選單頂端說明列(#start slot)講一次,個別缺 capability 才在該項 label 後綴。組裝點是 DetectionProfileManageView.vue::buildActionMenuItems()。
子任務卡採乙案共 7 張(CM-1060~1066),與執行 session 一對一——非第 2 棒規劃的 12 張。原 T-3.1(裝 CINC)未單獨建卡,安裝屬環境動作由決策者決定時機,程式碼與文件部分併入 CM-1065。
🔴 CM-1072 原被劃在 FR-060 之外,2026-08-04 由決策者裁定納入本 arc——它改的就是 FR-060.3 的抽取服務、程式碼已在裡面、DEV 已生效。
BE/FE 兩 repo 於 feature/e2e-env-build 上均已 push,工作區乾淨(git rev-list origin/..HEAD 為 0)。第 10 棒記載的「BE 未 push 8 支/FE 未 push 3 支」已由決策者全數 push 完畢。
工作區未 commit:本檔與 fr060-LOG.md(第 11 棒收尾),收尾時一併 commit。
id 17-24 tool=8(gcb) t=1 SYSTEM TWGCB-01-007~014 八支 file v1 cur/act=true
id 25-26 tool=6(inspec) t=1 SYSTEM dev-sec Linux/Windows 基準 url v1 cur/act=true
id 32 tool=8(gcb) t=102 TENANT twgcb-02-003-google-chrome file v1 cur=true act=true
id 33 tool=4(openscap) t=102 TENANT twgcb-02-003-google-chrome file v1 cur=false act=false ← 孤兒主檔來源
id 34 tool=8(gcb) t=102 TENANT TWGCB-Windows-2025 file v1 cur/act=true
🔴 id 32 與 33 同 tenant、同 name、同 file_id,但屬不同工具(tool 8 vs tool 4)——這是搬遷 JOIN 必須三欄的實據,也是 STG 測不出來的形態。
| 環境 | Host:Port | DB | 本案可否動 |
|---|---|---|---|
| DEV | 192.168.50.188:25432 |
guidant_ai_dev |
✅ 唯一可套 migration 的環境 |
| STG | 192.168.50.188:25432 |
guidant_ai_stg |
❌ 已服役、10 筆真資料(全 SYSTEM) |
| POC | 192.168.50.189:25432 |
guidant_ai_poc |
❌ 等同 production;第 9 棒已唯讀盤點(12 筆,新表 0),未做任何寫入 |
帳號 cmmgr,密碼查 BE .env 的 DB_SECRET。
開發期間所有 migration 只套 DEV。 STG / POC 一律等決策者當次明確指示。
拆表 migration 比加欄位危險一個量級——它 rename 的是一張 STG 正在服役的表。若派工單或交接文件寫「三環境都套」,該指令本身可能就是錯的,停下問決策者。
feature/e2e-env-build 上做git add <檔名>,禁用 -amcreate-pages 建完CM/來源 雷門/作業人員 小弟/狀態 Not started/需求編號 FR-060.x🎯 全案已結案(2026-08-07)。以下項目均已完成,保留原文供回顧;唯一剩餘的 follow-up 見「📋 結案後 follow-up」段。
四張卡待決策者手測 → 已手測通過,CM-1082/1083/1084/1093 皆已收。手測重點(原文保留):
| 面向 | 怎麼測 |
|---|---|
| **硬刪(放行路徑) | 拿一支引用 0 次的基準 → 刪除 → 確認框應寫出具體的版本數與控制項數**,刪完三張表零殘留、列表不再出現 |
| **改來源(放行路徑) | 同一支未使用基準 → 「修正來源」換網址送出 → 版號不變**(不會多出 v2)、狀態回「待解析」、稍後自動變「解析完成」且控制項換成新來源的 |
| **409 守門(擋下路徑) | 拿已被使用過的基準 → 「修正來源」應灰、最後一項應是停用而非刪除,選單頂端說明帶得出專案名稱** |
| 分頁 20 筆 | 進頁預設顯示 20 筆,paginator 的每頁筆數選擇器正常顯示 10/20/50 |
fr060-1,STG/POC 用環境自適應版本 fr060-1b。POC 12 支公版控制項抽取尚未觸發 —— 追蹤卡 CM-1104(Not started,作業人員 雷門)。詳見 §2「三環境 DB 上版已完成」段與 CM-1104 卡內容。這不是阻塞項,是管理員自行操作的待辦(子表「開始解析」入口已就緒,逐支點擊 12 次即可,非開發工作)。
CM-1095「config schema 更名為 detection」執行狀態未經第 11 棒確認。第 10 棒裁示「隨 FR-060 上版一起做」,但第 11 棒協調者查到的三環境 registry(見 §2)只列出 cm1047 / fr060-1(b) / fr060-2 / fr060-3 五筆,沒有看到對應 CM-1095 的 migration 記錄——這個 schema 改名是否真的隨本次上版執行,下一手需另外查證(\dn 看 schema 是否已是 detection,或查 schema_migrations 有無 CM-1095 對應列)。
背景(原文保留):config schema 本身在 STG/POC 都已服役(FR-056 v1.11.0 帶進去的),兩環境各 5 張表(detection_tools/tenant_detection_tool_configs/detection_tool_param_schemas/detection_tool_profiles/job_execution_detection_tools)。成本盤點:跨 schema FK 零/DB 端一行 ALTER SCHEMA/程式碼 8 個 model 檔的 __table_args__/舊 migration 檔不改。
CM-1079 專案軟刪除後無法檢視或復原——🔴 決策者裁示「優先權很後面,現在不建議做,僅記錄」。 ⚠️ 未來任何人要判「專案是否已刪除」,一律用 project_extensions.deleted_at,不可用 status='archived'。
CM-1094 DB schema 命名體系整理(母案)——🔴 決策者裁示「之後會再做一次大整理」,現階段只記錄,子卡 CM-1095 例外(見上方第 3 項)。
Done(第 9 棒內容全量重寫五段;第 11 棒追加「全案結案」段,含三環境 registry、push 狀態、POC follow-up 標記)。 CM-1077 母卡狀態:本次未查證,交接時未特別要求動它(母派工單指示「CM-1077 已是 Done,不用動它」)。docs/specs/current/system-admin/detection-profile-manage.md、docs/user-manual/scan-profile-guide.md 已隨早期 commit 完成,CM-1075/CM-1083/CM-1084 三批行為是否已補寫,第 11 棒未查證,留給下一手。kernel_module 等 14 種)/適用角色(baseline/dc/dns/web)/狀態(pending-mapping)。POST /api/1.0/detection-tool-profile-versions/<uid>/extraction(手動重抽),FE 已在用。同路徑 GET 是抽取狀態輪詢。detection_tool_profiles_deprecated_20260803)——觀察期後另案,design.md §8.3。上述項目除 CM-1104(已開卡追蹤)外,其餘每一項都要 user 當次單獨發令才動。
✅ BE 主機安裝 CINC Auditor — 四台皆已安裝:開發機(本機 macOS,7.1.7 於 /usr/local/bin/cinc-auditor)+ 三台部署機(188/189/190)。docs/claude/host-dependencies.md 第三項已補齊(授權紅線/路徑解析順序/缺了會怎樣/各主機狀況表)。 ⏳ 剩下的是各機 CINC_AUDITOR_CMD 路徑解析實測,仍列在上版前條件內。 ⚖️ 授權紅線:必須 CINC Auditor(Apache 2.0),絕不可換官方 InSpec 6+ 商業 binary 或 inspec-core gem(均受 Chef EULA)。 路徑解析走 CINC_AUDITOR_CMD 環境變數比照 LibreOffice 慣例,不要硬編 /usr/bin/cinc-auditor。
✅ POC 環境唯讀確認 — 第 9 棒完成(純 SELECT,未動任何狀態)。上版前的基準值:
| 環境 | config.detection_tool_profiles |
筆數 | config.detection_profile% 新表數 |
|---|---|---|---|
| POC | 存在 | 12 | 0 |
| STG | 存在 | 10 | 0 |
→ 四支 migration 只套 DEV 的結論不變。上版時這兩組筆數就是「搬遷前應有幾筆」的對帳基準。
✅ .1 開工時機 — 已完成。拆表 migration 於 2026-08-03 套 DEV(d7cf9abc),DEV 驗收通過;STG/POC 那張服役中的表未被動過,改名風險尚未實際發生,上版時才會遇到。
src/views/detection-profile/
├── DetectionProfileManageView.vue 961 行(原 1,239 → CM-1064 拆成 688 → CM-1078/1080/1084 後 961)
│ ├── pageSize = ref(20) L77 ← 分頁預設(`247b6f5`,原 10)
│ ├── buildActionMenuItems(row) 主檔層 menu 組裝點
│ └── :rows-per-page-options="[10,20,50]" L711 ← 改預設分頁時新值必須在此清單內
├── DetectionProfileControlsView.vue 632 行(控制項詳細頁)
├── profileDisplay.js 顯示名解析共用
└── components/
├── ProfileFormDialog.vue 433
├── ProfileVersionTable.vue 431(CM-1084 +185/-21,版本列也收成 menu)
├── ControlExtractionSummary.vue 279
├── ProfileSourceDialog.vue 207 ← CM-1084 新增(修正來源對話框)
├── ProfileNewVersionDialog.vue 175
├── ProfileDetailDialog.vue 170
└── ProfileCopyDialog.vue 149
src/composables/useProfileUsage.js 122 行 ← CM-1084 新增(問判定 + 組訊息)
src/service/DetectionToolProfileService.js 243 行(CM-1084 +77,五支新方法)
src/components/detection-tools/DetectionConfigField.vue 269 行(下拉分組)
src/views/device/DeviceManage.vue
src/config/api/api.js controls/extraction/taxonomies + CM-1084 四支端點常數
src/config/locales/i18n/{zh-tw,en}/detection-profile-manage.json CM-1084 各 +21 條
src/config/locales/i18n/{zh-tw,zh-cn,en}/error-code.json CM-1083 各 +3 條(409009~409011)
CM-1084 的三條 UX 規則(實作已落地,改這頁前務必先讀): ① 不可用的動作灰掉 + 說明原因,訊息要帶「被用了幾次 + 被哪些專案用 + 該怎麼辦」;專案清單為空但 in_use=true 時要自然降級成不帶專案名(不可印出空括號) ② 「刪除」與「停用」不同時出現——不是兩項都放然後刪除灰掉,而是只出現其中一項(未用過→刪除/用過→停用) ③ 刪除二次確認框要列出「將一併刪除 N 個版本、M 條控制項」的具體數字,不是只寫「確定刪除嗎」 ④ 判定拿不到時**保守當作「不能刪」**而非放行(判定回錯方向會刪掉不該刪的)
⚠️ 要改詳細頁的展開列,先讀 LOG 第 4 棒「PrimeVue 3 展開列會整個銷毀重建」那條——加 :key 或改具名函式 ref 都擋不住。
另一處事實更正:design.md §4.3 寫「orchestration 的三處呼叫點改指 get_version_with_profile()」,實查 _profile_domain.get_by_uid 只有兩處:
app/detection_tools/service/detection_orchestration_service.py:224(_load_profile(),破口①):794(_humanize_profile_param(),破口②)建 T-1.4 卡時寫兩處。
再一處事實更正(2026-08-03,CM-1060 實查):design.md §8.1 寫「既有 10 筆 soft-ref 引用零轉換仍可解析」,這個描述不精確。實際形態是 job_execution_detection_tools.tool_params 那 4 筆 4/4 全部指向 profile 的 uid,但 agent_tasks.params 那 6 筆裡只有 2 筆(url 型)指向 profile 的 uid,另外 4 筆(file 型)的 _profile.uid 存的是 upload_files 的 uid、本來就不指向 profile 表。
→ 寫迴歸測試時該斷言的是 6 筆(tool_params 4 + agent_tasks.params url 型 2),file 型 4 筆走 upload_files 路徑要分開驗。已寫進 CM-1062 卡頭。
detection_tool_profile* 命名已全數改為 detection_profile*)infra/detection_tools/model/ detection_profile{,_version,_control,_taxonomy}.py
infra/detection_tools/mapper/ detection_profile{,_version,_control,_taxonomy}_mapper.py
infra/detection_tools/repository/ detection_profile{,_version,_control,_taxonomy}_repo_impl.py
detection_profile_usage_query.py 124 行 ← CM-1082 三來源 UNION ALL(find_refs)
domain/detection_tools/entity/ detection_profile{,_version,_control,_taxonomy}_{entity,query_entity}.py
domain/detection_tools/repository/ detection_profile{,_version,_control,_taxonomy}.py
detection_profile_version_repo_impl.py 214 行(CM-1083 +49)
domain/detection_tools/service/ detection_profile_domain_service.py(含 get_version_with_profile;CM-1083 +41)
detection_profile_control_domain_service.py
detection_profile_taxonomy_domain_service.py
app/detection_tools/service/ detection_profile_service.py 1,119 行(CM-1082 +98/CM-1083 +171)
detection_profile_taxonomy_service.py
detection_profile_extraction_service.py
api/detection_tools/routes/ detection_profile_route.py 582 行(15 個 Resource)
detection_profile_taxonomy_route.py
api/detection_tools/serializers/ detection_profile.py/detection_profile_taxonomy.py
common/util/profile_extractor/ __init__.py 71/base.py 95(註冊表+抽象基底)/inspec.py 439
common/util/safe_http_fetch.py 473 行 ← CM-1072 代下載(SSRF 五道防護)+ CM-1075 probe_url_validators()
common/util/detection_profile_ref.py 76 行 ← §4.4 確認零影響,未動
common/code/detection_tools_error_code.py FR-060 共 13 條(CM-1083 +3:409009/409010/409011)
test/ test_detection_profile_{version_alloc,dispatch,taxonomy,archive}.py
test_detection_profile_usage.py 204 行 11 條 ← CM-1082
test_detection_profile_edit_delete.py 367 行 19 條 ← CM-1083(+CM-1093 補 autouse patch logger)
scripts/sql/2026-08-03-fr060-1-detection-profile-split.sql 662 行
scripts/sql/2026-08-03-fr060-2-detection-profile-taxonomies.sql 272 行
scripts/sql/2026-08-03-fr060-3-param-schema-extraction-declaration.sql 91 行
scripts/sql/2026-08-04-fr060-3-dpv-source-validators.sql 79 行 ← CM-1075(第四支)
CM-1082 新增的兩支唯讀端點(註冊在 /<string:uid> 之前,才不會被當成 uid 吃掉;沿用既有 referencing-* 命名慣例):
GET /api/1.0/detection-tool-profiles/<uid>/referencing-usage 主檔層
GET /api/1.0/detection-tool-profile-versions/<uid>/referencing-usage 版本層
回傳 {in_use, projects: [{uid, name}], version_refs}
app service 兩支方法:get_profile_usage() / get_version_usage()(detection_profile_service.py,共用 _build_usage()); domain service 新增 list_all_versions()(不分頁,判定專用)。
🔴 _build_usage() 有一條 fail-open fallback(if self._usage_query is None: return {"in_use": False, ...}),會讓「守門有效」與「守門根本沒被呼叫」在測試裡長得一模一樣。DI 已 wiring,真實環境不會走到;但寫新的守門測試時必須斷言 in_use=true 那條路徑確實走到,不可 mock 掉 usage_query。
CM-1083 新增的三支寫入端點:
PATCH /api/1.0/detection-tool-profile-versions/<uid>/source 改來源(版號不動、重抽控制項)
DELETE /api/1.0/detection-tool-profile-versions/<uid> 刪版本(非 current 且未使用過)
DELETE /api/1.0/detection-tool-profiles/<uid> 刪主檔(硬刪,CASCADE 帶走版本與控制項)
三個 error code(common/code/detection_tools_error_code.py):
| 常數 | 代碼 | 用途 |
|---|---|---|
DETECTION_PROFILE_VERSION_IN_USE |
DETECTION_TOOLS_409009 |
版本已被使用過,不可改來源/刪除 |
DETECTION_PROFILE_IN_USE |
DETECTION_TOOLS_409010 |
主檔底下有版本被使用過,不可刪除 |
DETECTION_PROFILE_CURRENT_VERSION_UNDELETABLE |
DETECTION_TOOLS_409011 |
不可單獨刪除當前版本 |
🔴 沒有任何「強制執行」參數或旗標可以繞過 409——已被使用過的版本一律凍結,這是決策者裁定的稽核可信度問題,不是 UX 取捨(不提供「確定要更新嗎」的硬改選項)。 無新 migration:CASCADE 在 FR-060.1 拆表時就已設好。
c3b10b32,第 9 棒上 Notion)docs/features/FR-060-2608-detection-profile-content-management/cards/
├── CM-1077-1-usage-judgement.md 202 行 → Notion CM-1082(✅ 已實作 `17e977eb`)
├── CM-1077-2-edit-and-delete.md 235 行 → Notion CM-1083(✅ 已實作 `dddfe7cf`;第 9 棒 185→235 補「前置卡 .1 提供的介面」節)
└── CM-1077-3-fe-actions.md 193 行 → Notion CM-1084(✅ 已實作 FE `88f2e13`)
三份都自足到「新 session 不讀其他文件就能開工」,含 DEV 實測值可直接當驗收斷言。 .2 卡經第 9 棒擴充後,決策者拍板的四節(規則/邊界/作業紀律/改完要能重抽)未動,只追加前置介面與第 13 條完成定義。
impact == 0.0用 tags.check_type == 'pending' 會漏 6 條(twgcb_01_014_0079~0084 標 check_type: 'service' 但實為 impact 0.0 且只有 skip)。impact 是 InSpec 原生語意,外來 profile 也一定有。不要依賴任何自訂 tag 做這個判定。
⚠️ 但表欄位名不叫 impact(D19)——用 severity_raw + severity_norm,判準寫在各格式的 extractor 裡。
_load_profile() 的 is_active 守門——拆表後在主檔。從檔 entity 有屬性但預設 None 則 None is False 為假 → 守門靜默失效、已停用的 profile 照樣派得出去(無聲授權漏洞,比 500 更糟)_humanize_profile_param() 的 getattr(profile,"name",None) 有 default 不報錯,只讓通知信「掃描設定」靜默退化成 profile:<uuid>,且目前無任何測試會抓到get_version_with_profile(uid) 回主+從合成 entitySTG 的 10 筆全 SYSTEM、無 TENANT。搬遷 SQL 在 STG 測不到租戶路徑、測不到 32/33 三欄 JOIN 陷阱、測不到停用列造成的孤兒主檔。驗收必須在 DEV 做。
答案分散在 §1、§2、§7,以及 CM-1054 母卡的 D3/D4 段。