Phase A0 Design — 既有 system_security_plan_system_implementations 表擴充

Phase:A0(基礎建設) 級別:重型 狀態:design draft,等 raymond review brainstorm 來源requirement-understanding.md §2(10 個問題已 resolved) 依賴:無(Phase 2 的最前置) 後續依賴本 phase:A1, A2, A3, A4, A5(Track A 全部)+ B2, B5(Track B 內容組裝與 OSCAL 匯出)


1. 設計目標

擴充既有 oscal.system_security_plan_system_implementations 表,使其能同時承載:

  1. 「合規資源庫」與「專案 SSP 版本」兩種範圍(既有只服 SSP)
  2. 與 tenant 層的 public.devices / compliance.information_systems 鉤稽(既有只存純文字 name)
  3. OSCAL leveraged-authorization 的特有欄位(既有無 party_uuid / date_authorized)
  4. OSCAL component 的常用 optional 欄位(title / purpose / status)

完成後,Phase 2 後續所有匯入流程(A1~A5)寫入此表、所有匯出流程(B2 / B5)讀取此表,無需新建任何 OSCAL mirror 表。


2. 既有現況盤點

2.1 Schema

oscal.system_security_plan_system_implementations
├── id (PK)
├── uid (UUID, unique, default uuid4)
├── system_security_plan_id (FK → oscal.system_security_plans.id, NOT NULL, ON DELETE CASCADE)
├── name (varchar(255), NOT NULL)
├── description (text)
├── implementation_type (varchar(50), NOT NULL)
├── responsible_party (varchar(100))
└── audit: created_at / updated_at / created_user / updated_user

2.2 既有 enum

SystemImplementationType(jedi-oscal common/enum/code_enum.py):

class SystemImplementationType(StrEnum):
    SYSTEM = "system"
    SUBSYSTEM = "subsystem"
    SERVICE = "service"
    COMPONENT = "component"
    HARDWARE = "hardware"
    SOFTWARE = "software"

2.3 既有資料

DB 內 140 筆,全部 implementation_type='hardware'(= devices 鏡像,由 project_device_mapping_service 寫入)。

2.4 既有 caller

模組 行為
app/associations/service/project_device_mapping_service.py hardware 紀錄
app/oscal/service/ssp_versioning_service.py SSP 版本複製時複製 system_implementations

2.5 既有 jedi-oscal stack

檔案
ORM jedi_oscal/infra/model/ssp/ssp_system_implementation.py
Entity jedi_oscal/domain/entity/ssp/ssp_system_implementation_*.py
Repo interface jedi_oscal/domain/repository/ssp/system_implementation_repo.py
Repo impl jedi_oscal/infra/repository/ssp/ssp_system_implementation_repo_impl.py
Mapper jedi_oscal/infra/mapper/ssp/system_implementation_mapper.py
OSCAL YAML mapper jedi_oscal/infra/mapper/ssp/ssp_yaml_mapper.py
DTO jedi_oscal/app/dto/ssp/ssp_system_implementation_dto.py
Enum jedi_oscal/common/enum/code_enum.pySystemImplementationType

3. Schema 變更

3.1 ADD COLUMN(共 9 個新欄位)

欄位 型別 nullable 用途
scope_type varchar(20) NOT NULL(既有資料 migration 為 'ssp' 'ssp''module_frame'
scope_id integer NOT NULL(既有資料 migration 為 system_security_plan_id 對應 scope 表 id(soft FK,無 DB constraint)
device_id integer nullable soft FK → public.devices.id(鉤稽既有 device 時填)
information_system_id integer nullable soft FK → compliance.information_systems.id(鉤稽既有 system 時填)
title varchar(255) nullable OSCAL component.title 人類可讀標題(與 name 區分)
purpose text nullable OSCAL component.purpose 用途說明
status varchar(50) nullable OSCAL component.status(under-development / operational / disposition / other)
party_uuid varchar(36) nullable OSCAL leveraged-authorization.party-uuid(型別對齊既有 oscal_responsible_parties.party_uuid
date_authorized date nullable OSCAL leveraged-authorization.date-authorized

3.2 既有欄位變更

欄位 變更 理由
system_security_plan_id NOT NULL → nullable,CASCADE FK 保留 scope_type='module_frame' 時此欄為 null
responsible_party 不動,標 deprecated(docstring) 不破壞既有 140 筆資料的寫入;新功能改用 oscal_responsible_parties (polymorphic with context_type='system_implementation')。後續優化資料遷移列入「最後統整優化清單」

3.3 enum 擴充

SystemImplementationType1 個值

LEVERAGED_AUTHORIZATION = "leveraged-authorization"

不加 inventory-item:既有 hardware 已 cover device 鏡像用途,加 inventory-item 會兩個 enum 值意義重疊。OSCAL 匯出時由 mapper 把 hardware 翻譯成 OSCAL inventory-item 結構,不動 DB enum。

3.4 新增 Index

Index 欄位 用途
ix_ssp_sys_impl_scope (scope_type, scope_id) 依 scope 查詢
ix_ssp_sys_impl_device_id device_id 依 device 反查
ix_ssp_sys_impl_info_system_id information_system_id 依 information_system 反查

3.5 Table COMMENT

COMMENT ON TABLE oscal.system_security_plan_system_implementations IS
'OSCAL system-implementation 多型鏡像表(v4 擴充:scope_type 區分 ssp / module_frame)。
 implementation_type 區分 hardware (device 鏡像) / component (information_system 鏡像) /
 leveraged-authorization / system / subsystem / service / software。';

3.6 GRANT 權限

GRANT SELECT, INSERT, UPDATE, DELETE ON oscal.system_security_plan_system_implementations TO cm_app;
-- sequence 既有,不需要重複 GRANT

4. 既有資料 Migration

4.1 既有 140 筆 hardware 資料

UPDATE oscal.system_security_plan_system_implementations
   SET scope_type = 'ssp',
       scope_id = system_security_plan_id
 WHERE scope_type IS NULL;  -- ADD COLUMN 後既有 row 此欄為 null

-- 驗證
SELECT COUNT(*) FROM oscal.system_security_plan_system_implementations
 WHERE scope_type = 'ssp' AND scope_id IS NOT NULL;
-- 預期 140

4.2 不動的部分

  • implementation_type 維持 hardware(不轉 inventory-item
  • responsible_party 既有純文字保留
  • 既有 system_security_plan_id 既有資料維持指向原 SSP(CASCADE FK 保留)

5. jedi-oscal 程式碼擴充

dev 期間走 poetry path dependency(主專案 pyproject.toml 改 path 指本地 source),Phase 2 完成後一次性 bump 版本推 Nexus。

5.1 ORM model 擴充

jedi_oscal/infra/model/ssp/ssp_system_implementation.py

加 9 個 Mapped[] column 對應 §3.1;system_security_plan_idnullable=True;補 3 個 Index。

5.2 Entity / Query Entity 擴充

jedi_oscal/domain/entity/ssp/

  • SspSystemImplementationEntity 加 9 個 attribute
  • SspSystemImplementationQueryEntity 加 scope_type / scope_id / device_id / information_system_id 篩選欄位

5.3 Repository 擴充

jedi_oscal/infra/repository/ssp/ssp_system_implementation_repo_impl.py

  • 既有 CRUD 維持
  • 補 query method:list_by_scope(scope_type, scope_id) / find_by_device_id(device_id) / find_by_information_system_id(info_system_id)

5.4 Mapper 擴充

jedi_oscal/infra/mapper/ssp/system_implementation_mapper.py

entity ↔︎ model 對應 9 個新欄位的雙向 mapping

5.5 OSCAL YAML Mapper 擴充

jedi_oscal/infra/mapper/ssp/ssp_yaml_mapper.py

implementation_type 分支序列化:

  • hardware → OSCAL inventory-items[*](含 uuid / description / props(補 device_id soft ref))
  • component / software / service 等 → OSCAL components[*](含 type / title / description / purpose / status)
  • leveraged-authorization → OSCAL leveraged-authorizations[*](含 title / party-uuid / date-authorized)

5.6 DTO 擴充

jedi_oscal/app/dto/ssp/ssp_system_implementation_dto.py:加 9 個欄位。

5.7 Enum 擴充

jedi_oscal/common/enum/code_enum.pySystemImplementationTypeLEVERAGED_AUTHORIZATION = "leveraged-authorization"


6. 既有 Caller Regression 驗證

A0 不改變既有 caller 的寫入行為(既有 caller 不寫新增的 9 欄,全部 nullable 預設 null)。但要驗證:

6.1 project_device_mapping_service

  • 既有寫入 hardware row 流程不變
  • 驗證新欄位 nullable 不影響 insert

6.2 ssp_versioning_service

  • 既有 SSP 版本複製流程不變
  • 驗證 system_security_plan_id 改 nullable 後不影響既有複製邏輯

6.3 既有 query

grep 全 repo 確認沒有 hard-code 假設 system_security_plan_id 為 NOT NULL 的 query。


7. 測試範圍

測試類別 範圍
Migration test 跑 migration → 驗證既有 140 筆 scope 已補;驗證新欄位為 null;驗證 enum 已加 leveraged-authorization
ORM CRUD 新欄位讀寫測試(scope / device_id / information_system_id / title / purpose / status / party_uuid / date_authorized)
Repository query list_by_scope / find_by_device_id / find_by_information_system_id 三個新 method
Mapper round-trip entity ↔︎ model 雙向 mapping 完整性
OSCAL YAML serialize implementation_type 三分支(hardware / component / leveraged-authorization)序列化正確
既有 caller regression project_device_mapping_service + ssp_versioning_service 既有測試跑通

8. 不在 A0 範圍

不做 理由 / 何時做
Excel parser / 匯入流程 A2
鉤稽(match)演算法 A3 / A4
Confirm 寫入 service(含 inline 新建 device) A5
docx generator B1 / B2
OSCAL JSON / XML serialize(YAML 以外) B5 — A0 只擴充 yaml_mapper,JSON/XML 另案
responsible_party 既有純字串資料遷移到 oscal_responsible_parties 列入「最後統整優化清單」
既有 hardware 是否完全淘汰改 inventory-item 列入「最後統整優化清單」
Frontend 改動 A5 / B6

9. 開工前置檢查(pre-flight verification)

實作開工前需 verify:


10. Acceptance Criteria

A0 視為 shipped 的條件:

  1. ✅ Migration SQL 在 dev DB 跑通,140 筆既有資料 scope_type='ssp' 補全
  2. ✅ jedi-oscal 8 個層(ORM / entity / query_entity / repo interface + impl / mapper / yaml_mapper / DTO / enum)擴充完成
  3. ✅ 新欄位 CRUD 單元測試 + scope query 測試通過
  4. ✅ Mapper round-trip 測試通過
  5. ✅ OSCAL YAML 三分支 serialize 測試通過
  6. ✅ 既有 caller (project_device_mapping_service + ssp_versioning_service) integration 測試通過
  7. ✅ 主專案 dev 啟動 + smoke test 通過(驗證 nullable 化既有欄位後 boot 不破)
  8. ✅ Changelog 完成(type=tweak,因為是基礎建設不直接讓 user 能做新事情)