FR-162 · Cross-framework Control Mapping — 設計文件 · 2026-10-24
框架之間的要求對得起來、顧問能調、證據能跨專案沿用;對照存成獨立的 OSCAL Mapping Collection,不塞進任一本 catalog
客戶做完 CMMC 再做 ISO 27001 時,兩套框架有一半的要求其實是同一件事,但現在是兩個獨立專案、證據要重傳一遍。本案建一份跨框架對照庫(控制項層+評估目標層),第一批灌 NIST 官方公布的 CMMC↔︎800-53↔︎ISO 鏈;資源庫有一個對照維護工作台讓顧問調整、匯入匯出;新專案規劃頁有「沿用其他專案的證據」一鍵批次:系統配對全專案評估目標、預覽後一次沿用,沒對應的順便列成差異清單;任務層保留單筆沿用當補救;三個時點主動提醒 user「有符合的證據可以用了」;官方只到控制項層的部分,由 AI 在小範圍內建議評估目標配對、顧問確認。本文件寫定案規則、為什麼這樣定、踩到會怎樣。
| 項目 | 內容 |
|---|---|
| 狀態 | 已實作(母卡 CM-3057,子卡 25 張皆驗收通過待確認或跳過);第 3 棒依決策者實測直改的規則見下方「控制項關聯管理:現行規則」 |
| 日期 | 2026-10-24 |
| 分析 | docs/analysis/2026-10-24-cross-framework-control-mapping.md(現況盤點、官方對照資料盤點、被排除方案) |
| 雛形 | prototype/index.html(五頁:框架對照工作台、點一顆對應後的對話框、新專案一鍵沿用(舊)、沿用其他專案的證據獨立頁(2026-10-25 定案)、任務層單筆沿用與標籤;雙擊即可開) |
| 前作 | FR-038(OSCAL v2 四層架構、source_identifier)、FR-053.1(覆核輪證據承襲)、FR-139/FR-161(資源庫頁與程序書池) |
| 官方資料 | 決策者桌面 00_Compliance Manager/07_稽核法規文件/Mapping/(OLIR 800-53↔︎ISO 2022、CSF↔︎800-53、ENISA CRA);NIST 800-171/r2/NIST.SP.800-171r2.pdf 附錄 D;主專案 common/util/input/NIST_800-53_to_800-171.xlsx |
客戶導入合規框架常不只一套:先 CMMC、再 ISO 27001,或加 CRA。系統裡每套框架是一個獨立專案,第二套的證據要重新上傳一遍,user 覺得在重工。NIST 有公布 800-53↔︎ISO 27001 的對照、800-171 附錄 D 有 800-171↔︎800-53 的對照、CMMC 的 practice 編號本身就是 800-171 編號;這些知識現在系統裡沒有落點。
本案要做到:系統知道「框架 A 的這條要求就是框架 B 的那條」,細到評估目標(AO,assessment objective,每條控制項底下要逐一判定的小項);user 做第二套框架時,收證據的畫面直接列出「你在 CMMC 專案對應的評估目標已交過這幾份,要不要沿用」。對照知識有三個來源:官方公布、我們用 AI 分析補、顧問討論後手動調,所以要有工作台能調、能匯入匯出。
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
subgraph 來源
O[官方 Excel<br/>OLIR/附錄 D]
J[OSCAL mapping-collection JSON]
AI[AI 建議 AO 配對<br/>背景工作]
C[顧問在工作台調整]
end
subgraph 對照庫["對照庫(jedi-oscal-v2,資源庫層跨專案共用)"]
M[control_mappings<br/>一對框架版本一筆]
E[control_mapping_entries<br/>控制項層與 AO 層對應邊<br/>官方層/覆寫層分開]
end
subgraph 使用
W[資源庫 對照維護工作台<br/>看、改、匯入匯出]
T[任務收證據<br/>「沿用其他框架的證據」]
R[報告引用對照版本]
end
O --> M; J --> M; AI --> E; C --> E
M --> E
E --> W; E --> T; E --> R
T -->|勾選沿用| EV[job_evidences 新一筆<br/>同檔、帶來源標記]
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
participant U as user(新 ISO 專案,規劃階段)
participant BE as BE 證據沿用服務
participant MP as 對照解析(套件)
participant EV as 其他專案的 job_evidences
BE-->>U: 規劃頁橫幅:「CMMC L2 專案『鼎盛精密』有 87 個評估目標的證據可沿用」
U->>BE: 點「查看並沿用」,選來源專案(可多選)
BE->>MP: 本專案每個 AO 代號 → 對應到來源框架的哪些 AO/控制項?
MP-->>BE: 每個 AO:目標代號、relationship、confidence、origin、hops
BE->>EV: 同租戶來源專案中綁到那些代號的任務 → 有效證據
EV-->>BE: 證據清單
BE-->>U: 預覽表(每列:本專案 AO/來源/關係/信心/證據數/預設勾選)+「31 個 AO 無對應」
U->>BE: 調整勾選後按「沿用所選」
BE->>EV: 每份證據新開一筆 job_evidences:同 file_id、source=REUSED、reused_from_evidence_id、mapping_entry_id
BE-->>U: 摘要:沿用 142 份到 87 個 AO;專案記 last_evidence_reuse_at
整案一句話:建一份跨框架對照庫並讓顧問可維護,收證據時能把其他框架專案已交的證據帶進來,不再重傳。
| 批 | 卡 | 做什麼 | 產出 | 完成怎麼判定(決策者檢查法) |
|---|---|---|---|---|
| 1 | 1a 套件對照表與匯入匯出 | 兩張表、解析服務、OSCAL JSON 與 Excel 匯入匯出、CMMC↔︎800-171 規則生成 | 套件 migration 021/022、服務、套件測試 | 套件測試綠;jedi_oscal_v2/migrations/021、022 套進 DEV 兩表存在 |
| 1 | 5 OSCAL 版本標記修正 | 套件 catalog 預設版本改 1.2.2 + 回填 | 套件一行+ migration 023 | DEV oscal.metadata.oscal_version 全部 1.2.2 |
| 2 | 1b BE 接線與灌官方資料 | DI wiring、三份官方檔轉接腳本、DEV 灌資料 | di_containers 一處、scripts/import_official_control_mappings.py、DEV 有資料 |
一句 SQL 看對照筆數(CMMC↔︎171 AO 層、171↔︎53、53↔︎ISO);匯出一份 JSON 打開有 mapping-collection;重跑灌資料筆數不變 |
| 3 | 2a 工作台 BE | route、能力點、選單 migration、矩陣端點(主軸×欄一次回含路徑)、寬表匯入匯出、error code | BE 端點可打 | Swagger 打 matrix(axis=ISO, cols=CMMC,CRA,SEMI)回整張;wide export 再 import 筆數不變 |
| 4 | 3a 證據沿用 BE | 共用讀模型、五支 API、job_evidences/projects migration |
BE 端點可打 | 對 DEV 既有 CMMC 專案與一個 ISO 專案打 preview 回得到配對;打 reuse 後 DB 多 source='REUSED' 筆數=摘要 |
| 5 | 2b 工作台 FE | 矩陣視圖:選主軸、勾並排欄,每格膠囊;點膠囊右側面板看路徑/覆寫/停用/歷史;寬表匯入匯出;AI 建議按欄 | 頁面 | 主軸 ISO 並排 CMMC/CRA/SEMI 看到矩陣與空格;點一顆看到三跳路徑;覆寫一條→DB 新 curated 列、官方列 disabled;匯出寬表再匯入一致 |
| 6 | 3b 證據沿用 FE(專案層) | 規劃頁橫幅提醒+三步 dialog(選來源→預覽→摘要) | 元件 | 新 ISO 專案進規劃頁看到橫幅;選 CMMC 專案,預覽表每列有對應與證據數;沿用後摘要寫「N 份到 M 個 AO、K 個無對應」 |
| 7 | 3c 證據沿用 FE(任務層) | drawer 提示列+單筆沿用、沿用 Tag、AR 頁 Tag | 元件 | 任一任務 drawer 看到提示列與沿用證據的「沿用自 CMMC 專案」標籤;AR 判定頁同標籤 |
| 7 | 4 AI 建議配對 | 背景工作兩模式:B 控制項層初配(CRA/SEMI 對 ISO/CMMC 的起點)、A 評估目標層配對;A 跑完規則回填控制項層關係;工作台下拉兩項與「確認」 | handler+工作台兩處 | 工作台對 CRA↔︎ISO 按「初配控制項」,幾分鐘後控制項層出現 ai-suggested 列;確認幾條後按「配對評估目標」,AO 層出現列且控制項層關係被回填;抽三條人工看合不合理 |
依賴一句:1b 等 1a;2a、3a 都等 1b 但不能同批(兩張都改 flow_control_error_code.py 與 manifest.tsv 這類登記型檔);2b/3b/3c 同理不能同批(都改 api.js、locales、error-code.json);卡 4 等 2b;3c 與 4 可同批(不同 repo 不同檔)。卡 5 與 1a 同批(套件不同檔)。決策者功課:驗收卡 1 前把 Mapping/ 三份檔案留在桌面原位,runner 要讀。
| # | 決策 | 定案 | 理由與被排除方案 |
|---|---|---|---|
| D1 | 對照存哪 | 獨立 mapping 表,放 jedi-oscal-v2(決策者 2026-10-24 裁「這應該是套件功能」) |
OSCAL Control Layer 三個平行 model:Catalog/Profile/Mapping Collection,對照本來就不在 catalog 裡。排除「塞 catalog_controls.links」:單向、無關係型別、無信心度,框架改版等於重寫 catalog;與 2026-10-10 CRA 裁示衝突。排除「復活 v1 oscal_control_mapping」:只有邊、無關係型別/AO 層/來源。 |
| D2 | 鍵用什麼 | 控制項代號 control_id(A.5.1/AC.L2-3.1.1)+ AO part_id(A.5.1_obj.3),不綁數字 id |
資源庫 clone、專案 clone 會長新 id(DEV 14 個 catalog 只有 5 個母版),綁 id 每 clone 一次要複製對照。綁代號則母版與副本共用一份。官方長寫法(ISO/IEC 27002:2022 5.1)存 remarks 供報告引用。 |
| D3 | 粒度 | 雙粒度:同一張表容納控制項層與 AO 層;解析時 AO 層有就用,沒有退控制項層並降一級信心度 | 官方全是控制項層;AO 層由 CMMC↔︎800-171 規則生成、AI 建議、顧問補。排除「只做控制項層」:ISO 一條 2~3 個 AO、CMMC 3~6 個,推導出的候選雜訊多一倍。排除「只做 AO 層」:無官方背書、715 個 AO 全人工。 |
| D4 | 證據怎麼重用 | 跨專案建議沿用,不做一專案多框架(決策者裁 OK) | 一專案多框架要動 resolver、SSP 匯出、AP 草稿、AR 判定、報告包全部,且 ISO 有 SoA、CMMC 沒有。沿用時**新開一筆 job_evidences**同 file_id(檔案本體一份、不複製;證據紀錄各專案一筆),比照覆核輪承襲(inherited_from_round_id)形狀;對 user 是「關聯」——來源換新版不自動跟(已凍結的稽核證據不可變動),要跟就再帶一次。排除「共用同一筆」:凍結/刪除/覆核承襲語意打結。 |
| D5 | 官方與自家改動怎麼共存 | 官方層與覆寫層分開:origin 區分 official/third-party/curated/ai-suggested(third-party=OSA、SunSquare 這類二級來源灌入,與 official 一樣是「既有可信起點」,不覆蓋),顧問改官方條時不改原列,另存 curated 列並記 overrides_entry_id;解析時覆寫層優先 |
官方更新重匯時不沖掉顧問調過的;畫面看得出哪些是自己改的。 |
| D6 | 匯入語意 | 更新不覆蓋:同鍵覆蓋、新鍵新增、檔內沒有的不刪;要回到原廠資料用「還原出廠設定」(主軸 × 一欄,二次確認) | 比照框架 Excel 匯入既有庫只增不刪。「以檔案取代整欄」不提供:跟匯入重複、又會硬刪紀錄。 |
| D7 | 800-53 這種我們沒有 catalog 的中繼框架 | 允許對照的來源/目標指向「只有代號沒有 catalog」的框架版本:在 oscal.frameworks/framework_versions 建 NIST 800-53 R5 與 800-171 r2 兩筆,catalog_id 留 NULL(欄位本來可空) |
800-53 是所有官方對照的樞紐。排除另開「參考框架表」:既有表欄位夠用,多一張表多一套 join。畫面上 catalog_id NULL 的框架標「參考用,無目錄」。 |
| D9 | 沿用的入口與形狀 | 專案總覽「證據作業」下拉 → 獨立頁;一個來源專案一份沿用設定,隨時調整,不做批次(決策者 2026-10-25 改判,取代「規劃頁三步對話框」) | 入口:專案總覽一顆「證據作業」下拉,收「上傳檔案,AI 自動分類」「從雲端資料夾分類」「沿用其他專案的證據」三項(同屬收證據動作,放一起才找得到);規劃頁的常駐按鈕與橫幅移除。頁面比照自動分類:首頁=來源專案列表(一列一個來源:目前沿用檔數→評估目標數、被判定引用數、最後調整、ⓘ 調整紀錄彈窗、「調整」「全部取消」);「選擇來源專案」只列尚未選過的;調整頁=三欄可拖(來源框架導航/該節點證據檔/歸到本專案哪些控制項與評估目標),右欄複用自動分類的 PlacementTable+AOPickerDialog,預設勾「通用」(評估目標層與控制項層一視同仁:控制項層對應=來源控制項全部評估目標都適用;已細分的列不算)、「部分可用」在候選區不勾、可加任何一條;右欄依控制項分組;中欄檔案可預覽;「一鍵勾選通用對應(N)」一次勾好再微調,N=0 時停用並說明原因;「套用變更(+N/-M)」一次存。全部取消=該來源帶進來的全拿掉,被稽核判定引用的擋下不刪並列出。每次調整留唯讀紀錄(誰、何時、+N/-M、擋下幾筆),走既有稽核事件機制,不可復原某一次。決策者原話:「同一個專案不要重複沿用,就是只能取消全部,不要做這麼複雜,就是一直去那個裡面調整對應結果就好」「我們要有記錄就好」。雛形 prototype/project-reuse-page.html。命名(2026-10-24 定):畫面「證據沿用」,程式與 DB 一律 reuse;覆核輪仍叫「承襲」。沿用的是證據檔不是判定結果。 |
| D10 | 怎麼提醒 user | 兩個提醒點:① 證據作業下拉旁一行小字「偵測到〈專案〉有 N 個評估目標的證據可沿用」(含來源新增證據時的「還有 N 個新證據」);② 任務 drawer 證據區提示列+常駐「沿用」按鈕 | 原規劃頁橫幅(2026-10-24 D10①③)隨入口搬家併成總覽頁一行小字,不再做可關閉橫幅;沿用列表首頁上方也顯示同一句並附「去調整」。drawer 單筆沿用維持。 |
| D11 | 「其他專案」的範圍 | 當前使用者看得到的專案(與專案列表同一套可見性:owner 或參與者,admin 全部),再排除封存、已刪除、本專案(決策者 2026-10-25 改判,取代「第一版=同租戶」) | 2026-10-25 實查:DEV 租戶 102 的鼎盛 CMMC L2 專案屬另一組織單位(176),使用者專案列表只有 3 個,沿用來源卻列出它且能拉它的證據——同租戶範圍是跨組織單位資料外洩;也解釋 CM-3072 那次 3,599 筆爆量混進鼎盛 204 份檔。RLS 只擋租戶,可見性在應用層:canonical 是 infra/readmodel/audit/flow_control_dashboard_repo_impl.py:_visible_project_ids(owner/_related_project_ids_subq/admin),沿用來源改用它。封存(status='archived')原本也沒排除。資訊系統過濾仍待 ISO 資產設計。 |
| D8 | 評估目標層與無官方對照的框架怎麼產 | AI 兩種模式+規則回填:模式 A(AO 層)對控制項層已對上的組,兩邊 AO prose 兩兩比;模式 B(控制項層初配)給一對框架版本,AI 讀控制項標題+敘述做初配,候選用提示對(ENISA/第三方對照、顧問勾選)或先選 group 兩階段縮小;模式 A 跑完用明確規則回填控制項層關係型別(AO 全等價→等價、全不相關→不相關、其餘部分重疊)。CMMC↔︎800-171 r2 仍規則生成。顧問在工作台確認後才算正式 | 決策者 2026-10-24 指出:官方資料只讓 CMMC/800-171/ISO 對得起來,CRA 與 SEMI 連控制項層都空,只有模式 A 時它們沒起點,第一版進不了沿用流程;且官方全不給關係型別,D9 的預設勾選對官方鏈幾乎全空。重查後 CRA 有 OSA cra.json(→800-53,CC BY-SA)、SEMI 有 SunSquare 表 2(→IEC 62443)兩份二級來源可灌,初配只補 OSA 未覆蓋的 CRA Article 13/Annex VII 與 62443-4-1 五個 practice(見 docs/analysis/2026-10-24-mapping-sources-for-frameworks-without-official-crosswalk.md,含來源三級分級)。不做 AO 全配(六萬對)。AI 準確率未實測,報告輸出必標來源;AO 的 _obj.N 是我們依匯入順序編的非官方編號,mapping 綁框架版本、改版即新對照。 |
| D12 | 對照的層級 | 只能同層:控制項對控制項、評估目標對評估目標(決策者 2026-10-25 裁,10-26 補實作規則)。後端 add_entry 一處把關:主軸評估目標寫到目標控制項的直連自動展開成逐條評估目標,其餘跨層 400 GRC_400189。解析器補一條:排除了某控制項的任一評估目標,同一控制項的控制項層命中也不再成立 |
矩陣、證據沿用、Excel 共用同一套解析,開「評估目標→控制項」例外,每個讀取端都要各自認。少了解析器那條,逐條標評估目標不可用擋不住多跳退回的控制項層,只能寫跨層列。決策推理見 docs/analysis/2026-10-26-fr162-same-level-mapping-and-evidence-delete-semantics.md |
| D13 | 刪除沿用來的證據 | 只動本專案:同專案多處掛同一份檔可選「只這一處/本專案全部」;沿用來的那筆刪了寫 deleted_reason='NOT_APPLICABLE'=本專案此處不適用,沿用建議不再帶回、調整頁可勾回;來源刪除下游照常可用,標「來源已移除」;刪掉的證據本專案不再給下載(決策者 2026-10-26 裁) |
排除「連帶刪除其他專案」:跨過權限與輪次狀態,原上傳者無權替其他專案決定。排除「用 USER_DELETED 判不適用」:調整頁拿掉與歷史清理共用這個值,整輪建議會消失。排除「沿用或刪除時複製檔案」:檔案不可改、軟刪不刪檔、外鍵保護,複製只多儲存空間。job_evidences 不開 RLS(背景與系統脈絡路徑太多)。推理同上份分析 |
| 元件 | 現況 | 本案動作 |
|---|---|---|
jedi_oscal_v2 catalog 層 |
catalog_controls.source_identifier 是同框架跨版本代號;catalog_control_parts.name='assessment-objective'、part_id 格式 <control_id>_obj.N |
不改。對照表鍵對 control_id 與 part_id |
jedi_oscal_v2 profile 層 |
ProfileResolutionService.resolve 已迭代多筆 import |
不改 |
jedi_oscal_v2/app/service/io/oscal_io_service.py |
匯入匯出 catalog/profile/SSP/AP/AR/POA&M,無 mapping | 加 mapping-collection 匯入匯出(卡 1) |
jedi_oscal_v2/migrations/ |
到 020 | 加 021(兩表)、022(800-53/800-171 參考框架版本 seed)、023(oscal_version 回填,卡 5) |
jedi_oscal_v2/app/service/catalog/catalog_service.py:90 |
預設 oscal_version="1.1.2",DEV 53 筆錯標 |
改 1.2.2(卡 5) |
主專案 di_containers/oscal/oscal_containers.py |
wiring 套件服務(providers.Factory) |
加 mapping 相關 service(卡 1) |
主專案 api/oscal/routes/resource_library_route.py、能力點 oscal.resource-library.* |
四顆 CRUD | 加 oscal.control-mapping.read/manage(卡 2);寫入另過 require_tenant_hq(對照全站共用,只開放總部改) |
public.ui_routes |
側選單走 migration 登記(FR-161 先例 2026-10-23-fr161-pre-engagement-capabilities.sql) |
加「控制項關聯管理」入口,掛在「合規稽核」群組(卡 2) |
compliance.job_evidences |
source CHECK 四值;inherited_from_round_id 承襲標記 |
source 加 REUSED;加 reused_from_evidence_id、mapping_entry_id(卡 3,主線 migration) |
public.workflow_execution_control_mapping |
任務 ↔︎ control_id+ao_part_id+round_id,證據→AO 的權威鏈 |
不改,卡 3 讀它找「對應 AO 的任務」 |
infra/readmodel/audit/ar_evidence_candidate_query.py |
既有「某控制候選證據池」讀模型 | 卡 3 新讀模型照它的 scope 紀律(二次用 wecm scope) |
FE src/components/grc/JobExecutionDrawer.vue(2,360 行,超標) |
證據區塊在 job-drawer/JobEvidenceLinksSection.vue,承襲標籤 inherited_from_prev_round |
新區塊新開 job-drawer/JobEvidenceReuseSection.vue,不往 drawer 塞(卡 3) |
FE src/views/module_frame/、src/config/router/index.js、src/config/capabilities.js |
資源庫列表頁與範本編輯頁 | 新頁 src/views/control-mapping/(卡 2) |
背景工作 app/background_job/handler_registry.py、AI 閘道 core/plugins/_source_scan_ai.py 範式 |
@register_job_handler;gateway.complete(req) 經 select_model_for_current_tenant |
卡 4 照抄 |
jedi_oscal_v2/migrations/021-control-mappings.sql)-- 一對框架版本一筆(對齊 OSCAL mapping)
CREATE TABLE oscal.control_mappings (
id BIGSERIAL PRIMARY KEY,
uuid UUID NOT NULL UNIQUE,
source_framework_version_id BIGINT NOT NULL REFERENCES oscal.framework_versions(id),
target_framework_version_id BIGINT NOT NULL REFERENCES oscal.framework_versions(id),
title TEXT NOT NULL,
method VARCHAR(64), -- OSCAL provenance.method(manual / tool-assisted / rule)
matching_rationale VARCHAR(32), -- syntactic / semantic / functional(IR 8477)
status VARCHAR(20) NOT NULL DEFAULT 'draft', -- draft / published / deprecated
provenance JSONB, -- 來源文件、頁次、網址、匯入檔名、匯入時間
remarks TEXT,
created_at / updated_at / created_user / updated_user,
UNIQUE (source_framework_version_id, target_framework_version_id)
);
-- 一筆對應邊(對齊 OSCAL map)
CREATE TABLE oscal.control_mapping_entries (
id BIGSERIAL PRIMARY KEY,
uuid UUID NOT NULL UNIQUE,
mapping_id BIGINT NOT NULL REFERENCES oscal.control_mappings(id) ON DELETE CASCADE,
source_level VARCHAR(10) NOT NULL CHECK (source_level IN ('control','objective')),
source_control_code VARCHAR(128) NOT NULL, -- = catalog_controls.control_id
source_part_id VARCHAR(255), -- objective 時 = catalog_control_parts.part_id
target_level VARCHAR(10) NOT NULL CHECK (target_level IN ('control','objective')),
target_control_code VARCHAR(128) NOT NULL,
target_part_id VARCHAR(255),
relationship VARCHAR(20) NOT NULL CHECK (relationship IN
('equivalent-to','subset-of','superset-of','intersects-with','not-related-to')),
confidence NUMERIC(3,2) CHECK (confidence BETWEEN 0 AND 1),
origin VARCHAR(16) NOT NULL CHECK (origin IN ('official','third-party','curated','ai-suggested')), -- third-party 由套件 024 補
status VARCHAR(16) NOT NULL DEFAULT 'active' CHECK (status IN ('active','disabled')),
overrides_entry_id BIGINT REFERENCES oscal.control_mapping_entries(id), -- curated 蓋 official 時指回原列
remarks TEXT,
created_at / updated_at / created_user / updated_user,
UNIQUE (mapping_id, source_control_code, source_part_id, target_control_code, target_part_id, origin)
);
CREATE INDEX ON oscal.control_mapping_entries (mapping_id, source_control_code);
CREATE INDEX ON oscal.control_mapping_entries (mapping_id, target_control_code);
-- GRANT ... TO cm_app + sequence 權限;兩表非 tenant-scoped(對照是產品知識,跨租戶共用),不掛 RLS變更紀錄不另開表:control_mapping_entries 只增不改,顧問改一條=原列 status='disabled' + 新列 overrides_entry_id 指回;誰改、何時在新列的 created_user/created_at。工作台「歷史」就是沿 overrides_entry_id 往回走。
022-reference-framework-versions-seed.sql)在 oscal.frameworks 建 NIST_SP_800_53_R5(authority NIST)、NIST_SP_800_171_R2(authority NIST),各一個 framework_versions,catalog_id NULL。ON CONFLICT (uid) DO NOTHING,uid 寫死在 migration。
五個產品框架之間沒有任何一組直接對照,全部經參考框架中轉;NIST SP 800-53 R5 是唯一通往 ISO 的匝道(ISO 只與 800-53 有官方對照,即 NIST OLIR)。參考框架只有代號沒有目錄,矩陣預設隱藏,解析結果一律帶 hops 與每跳 origin,顧問看得出一條對應是怎麼來的。
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB'}}}%%
flowchart LR
subgraph P["產品框架(有 catalog)"]
L1[CMMC 2.13 L1]
L2[CMMC 2.13 L2]
CRA[CRA 2024/2847]
SEMI[SEMI E187]
end
subgraph R["參考框架(只有代號,無 catalog)"]
N171[NIST SP 800-171 r2]
N53[NIST SP 800-53 R5]
I62[IEC 62443]
end
ISO[ISO/IEC 27001:2022]
L1 -->|"恆等規則<br/>控制項+AO 層"| N171
L2 -->|"恆等規則<br/>控制項+AO 層"| N171
N171 -->|"800-171 r2 附錄 D"| N53
N53 -->|"NIST OLIR 2023-10-12"| ISO
CRA -.->|"OSA cra.json"| N53
SEMI -.->|"SunSquare 表 2"| I62
I62 -.->|"800-82 r3 附錄(官方)<br/>或 OSA(社群)"| N53
| 起點 | 到 ISO 幾跳 | 經過 | 每跳來源 | 備註 |
|---|---|---|---|---|
| CMMC L1/L2 | 3 | 800-171 → 800-53 | 恆等規則 → 附錄 D → OLIR,全官方 | 唯一有 AO 層的一跳在 CMMC↔︎800-171,過了 800-53 退回控制項層 |
| CRA | 2 | 800-53 | OSA(二級)→ OLIR(官方) | OSA 不涵蓋 Article 13 與 Annex VII 共 17 條,交 AI 初配 |
| SEMI E187 | 3 | 62443 → 800-53 | SunSquare(二級)→ 800-82 r3 附錄(官方,待取得)或 OSA(二級)→ OLIR(官方) | 至少一跳二級,信心最低;三個來源都不含 62443-4-1 五個 practice,交 AI 初配 |
| CMMC ↔︎ CRA | 3 | 800-171 → 800-53 | 兩邊各自匯到 800-53 再接 | 不經 ISO |
每一跳的資料從哪來、有多可信(決策者 2026-10-24 追問「資料怎麼來的、什麼網站、什麼 PDF、有公信力嗎」):
| 跳 | 來源名稱 | 誰發的 | 檔案/網址 | 粒度 | 公信力 | 灌入時標 |
|---|---|---|---|---|---|---|
| CMMC → 800-171 r2 | CMMC 2.13 模型本身 | 美國國防部(DoD CIO) | 《CMMC Model Overview v2.13》《Assessment Guide L2 v2.13》,dodcio.defense.gov/CMMC;桌面 07_稽核法規文件/CMMC 2.0/ |
控制項+AO(practice 編號=800-171 編號、AO=800-171A 判定句) | 最高:不是對照表,是定義本身 | official,規則生成 |
| 800-171 r2 → 800-53 R5 | 800-171 r2 附錄 D | NIST | 《NIST.SP.800-171r2.pdf》附錄 D 表 D-1~D-14;桌面 NIST 800-171/r2/;表格版 BE common/util/input/NIST_800-53_to_800-171.xlsx |
控制項 | 高:NIST 自發,但 NIST 自註「informational」、ISO 欄是 2013 版不用 | official |
| 800-53 R5 → ISO 27001:2022 | NIST OLIR Informative Reference #155 | NIST(National Online Informative References 計畫) | sp800-53r5-to-iso-27001-mapping-2022-OLIR-2023-10-12-UPDATED.xlsx;入口 csrc.nist.gov/pubs/sp/800/53/r5/upd1/final「Supplemental Material」;桌面 Mapping/ |
控制項(含 enhancement) | 高:NIST 自發、有 IR 8477 方法論與 OLIR 審查流程;但不給關係型別(Strength 欄全空)。ISO 自己沒發對 NIST 的對照 | official |
| CRA → 800-53 R5 | OpenSecurityArchitecture osa-data |
社群:OSA 是 2008 年起的開源資安架構志工專案(opensecurityarchitecture.org),GitHub 組織 opensecurityarchitecture/osa-data;無署名作者、無標準組織審核 |
官網 https://www.opensecurityarchitecture.org ;資料庫 https://github.com/opensecurityarchitecture/osa-data ,檔 data/framework-coverage/cra.json(CC BY-SA 4.0);桌面 Mapping/osa-cra-to-sp800-53r5.json;repo scripts/data/osa_cra_to_sp800-53r5.json(與桌面逐 byte 相同) |
條→控制項清單,附 coverage % 與 rationale | 中偏低:每條有理由可逐條核,但 coverage 是估的、頁面自註「no line-by-line verification recorded」;稽核報告寫「依 OSA」會被問「OSA 是誰」。只當顧問起點,確認後才算 | third-party |
| CRA 官方對照(不灌) | ENISA《CRA implementation via EUCC》附錄 | ENISA(歐盟網路安全局) | ENISA-CRA-implementation-via-EUCC-annex-2025-02.pdf(93 頁,2025-02);桌面 Mapping/ |
Annex I 每條 → Common Criteria SFR | 高,但對的是 ISO/IEC 15408 不是 ISO 27001/800-53,我們無 CC catalog | 不灌,留證 |
| CRA 正式對照(未出) | CEN/CENELEC prEN 40000-1-4 | 歐洲標準組織(受 EC 標準化請求 M/606) | cencenelec.eu;預計 2027-10 | Annex I Part I 2(a)~(m) 技術要求目錄 | 出來後是唯一正式依據 | 出來即換 |
| SEMI E187 → IEC 62443 | SunSquare Tech 文章表 2 | 第三方個人:SZ Lin(林上智),SunSquare Tech;同一作者在 SEMI 官網掛過《ISA/IEC 62443 Status Updates》簡報,有 SEMI 資安工作組背景,但文章與簡報都非 SEMI 正式出版 | https://sunsquare.tech/2026/07/08/understanding-the-relationship-between-semi-e187-and-isa-iec-62443-in-equipment-security-implementation/ (表格是圖片);桌面 Mapping/SunSquare-image*.webp;抄錄在 analysis §四 |
E187 12 條 → 62443-4-1 practice/3-3 SR/4-2 CR | 中偏低:作者明標「author's interpretation … not an official cross-standard specification」;對應邏輯與 METI 指引、E187 條文一致。SMCC WG4 官方比較分析出來即換 | third-party |
| SEMI 其他(提示用) | METI《半導體工廠 OT 安全指引》v1.0 | 日本經濟產業省 | semiconductor_systems_guideline_ver1.0_eng.pdf(132 頁,2025-10-24);桌面 Mapping/ |
風險對策 → NIST CSF 2.0 子類別,E187 以章節名引用 | 高(政府),但對 CSF 非 ISO、E187 非獨立欄 | 不灌,AI 初配提示 |
| SEMI 官方(確認無對照) | SMCC《E187 Compliance Guidance》白皮書 | SEMI SMCC WG1/2 | Manufacturing_Cyber_Security_White_Paper_FINAL070725.pdf(18 頁,2025-07);桌面 Mapping/;數位產業署《查核規範》v1.0(23 頁)桌面 Semi E187/ |
12 條 RQ 的 rationale 與範例 | 高,但全文零他框架引用 | 不灌 |
| IEC 62443 → 800-53 R5 | ① NIST SP 800-82 r3 附錄 ② ISAGCA 62443↔︎CSF + NIST CSF↔︎800-53 xlsx ③ OSA iec-62443.json |
① NIST ② ISA 全球資安聯盟+NIST ③ 社群 | ① nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-82r3.pdf(待取得)② isagca.org + 桌面 Mapping/csf-pf-to-sp800-53r5-mappings.xlsx ③ https://github.com/opensecurityarchitecture/osa-data 的 data/framework-coverage/iec-62443.json,repo scripts/data/osa_iec62443_to_sp800-53r5.json(桌面無此檔,runner 直接取自 GitHub) |
62443-3-3 SR → 800-53 | ① 高(800-82 是 800-53 的 OT overlay)② 高但兩跳 ③ 中偏低 | ① official ②③ third-party;沒有 ISA 或 NIST 直接發的官方對照,三者都不含 62443-4-1 practice |
公信力的實務判準:「稽核報告引用這條時,客戶或驗證機構會不會問『這是誰說的』」。NIST、DoD、ENISA、METI 不會被問;OSA、SunSquare 會,所以它們只能是顧問看哪幾條的起點,顧問在工作台確認過轉 curated 才進報告,報告寫「顧問確認,參考來源 X」。三級分級的完整定義見 analysis §二。
DEV 實際灌了哪幾冊(2026-10-24 實查 oscal.control_mappings;origin 四值:official/third-party/curated/ai-suggested,二級來源自 CM-3068 起標 third-party,curated 保留給顧問覆寫與確認):
| mapping | 來源 → 目標 | 控制項層 | AO 層 | origin | provenance 現況 |
|---|---|---|---|---|---|
| 90 | CMMC L2 → 800-171 r2 | 110 | 320 | official(規則生成) | 記規則文字 |
| 129 | CMMC L1 → 800-171 r2 | 17 | 59 | official(規則生成) | 記規則文字;L1 的 AO 以文字比對對應 L2 practice 序號 |
| 128 | 800-171 r2 → 800-53 R5 | 198 | 0 | official | 記「附錄 D」,無網址 |
| 127 | 800-53 R5 → ISO 27001:2022 | 643 | 0 | official | 記 OLIR #155 檔名與日期,無網址;Clause 4~10 列 remarks='clause'、status='disabled' |
| 130 | CRA → 800-53 R5 | 179 | 17 | third-party | 記 OSA 檔名、GitHub 網址、CC BY-SA 4.0 |
| 131 | SEMI E187 → IEC 62443 | 26 | 0 | third-party | 記「SunSquare 2026-07-08 Table 2」與 CSV 檔名,無文章網址 |
| 132 | IEC 62443 → 800-53 R5 | 65 | 0 | third-party | 記 OSA 檔名、GitHub 網址、CC BY-SA 4.0 |
| 267 | CMMC L2 → ISO 27001:2022 | 229 | 684 | ai-suggested+curated | AI 初配(CM-3066 跑出);這冊是直達路線,有了它 CMMC→ISO 不必經 800-53 |
| 268 | CRA → ISO 27001:2022 | 64 | 0 | ai-suggested | AI 初配 |
三冊 official/third-party 的 provenance 缺網址(128、127、131),報告引用時無法一鍵指路;補法是在灌資料腳本的 provenance 加 url 後重跑(冪等,只更新不新增),屬小修,要不要開卡由決策者裁。
踩到會怎樣:跳得越多對得越鬆。ISO 一條常對 800-53 多條、800-53 一條又對 800-171 多條,三跳後一條 CMMC 控制項可能對到 ISO 四五條,含雜訊;因此官方鏈第一版關係一律 intersects-with、信心留空,靠顧問在工作台確認或 AI 補關係型別。路線不是寫死的:顧問或 AI 直接建一冊「CRA ↔︎ ISO」後,解析服務會走一跳直達,800-53 自動退為備援。來源分級與二級來源的可信度判準見 docs/analysis/2026-10-24-mapping-sources-for-frameworks-without-official-crosswalk.md §二。
ControlMappingResolutionService)輸入:來源框架版本 id、來源 control_id、來源 part_id(可空)、目標框架版本 id 清單(空=全部)。輸出:[(目標框架版本, 目標 control_id, 目標 part_id 或 None, relationship, confidence, origin, 幾跳)]。
status='active' 且沒被 overrides_entry_id 指到的列(被蓋的官方列自動退場)。source→target 或 target→source 反向都算(對照雙向等價)。source_part_id 相符);沒有才找控制項層,控制項層命中時回傳 target_part_id=None 並把 confidence 乘 0.7(常數放 common/constant,可調)。confidence 連乘,relationship 取最弱(equivalent-to > superset/subset > intersects-with),回傳 hops。not-related-to 是明示排除,命中即從結果拿掉,不往下跳。控制項層的排除涵蓋該控制項全部評估目標;反過來,排除了某控制項的任一評估目標,同一控制項的控制項層命中(「全部評估目標適用」)也不再成立。少了後半條,評估目標列逐條標不可用擋不住多跳的控制項層退路,只能寫跨層排除列。OscalIoService 擴充+ControlMappingExcelService)mapping-collection 1.2.2 形狀;mapping-resource-reference.href 寫框架版本 uid;mapping-item.type 用 control 或 part;provenance 必填照 D1。匯入時框架版本 uid 對不到 → 400 列出缺哪個。source_framework_code, source_version, source_control_code, source_part_id, target_framework_code, target_version, target_control_code, target_part_id, relationship, confidence, remarks。匯入時 control_code 不存在於該框架 catalog(參考框架除外)→ 整檔退回列出錯行,不半寫。scripts/):OLIR xlsx(20 sheet、A 欄 800-53、D 欄 ISO,Clause 條文列先存著標 remarks='clause')、NIST_800-53_to_800-171.xlsx(B 欄逗號多值拆列)、CMMC↔︎800-171 規則生成(practice XX.Ln-a.b.c → a.b.c,AO _obj.N 同序號 equivalent-to)。三者 origin='official'、relationship='intersects-with'(官方不給型別,CMMC↔︎171 例外為 equivalent-to)、confidence NULL、method='manual'、provenance 記檔名與日期。POST /oscal/control-mappings/factory-reset 帶 confirm=true。共用讀模型 infra/readmodel/audit/evidence_reuse_candidate_query.py:
module_frames.oscal_framework_version_uid → 來源框架版本(專案 clone 的 catalog framework_version_id 是 NULL,必須走 module_frame 回溯,2026-10-24 實查五個專案皆可回溯)。workflow_execution_control_mapping 的 control_id/ao_part_id,取當前輪)→ 套件解析 → 目標代號清單(含 relationship/confidence/origin/hops)。workflow_execution_control_mapping 命中目標 control_id(AO 層命中再縮 ao_part_id)→ job_evidences(is_deleted=false、排除 source='REUSED' 避免循環、排除本專案已有同 file_id 的)。default_checked(D9 規則)。job_execution_id 版本=同一支加 filter,供 drawer。API(api/flow_control/routes/evidence_reuse_route.py;2026-10-25 改判後的形狀,舊的 sources/preview/reuse/new-since-last 由新端點取代或改語意):
GET /projects/<uid>/evidence-reuse/sources:可見(D11)、未封存、未刪、非本專案的來源,每筆帶框架、可對應 AO 數、證據檔數、authorization_boundary_description(living SSP 的 ssp_system_characteristics)、reused_count(已沿用檔數/AO 數)、cited_count(已被判定引用)、last_adjusted_at/by、can_pick(沒有 AO 層對照者 false 並附原因)。首頁列表與選擇頁共用。GET /projects/<uid>/evidence-reuse/<source_uid>/tree:來源框架導航(群組→控制項→AO,各節點證據檔數)與每檔的「本專案預設歸檔」(對照表配到的 AO 層通用列)與「其他可能」(部分可用)。PUT /projects/<uid>/evidence-reuse/<source_uid> body=期望的最終集合 [{evidence_uid, job_execution_uid, mapping_entry_id|null}];BE 算差集:新增寫、拿掉軟刪、被判定引用的拿不掉回在 blocked;回 {added, removed, blocked} 並寫一筆紀錄事件。DELETE /projects/<uid>/evidence-reuse/<source_uid>:全部取消,同樣跳過被引用並回報;寫紀錄事件。GET /projects/<uid>/evidence-reuse/<source_uid>/history:該來源的調整紀錄(稽核事件 EVIDENCE_REUSE_ADJUSTED/EVIDENCE_REUSE_CLEARED,payload 帶數字)。GET /jobs/<uid>/evidence-reuse、POST /jobs/<uid>/evidence-reuse/reuse:drawer 單筆,維持。PROJ.EVIDENCE_MANAGE。寫入:每筆新開 job_evidences:同 file_id、source='REUSED'、reused_from_evidence_id、mapping_entry_id、description 帶「沿用自〈專案〉〈控制項 AO〉」。同任務同 file_id 已存在(既有唯一索引)→ 跳過並計入摘要。檔案本體不複製:沿用列直接指向同一份檔,不經過來源那筆證據。
刪除與來源移除(決策者 2026-10-26 裁):
GET /job-evidence/<uid>/delete-impact,回本專案同一輪同一份檔(只比 file_id,不擴到同內容另存的檔)另掛的評估目標,以及其他專案名。其他專案只告知、不動。DELETE /job-evidence/<uid>?scope=this|project。project=本專案當前輪同一份檔的全部有效證據,逐筆照現行守門(被指派人/專案 manager、輪次未結束),擋下的留著並在 kept 回報。前端 job-drawer/JobEvidenceDeleteDialog.vue,只有本專案另有掛載時才出兩個選項。deleted_reason='NOT_APPLICABLE'(自己上傳的照舊 USER_DELETED)。任務層候選、一鍵沿用、橫幅「有新證據」與寫入前比對都排除這組(任務, 檔案);調整頁不排除,照常列出、目標標 dismissed、不預設勾,勾回照常寫入。陷阱:調整頁拿掉、全部取消、歷史清理也都是 USER_DELETED(DEV 當前輪有 3,738 筆),拿它當不適用會讓整輪沿用建議一起消失,所以不適用必須是獨立的原因值。job_evidences.file_id 對 upload_files 有外鍵,還有人指著就刪不掉);硬刪來源專案只刪該專案自己的證據列。下游標籤改「沿用自〈專案〉(來源已移除)」,來源那筆軟刪、硬刪或來源專案已刪都算(reused_source_removed,任務抽屜與判定頁共用同一支純量 SQL)。job_evidences 本身沒開 RLS,靠 join 有 RLS 的表擋;評估過開 RLS,背景與系統脈絡路徑太多,沒做。Migration(主線 phase=active,回寫時明講出貨基線待重產):job_evidences.source CHECK 加 REUSED;加 reused_from_evidence_id INT、mapping_entry_id BIGINT(soft-ref);compliance.projects 加 last_evidence_reuse_at TIMESTAMPTZ;job_evidences.deleted_reason CHECK 加 NOT_APPLICABLE(2026-10-26-fr162-job-evidences-not-applicable.sql)。
FE 專案層(2026-10-25 改判,取代 3b 的規劃頁對話框):路由比照自動分類:…/round/:roundUid/evidence-reuse(首頁列表)、…/evidence-reuse/new(選擇來源專案)、…/evidence-reuse/:sourceUid(三欄調整頁,新增與調整同一頁)。新目錄 src/views/evidence-reuse/;三欄用 PrimeVue Splitter(state-key 存欄寬);右欄複用 evidence-classification/components/PlacementTable.vue 與 AOPickerDialog.vue。總覽工具列的「自動分類證據」「證據雲端資料夾」兩顆與新項合併成「證據作業」下拉(ProjectAuditorOverview.vue),各項顯示條件維持原本。規劃頁 EvidenceReuseBanner.vue/EvidenceReuseEntryButton.vue/EvidenceReuseDialog.vue 移除。授權邊界預設三行、展開全文,畫面不標「SSP」。雛形 prototype/project-reuse-page.html。 FE 3c 任務層:job-drawer/JobEvidenceReuseSection.vue,證據區動作列加常駐按鈕「沿用」(與上傳、加連結並排,正式入口、永遠在)+提示列(只是提醒,有可沿用才出現)+展開清單勾選沿用;全部沿用完或沒有對應時按鈕仍可按,清單處顯示原因並指路框架對照頁;已沿用證據在既有清單 Tag lang.grc_shared.reused_from_project(比照 inherited_from_prev_round),點 Tag 顯示來源專案與該處判定;AR 判定頁證據清單同 Tag。
本段是目前的規則,與下方「矩陣視圖」原設計衝突時以本段為準。
add_entry):主軸評估目標寫到目標控制項的直連(清空、詳情對話框的確認/改狀態/標不可用都走這條)一律展開成對該控制項每個評估目標各一條;其餘跨層寫入回 GRC_400189。前端各入口不必各自處理層級。refined_targets)。POST /oscal/control-mappings/entries/expand 把整組寫成逐條 curated(關係與信心照搬),再做原本的動作。overrides_entry_id(解析器把被任何列指到的列當退場,只停用不會讓官方列回來)。controlMappingUtil.js(AI_SUGGEST_ENABLED/OSCAL_IO_ENABLED),後端端點與能力點守門照舊。v-can manage)。分段按鈕一律共用元件 SegmentButtons(照待辦任務頁、small)。AOPickerDialog(控制項關聯管理新增對應、證據沿用加入評估項目、AI 自動分類三處共用):左欄群組 → 控制項(點已展開的群組收合)、右欄勾選(控制項標題三態框)、上方搜尋(搜全部)與「全部/只看已勾」、底列已勾膠囊。群組代號 ISO27001-A5 而名稱已是「A.5 …」就不顯示代號(挑選器內統一套)。標題「從 〈框架〉 挑選,對應到 〈這一條〉」;評估目標字母從文字開頭 [x] 取(_obj.N 不是字母序)。為什麼是矩陣不是一對一(決策者 2026-10-24 裁):一對一配對數隨框架數平方成長(5 框架 10 對、10 框架 45 對、加 3 個參考框架 78 對),顧問被迫同一條控制項對不同框架看好幾次。資料層不變(對照庫仍存邊,任意一對都能解析),只改畫面組織。
control-mapping,側選單掛「合規稽核」群組(ui_routes migration),能力點 oscal.control-mapping.read/manage。Dialog modal,寬約 60rem;決策者 2026-10-25 裁捨棄抽屜,雛形 prototype/mapping-side-panel.html)。由上到下七塊:①標題(控制項對應/評估目標對應)②兩端並排——左是點的那列、右是對到的,各顯示框架、代號、標題,可展開條文全文與評估目標清單(AO 層對應預設展開命中那條並標「評估目標 N/M」)③狀態:只有「通用」「部分可用」兩種顯示值+一句補充(見下)④來源:官方寫文件名(NIST OLIR #155/800-171 附錄 D/DoD CMMC 模型)、第三方寫機構與檔名附連結、AI 寫日期與理由、顧問寫人名時間備註;信心分數放在來源行一起看:第三方(OSA coverage 換算、SunSquare 0.6)、AI(附理由)、顧問(覆寫時可填)顯示;官方不顯示(NIST/DoD 不給、DB 為 NULL,不顯示成「未給」) ⑤路徑:每跳一列(代號、框架、該跳來源),直連一跳;中繼框架只在這裡出現 ⑥動作:確認這條對應/改為通用(或部分可用)/標為不可用;被顧問改過的多「撤銷,回到官方」⑦變更紀錄。不出現「間接」「無法修改」字樣,每顆都能改(改=在兩端建 curated 直連,中繼不動,9a 端點)。空格「+」新增(目標框架已定,只選目標控制項/AO)。equivalent-to,以及 superset-of/subset-of 從寬往窄沿用的方向)與部分可用(橘點:intersects-with、涵蓋從窄往寬的方向、官方未給強度的全部)。不可用不是顯示狀態(not-related-to 的格子不會出現東西),只當對話框的動作名。顧問改狀態時選項只有「通用」「部分可用」「不可用」三個,分別存 equivalent-to/intersects-with/not-related-to;涵蓋兩值只從官方資料進來,顧問不手選。等價/部分重疊/涵蓋/不相關這些術語只留在資料庫、Excel 與 OSCAL 匯出,畫面不出現。證據沿用預覽只對「AO 層通用」預設勾選。GET /oscal/control-mappings/matrix?axis_fv=&cols_fv=&expand_ao=&filter=(一次回整張矩陣:主軸控制項與 AO、每格的生效對應含路徑;93×3 欄量級一次查得完,解析走套件 resolve 批次版);寬表匯入匯出 GET|POST /oscal/control-mappings/wide?axis_fv=&cols_fv=;其餘端點(override/disable/history/ai-suggest)不變。frozen 欄或自訂 sticky。禁左側粗色邊框;dark-card、全站字級。雛形 prototype/mapping-workbench.html。兩種模式共用一支 plugin core/plugins/_control_mapping_ai_suggest.py,皆走 @register_job_handler、gateway.complete(select_model_for_current_tenant)、_ai_quota_adapter 配額、prompt 由 jedi_ai_gateway.get_prompt("control-mapping", <key>, BUILTIN) 取;worker 另起。
control_mapping_ai_suggest_controls,payload {source_framework_version_id, target_framework_version_id, hint_pairs?}:對來源每條控制項(標題+statement prose+繁中)與目標候選控制項兩兩比,回 relationship(五值)+confidence+reason,寫控制項層 origin='ai-suggested';mapping 不存在先建(method='tool-assisted')。候選縮小優先序:① hint_pairs(顧問在工作台勾「大概相關」,或由 ENISA CRA 報告/第三方 E187↔︎62443 對照整理成提示);② 無提示時兩階段:先讓 AI 從目標框架 group 選相關 group,再比 group 內控制項;③ 總對數 ≤ 5,000 直接全配。第一版要跑:CRA 的 Article 13/Annex VII 17 條↔︎ISO、62443-4-1 五個 practice↔︎ISO/800-53(其餘由 1b 灌的 OSA 與 SunSquare 二級來源接)。control_mapping_ai_suggest_objectives,payload {mapping_id, only_missing}:只對 origin 為 official/third-party/curated 的 active 控制項層列跑(ai-suggested 的要顧問確認後才跑);每列兩邊 AO prose 一次 call,要求每對都回一筆(含 not-related-to);寫 AO 層 origin='ai-suggested',同鍵已有 curated 跳過。ai-suggested 列 overrides 原 official 列,不改官方列。override_entry 若不接受不改內容只確認,加 confirm_entry)。AO 配對實例(DEV 真實資料):CMMC AC.L2-3.1.1 6 個 AO ↔︎ ISO A.5.15/5.16/5.18 共 7 個 AO,42 對一次給 AI。期待:_obj.1「authorized users are identified」↔︎ A.5.16_obj.3「each identity is unique and linked to an individual」等價 ~0.9;_obj.4「access limited to authorized users」↔︎ A.5.15_obj.4「access control rules are implemented」等價 ~0.85;_obj.2/_obj.5 程序身分 → 不相關(ISO 無此概念);_obj.3/_obj.6 設備 ↔︎ A.5.15_obj.4 部分重疊 ~0.6。存的是代號對代號,prose 只是配對輸入。
common/code/flow_control_error_code.py,GRC_ 前綴照序)| 碼 | 情境 |
|---|---|
GRC_400xxx CONTROL_MAPPING_IMPORT_INVALID |
匯入檔欄位/代號對不到,msg 帶錯行清單 |
GRC_404xxx CONTROL_MAPPING_NOT_FOUND |
mapping 或 entry 不存在 |
GRC_409xxx CONTROL_MAPPING_PAIR_EXISTS |
同一對框架版本已有 mapping |
GRC_412xxx CONTROL_MAPPING_REBUILD_NOT_CONFIRMED |
重建未帶 confirm |
GRC_409xxx EVIDENCE_ALREADY_IN_JOB |
沿用時同檔已在該任務 |
GRC_400189 CONTROL_MAPPING_CROSS_LEVEL |
對照跨層寫入(評估目標→控制項的直連會自動展開,不會走到這裡) |
JOB_EVIDENCE_400001 JOB_EVIDENCE_DELETE_SCOPE_INVALID(common/code/error_code.py) |
刪除範圍不是 this/project |
FE error-code.json 中英同步。
工作台屬系統層(沒有「專案」對象,FR-160 判準),兩顆能力點 is_platform=false、scope {tenant,org_unit},license_module='module-frame'。收證據沿用沿用任務既有守門。
| 卡 | 批 | Repo | 做什麼 | 改哪些檔 | 驗收 | 依賴 |
|---|---|---|---|---|---|---|
| 1 套件對照表與匯入匯出 | 1/2 | jedi-python-package + BE(DI、轉接腳本) | 021/022 migration、entity/repo/mapper/service、解析服務、OSCAL 與 Excel 匯入匯出、三份官方檔轉接、DEV 灌資料 | 套件 jedi_oscal_v2/{migrations,domain,infra,app}/...mapping...;BE di_containers/oscal/oscal_containers.py、scripts/import_official_control_mappings.py |
DEV 兩表有資料(CMMC↔︎171 AO 層、171↔︎53、53↔︎ISO);匯出 JSON 符合 1.2.2;重匯不重複;解析 A.5.15 回得到 CMMC AO | 無 |
| 5 OSCAL 版本標記 | 1 | jedi-python-package | catalog_service.py:90 改 1.2.2;023 回填 migration |
套件兩檔 | DEV metadata 全 1.2.2 | 無(與卡 1 不同檔) |
| 2 對照維護工作台 | 3/5 | BE 一張、FE 一張(Repo 不同拆兩卡:2a BE、2b FE) | 2a:route、能力點、ui_routes migration、匯入匯出端點、error code;2b:頁面、匯入匯出 dialog、i18n、capabilities.js | BE api/oscal/routes/control_mapping_route.py、app/oscal/service/control_mapping_app_service.py、scripts/sql/2026-10-xx-fr162-control-mapping-capabilities.sql;FE src/views/control-mapping/*、router/index.js、capabilities.js、locales |
選 CMMC L2↔︎ISO 看到列與 AO;改一條→DB 新 curated 列、官方列 disabled;匯出再匯入一致 | 卡 1 |
| 3 證據沿用 | 4/6/7 | 3a BE;3b FE 專案層;3c FE 任務層 | 3a:共用讀模型、五支 API、migration(job_evidences 三處+projects 一欄)、error code;3b:規劃頁橫幅+三步 dialog;3c:drawer 區塊、Tag、AR 頁 Tag | BE infra/readmodel/audit/evidence_reuse_candidate_query.py、app/flow_control/service/evidence_reuse_app_service.py、api/flow_control/routes/evidence_reuse_route.py、scripts/sql/2026-10-xx-fr162-job-evidences-mapped.sql;FE views/project/planning/EvidenceReuseBanner.vue、EvidenceReuseDialog.vue、job-drawer/JobEvidenceReuseSection.vue、evidenceMapper.js、AR 證據清單元件 |
見分工概述卡 3 列;DB source='REUSED' 筆數=摘要沿用數;來源專案刪一份檔,新專案那筆仍可預覽 |
卡 1;3b、3c 等 3a |
| 4 AI 建議配對 | 7 | BE + FE 小改(同卡,FE 只加下拉與篩選) | 兩種模式 handler、prompt、入列端點、規則回填;工作台「產生 AI 建議」下拉、origin 篩選、「確認」 | BE core/plugins/_control_mapping_ai_suggest.py、route;FE 工作台頁兩處 |
CRA↔︎ISO 初配有列;確認後 AO 層有列;控制項層關係被回填;只跑一次 only_missing 新增 0 | 卡 2b |
七批(以 Notion 子卡 Stage 為準):批 1 = 1a、5(套件不同檔)。批 2 = 1b。批 3 = 2a。批 4 = 3a。批 5 = 2b(順便建 mappingTags.js 共用 Tag 元件)。批 6 = 3b。批 7 = 3c、4。原規劃把 2a/3a 同批、2b/3b/3c 同批,重查發現它們各自要在同一個登記型檔(error code 表、migration manifest、FE api.js/locales/error-code.json)加列,同批合回必衝突,故拆開;工作台先、沿用後,決策者最早在批 5 看到畫面。工作坊規範「一張卡只改一個 repo」,所以卡 1 拆 1a(套件)/1b(BE),卡 2 拆 2a(BE)/2b(FE),卡 3 拆 3a(BE)/3b(FE 專案層)/3c(FE 任務層)。
origin='third-party',報告標來源)+AI 補洞,不會有「官方」等級。clause,等 ISO 導入設計拍板)。