對應 design:design-C2.md 級別:中 預估工時:BE 3~4 天(分兩批 ship 推薦)
# 1. 確認 MF endpoints 內部已是 SSP scope(不會弄錯複用模式)
grep -n "scope_type.*ssp\|scope_id=ssp" \
app/module_frame/service/module_frame_ssp_resources_service.py \
app/module_frame/service/module_frame_party_service.py | head -10
# 2. 確認 ssp_excel_import_app_service 內 _confirm_*_flow 命名
grep -n "_confirm.*flow\|source_type" \
app/oscal/service/ssp_excel_import_app_service.py | head -10
# 3. 確認 C1 system_menus seed 已 ship
psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -c \
"SELECT COUNT(*) FROM system_menus WHERE \"group\" = 'ssp_party_role';"
# 預期:9
# 4. 確認 GrcErrorCode 下一個可用序號
grep -E "GRC_4[0-9]+|GRC_403[0-9]+" common/code/grc_error_code.py | head -10
# 5. 確認 ProjectAssessmentPlanMapping 反查路徑
grep -rn "ProjectAssessmentPlanMapping\|project_assessment_plan_mapping" \
domain/ infra/ --include="*.py" | head -5C5(FE SSP tab)依賴 Batch 1 即可開始(範圍 + party + system-characteristic),Excel import 可後補。
SspProjectResolver + require_ssp_manager helper(BE)新檔:
domain/oscal/service/ssp_project_resolver.pycommon/middleware/permission/ssp_permission.py內容:對齊 design-C2.md §3.1
新 error codes(加入 common/code/grc_error_code.py):
GRC_SSP_NOT_FOUND = ("SSP 不存在", "GRC_404010") # 序號 pre-flight 確認
GRC_AP_NOT_ACTIVE = ("AP 已關閉,無法編輯 SSP", "GRC_412001") # 412 第一條
GRC_NOT_PROJECT_MANAGER = ("僅專案 manager 可編輯", "GRC_403005")
GRC_SSP_PARTY_NOT_FOUND = ("SSP 內參與人員不存在", "GRC_404011")
GRC_SSP_RESOURCE_NOT_FOUND = ("SSP 資源不存在", "GRC_404012")
GRC_INVALID_OSCAL_ROLE = ("不合法的 OSCAL role", "GRC_400015")Unit test:
Commit:feat(oscal): C2.1 SspProjectResolver + require_ssp_manager helper + error codes
module_frame_party_service 抽 list_parties_by_context / create_party_in_context檔案:app/module_frame/service/module_frame_party_service.py
動作:
list_parties(mf_uid) 內部已透過 mf 反查 internal SSP id_list_parties_by_context(context_type='ssp', context_id=<ssp_id>) 為 baseCommit:refactor(module-frame-party): C2.1 抽共用 SSP context base method
module_frame_ssp_resources_service 同樣抽 base檔案:app/module_frame/service/module_frame_ssp_resources_service.py
動作:
list_items / add_item / update_item / delete_item 已是 SSP scopeCommit:refactor(module-frame-ssp-resources): C2.1 抽共用 ssp_id base method
/ssp/<ssp_uid>/parties 4 個 endpoint(BE)新檔:
api/oscal/routes/ssp/ssp_party_route.pyapi/oscal/serializers/ssp/ssp_party.pyapp/oscal/service/ssp_party_app_service.pydi_containers/oscal/... 對應 wiringService:呼叫 T2.1 抽出的 base method,加 require_ssp_manager 驗證
Validation:
role_ids 內每個值用 system_menu_service.get_menus(group='ssp_party_role') 查白名單,否則 GRC_INVALID_OSCAL_ROLEURL 註冊:api/oscal/__init__.py
api.add_resource(SspPartiesRoute, '/ssp/<string:ssp_uid>/parties')
api.add_resource(SspPartyRoute, '/ssp/<string:ssp_uid>/parties/<string:party_uid>')Unit test:
Commit:feat(ssp-party): C2.1 /ssp/<uid>/parties 4 個 endpoint
/ssp/<ssp_uid>/ssp-resources 4 個 endpoint(BE)新檔:
api/oscal/routes/ssp/ssp_resources_route.pyapi/oscal/serializers/ssp/ssp_resources.pyapp/oscal/service/ssp_resources_app_service.pyService:呼叫 T2.2 抽出的 base method
URL 註冊:
api.add_resource(SspResourcesRoute, '/ssp/<string:ssp_uid>/ssp-resources')
api.add_resource(SspResourceItemsRoute, '/ssp/<string:ssp_uid>/ssp-resources/items')
api.add_resource(SspResourceItemRoute, '/ssp/<string:ssp_uid>/ssp-resources/items/<string:item_uid>')Unit test:同 T3 pattern
Commit:feat(ssp-resources): C2.1 /ssp/<uid>/ssp-resources 4 個 endpoint
/ssp/<ssp_uid>/system-characteristic 2 個 endpoint(BE)新檔:
api/oscal/routes/ssp/ssp_system_characteristic_route.pyapi/oscal/serializers/ssp/ssp_system_characteristic.pyapp/oscal/service/ssp_system_characteristic_app_service.pyService:直接讀寫 OscalSystemSecurityPlanSystemCharacteristic(既有 jedi-oscal model)
URL 註冊:
api.add_resource(SspSystemCharacteristicRoute, '/ssp/<string:ssp_uid>/system-characteristic')Unit test:GET 既有資料、PUT 更新後 GET 看到新值
Commit:feat(ssp-system-characteristic): C2.1 /ssp/<uid>/system-characteristic 2 個 endpoint
/projects/<project_uid>/current-ssp-uid helper endpoint(BE)新檔:
api/grc/routes/project_current_ssp_route.py(或加進既有 project route)Logic:
compliance.projectsstatus='active' 的 latest one{ssp_uid, ap_uid, ap_status, is_editable}URL 註冊:
api.add_resource(ProjectCurrentSspRoute, '/projects/<string:project_uid>/current-ssp-uid')Commit:feat(project): C2.1 /projects/<uid>/current-ssp-uid helper endpoint
Changelog:docs/changelog/YYYY-MM-DD-feat-ssp-scoped-endpoints-batch1.md
---
type: feat
breaking: false
modules: [oscal, grc]
---
## 需求說明
C2.1:補 11 個 SSP-scoped endpoints — party / ssp-resources /
system-characteristic / current-ssp-uid。支援 C5 SSP tab 編輯 UI。
## 變更範圍
### BE
- 新建 SspProjectResolver + require_ssp_manager
- 6 個新 error code
- 4 個 party endpoint (/ssp/<uid>/parties[/<party_uid>])
- 4 個 ssp-resources endpoint
- 2 個 system-characteristic endpoint
- 1 個 current-ssp-uid helper
- Service 層抽 SSP context base method (party + resources)
## 測試
- 11 個新 endpoint 各有 unit test
- 既有 MF endpoints 透過 wrapper 仍正常ssp_excel_import_app_service 加 source_type='ssp' 支援檔案:app/oscal/service/ssp_excel_import_app_service.py
動作:
_confirm_update_flow(針對 MF)+ _confirm_superset_flow(針對 framework_version)_confirm_ssp_update_flow(ssp_uid, parsed_result, ...)source_type='ssp' 入口處理(preview / parse 流程)Commit:feat(ssp-excel-import): C2.2 加 source_type='ssp' 支援
/ssp/<ssp_uid>/excel-import/* 5 個 endpoint(BE)新檔:
api/oscal/routes/ssp/ssp_scoped_excel_import_route.pyssp_excel_import_route.py(既有 MF / FW-version 入口)但 URL 改 /ssp/<uid>/...URL 註冊:對齊 design-C2.md §5
Service:複用 ssp_excel_import_app_service(T8 已擴增)
Commit:feat(ssp-excel-import): C2.2 /ssp/<uid>/excel-import/* 5 個 endpoint
/ssp/<ssp_uid>/leveraged 4 個 endpoint(BE)新檔:
api/oscal/routes/ssp/ssp_leveraged_route.pyapp/oscal/service/ssp_leveraged_app_service.pyService:複用 ssp_resources base method,只是 implementation_type 鎖在 'leveraged-authorization'
URL 註冊:
api.add_resource(SspLeveragedListRoute, '/ssp/<string:ssp_uid>/leveraged')
api.add_resource(SspLeveragedDetailRoute, '/ssp/<string:ssp_uid>/leveraged/<string:item_uid>')Commit:feat(ssp-leveraged): C2.2 /ssp/<uid>/leveraged 4 個 endpoint
---
type: feat
breaking: false
modules: [oscal]
---
## 需求說明
C2.2:補完 SSP-scoped 剩餘 endpoint — Excel import (5) + leveraged (4)
## 變更範圍
### BE
- ssp_excel_import_app_service 加 source_type='ssp'
- 5 個 /ssp/<uid>/excel-import/* endpoint
- 4 個 /ssp/<uid>/leveraged endpoint| 測試 | 內容 |
|---|---|
| Unit | 每個 endpoint:CRUD path + 權限驗證 + invalid input |
| Unit | SspProjectResolver: 各種 resolve 失敗情境 |
| Unit | require_ssp_manager: 4 個角色都試一遍 |
| Integration | 建專案 → 啟動 AP → 拿 current-ssp-uid → 用該 uid 加 party → 列出看到 |
| Integration | Excel import (SSP scope): 上傳 → preview → confirm → SSP items 增加 |
| Regression | 既有 MF endpoints 仍正常運作 |
| 風險 | 緩解 |
|---|---|
| MF service 抽 base 後 wrapper 邏輯 break | 既有 MF endpoint unit test 全跑一次 |
| 既有 SSP endpoint URL 撞名 | pre-flight grep 確認無重複 route |
| Excel import scope='ssp' 與 'module_frame' 邏輯差異被忽略 | 兩條 path 各寫 test case |
Rollback:每 batch 獨立 commit,可分別 revert