| 項目 | 內容 |
|---|---|
| Branch | feature/ssp-oscal-alignment(BE only — FE 無改動) |
| 起源 handoff | handoff/2026-05-25-bug-d-leveraged-services-handoff.md |
| 涵蓋 fix | docx adapter Table #7 (Category) 也 emit ParsedLeveragedAuthorization;ParsedLeveragedAuthorization 新增 props 欄位;write strategy merge props 進 entity JSONB |
| Verify evidence | mf 369 (f489a145-47da-4506-8675-5cf45a6f218b) ssp 267 oscal.ssp_leveraged_authorizations 4 筆完整(MDR / Microsoft Windows Update / Fortinet / 印表機)+ FE template-edit 「外部利用服務 (4)」tab 4 列完整 |
| 接續 | Bug A / B / C / D 四 bug 全 close,design §11.17 + §11.22 + §11.23 + §11.24 + §11.25 完整覆蓋 ssp-oscal-alignment Phase 4 fix arc |
症狀:mf template-edit「外部利用服務 (1)」但 docx 預覽「外部利用服務 (4)」— 寫 1/4 (3 筆漏)。
Root cause:cmmc_ssp_adapter.adapt_to_bundle Table #6 (FedRAMP CSP/CSO) emit ParsedLeveragedAuthorization + ParsedComponent pair;Table #7 (Category 一般外部服務) 卻只 emit ParsedComponent,完全沒 emit LA。User docx 4 筆分佈:1 T6 + 3 T7 → 寫 1 LA。Product「外部利用服務」tab 讀 oscal.ssp_leveraged_authorizations(不讀 Component),所以 3 筆漏。
Fix(commit 本期):T7 loop 也 parsed_las.append(ParsedLeveragedAuthorization(title=..., props={"category", "purpose", "protocol", "port_ranges", "security_auth"})),並補上 paired Component 的 leveraged_authorization_ref=title。ParsedLeveragedAuthorization 新增 props Optional Dict 欄位裝非 OSCAL 標準的 product-specific fields。LeveragedWriteStrategy.write merge parsed.props 進 entity props JSONB(OSCAL 標準欄位 setdefault precedence)。bundle_restore._restore_la round-trip props 欄位(JSONB persist + restore)。
詳細 root cause / fix options trade-off / Bug B vs Bug D 區別 → design.md §11.25。
| Repo | Commit | 內容 |
|---|---|---|
| BE | 本 commit | fix: Bug D — cmmc adapter T7 emit LA + ParsedLeveragedAuthorization.props + write strategy props merge + design §11.25 + 本 SUMMARY |
| FE | — | 無改動 |
| jedi-* | — | 無改動 |
push 狀態:1 commit 待 push(等 user 拍板)。
140 passed, 10 warnings in 0.89s
(覆蓋 test_cmmc_ssp_adapter_v3_bundle / test_ssp_write_strategy / test_parsed_bundle_normalizer
/ test_ssp_intermediate_v2_bundle / test_ssp_docx_import_app_service
/ test_ssp_import_pipeline_smoke / test_a4_reconciliation_leveraged
/ test_a4_reconciliation_orchestrator)
parse_job 148: lev_auths=4, lev_svcs=4, components=4, parties=5
(pre-fix 同 docx parse_job 146: lev_auths=1, lev_svcs=4 — 4 → 1 → fix 後 4 → 4)
SET app.is_super_admin='t')SELECT id, title, props->>'category' AS category, props->>'protocol' AS protocol,
props->>'fedramp_package_id' AS fedramp, props->>'impact_level' AS impact
FROM oscal.ssp_leveraged_authorizations
WHERE ssp_id=267
ORDER BY id;
-- 21 | MDR、病毒碼與威脅情資同步更新 | | | FR18078583629 | moderate
-- 22 | Microsoft Windows Update | service | HTTPS (Port 443) | |
-- 23 | Fortinet | service | HTTPS (Port 443) | |
-- 24 | 印表機 | interconnection | 有線網路 | |
-- (4 筆 — T6 一筆 FedRAMP + T7 三筆 external-service / interconnection)mf f489a145-47da-4506-8675-5cf45a6f218b /template-edit 「外部利用服務 (4)」tab:
| 類別 | 服務名稱 | 狀態 | 描述 / 用途 |
|---|---|---|---|
| — (T6 FedRAMP) | MDR、病毒碼與威脅情資同步更新 | 運作中 | — |
| service | Microsoft Windows Update | 運作中 | 系統安全性更新與補丁下載 |
| service | Fortinet | 運作中 | 防火牆校時 |
| 互連 | 印表機 | 運作中 | 輸出紙本 |
截圖 .playwright-mcp/bug-d-fixed-leveraged-4-items.png 已存。User 視覺驗收 4 筆完整。
| 項目 | 處理 |
|---|---|
| T6 FedRAMP 行 category 顯示「—」 | Cosmetic — T6 = OSCAL FedRAMP authorization 嚴格語意沒 category prop(只有 fedramp_package_id 區分)。FE 顯示「—」合理;未來若想顯示「FedRAMP 授權」label 可另開 Issue |
Excel side ParsedLeveragedAuthorization.props 也接 product-specific fields |
Excel SHEET_LEVERAGED 每行 1 LA(無 T6/T7 拆分)目前沒踩 bug;但若 Excel template 加 category column 同樣會踩 — 列入 future cross-source consistency item |
jedi-oscal _upsert_responsible_party silent-skip pattern |
同 Bug B follow-up — jedi-oscal 進版時順手改 log.warning |
| Cross-source ParsedParty / ParsedLA adapter 共用 helper refactor | 同 Bug B follow-up — Excel + docx + 未來 OSCAL JSON 各自 build ParsedParty / ParsedLA,沒共用 → 下次又會漏 |
| 進版(L8 jedi-oscal Nexus + L9 BE/FE 版號對齊) | User 拍板才做 — Bug D fix 不涉 jedi-oscal 套件層 |
mf 367 (fc51dd08) 失敗 import 殘留 |
仍可手動刪,無害 |
leveraged_services) 跟 BE confirm 寫入計數 (leveraged_authorizations) 不同 key 不同來源 → 顯示「外部利用服務 (4)」但實寫 1 筆。下次 parsed_result 放兩個語意接近 list 必須附 cross-check(要嘛單一 key,要嘛兩 key 同 length)。leveraged_authorization 規範限 FedRAMP;product「外部利用服務」採廣義(含 printer)。不一致時優先 product 語意(user-facing concept = single source of truth),OSCAL 例外走 props JSONB 容納。written_las 計數,避免重蹈覆轍。已修 + 已驗收:
domain/oscal/adapter/cmmc_ssp_adapter.py + domain/oscal/parser/ssp_intermediate.py + domain/oscal/import_pipeline/bundle_restore.py + domain/oscal/service/write_strategy/leveraged_write_strategy.py) — Table #7 也產 LA + props 欄位tests/test_cmmc_ssp_adapter_v3_bundle.py + tests/test_ssp_write_strategy.py) — 共 140 passed亞航-CMMC-SSP-20260520-1會議討論版.docx 重跑完整 docx import flow(CMMC Level 1 / module_frame create mode)→ 新建 mf f489a145-47da-4506-8675-5cf45a6f218b → DB ssp_leveraged_authorizations 4 筆完整 → FE template-edit「外部利用服務 (4)」tab 4 列正確顯示動作項(user 拍板):
origin/feature/ssp-oscal-alignment(user 一直 push 自己掌控).playwright-mcp/bug-d-fixed-leveraged-4-items.png 驗收 UI測試新建殘留資料:
f489a145-47da-4506-8675-5cf45a6f218b (id=369) 「Bug D E2E - 亞航 CMMC SSP 測試」— user 可手動刪E2E 用 user docx 跑 flow 過程在 Playwright console 看到 1 個 FE error + 多筆 i18n warning,順手修:
ModuleFrameDocumentPoolPanel.vue TDZ ReferenceError症狀:FE console ERROR fetchDocuments failed ReferenceError: Cannot access 'baseService' before initialization。template-edit「程序書文件池」tab 永遠無法 fetch documents(雖然 fallback catch 不阻 user,但功能廢)。
Root cause:const baseService = new BaseService() 之前 declared 在 line ~108(onSelectFiles 上方),但 fetchDocuments() 由 watch(immediate: true, line ~85) 在 setup 階段立即呼叫 — 那時 baseService 還在 Temporal Dead Zone。
Fix:把 const baseService = new BaseService() 移到 State 區段(line ~55),確保 fetchDocuments / onSelectFiles 都能 access。
system-user 是 Bug B fix 引發的 cascade)症狀:FE console 多筆 [intlify] Not found 'lang.oscal_role.ssp_party_role.system-user.label' key in 'tw' locale messages + 'lang.module_frame.template_ssp_empty_hint' warning。
Root cause:
system-user:Bug B fix(BE commit fef5eecf)把 docx 匯入 person 的 default role 設為 "system-user",但 FE oscal-role.json (zh-tw + en) 沒對應 label / description → 責任人員 tab render 時警告且顯示 raw keytemplate_ssp_empty_hint:ModuleFrameTemplateEditView.vue:2058 用此 key 但 module-frame.json 沒定義(雖有 ?? fallback hardcoded 中文字串但 console warning + 沒法 i18n 切換)Fix:兩 locale 都補上對應 key。
| 檔案 | 改動 |
|---|---|
src/config/locales/i18n/{zh-tw,en}/oscal-role.json |
補 system-user label + description |
src/config/locales/i18n/{zh-tw,en}/module-frame.json |
補 template_ssp_empty_hint |
驗證:Playwright 重 navigate template-edit 頁,循序 click 10 tabs (基本資料 / 適用控制項 / 受評標的 / 責任單位 / 責任人員 / 設備 / 資訊系統 / 外部利用服務 / 元件清冊 / 程序書) → console 0 errors / 0 warnings(vs 修前 ERROR fetchDocuments failed + 多筆 i18n warnings)。
FE commit c7d5791 —「fix(ssp-oscal-alignment): Bug E + F — DocumentPoolPanel TDZ + Bug B 引發的 i18n missing keys」
教訓:BE fix 改字串常量(如 default role string "system-user")必須同步 trace FE 是否有對應 i18n key — 否則 user 立即看到 raw key + console warning。Cross-stack consistency check 應該列入 Bug B / Bug D 同類 fix 的 follow-up checklist(跟 cross-source consistency check 平行)。
Bug B 修 party adapter chain(_dict_to_parsed_parties + _upsert_responsible_party),Bug D 修 leveraged adapter T6/T7 拆分(adapt_to_bundle.parsed_las emission)— 完全不重疊的 code path。User 觀感都是「docx N 筆 → 看到 M 筆 (M < N)」但 root cause 完全不同。
兩者共通教訓:adapter / extractor / write strategy 任何 chain,凡涉及「跨 table / 跨 source 拆兩 path」一定先 cross-source check user-facing UI。Bug B 教訓 2 (Cross-source feature fix audit) + Bug D 教訓 1 (Adapter 兩條對稱 path) 是同概念不同 facet — 列入未來 review checklist。