盤點日期:2026-09-21/盤點員:Opus 5/工作目錄:compliance-manager-be 基準 commit:6b011d67(feature/review)
| 界定法 | 檔數 | 行數 | 說明 |
|---|---|---|---|
| 路徑法(oscal 四層 + di_containers/oscal) | 159 | 20,504 | api/oscal 61、app/oscal 46、domain/oscal 36、infra/oscal 14、di_containers/oscal 2 |
引用法(程式裡寫了 jedi_oscal_v2 的檔) |
46 | — | 其中 app/oscal 19、app/module_frame 10、測試檔 9、其餘散落 |
| 🔴 建議採用範圍(路徑法 + 5 個外圍接線檔) | 167 | 21,364 | 見下方「建議範圍」 |
差距不是統計方法不同,而是總表那個 191 是當初排順序時的估算,沒有對得上任何一種數法。實際驗證過的數字:
git ls-files 數 oscal 四層加上 di_containers 是 159 支 .py(首腦說的 156 應該是漏了 di_containers 那 2 支跟 api/oscal/__init__.py,或是用了不含 di 的算法=157)find 連未進版控的檔一起數也是 159;連 .pyc 等非 .py 檔全算進去是 327,也不是 191我試過各種加總組合(159+module_frame 的 api 25=184、再加 domain 12=196),沒有任何一種組合剛好等於 191。結論:191 是估的,請以本盤點的 167 為準,並建議首腦回頭把總表 §0.5 第 1 列跟 §5 的「191 個檔案」改成 167。
路徑法的 159 支,再加 5 支住在別的目錄、但實際承擔 OSCAL 權限判斷或接線責任的檔(加上 di_containers/dashboard_apis/oscal.py 共 8 支,其中 3 支已含在 159 內):
| 補進來的檔 | 行數 | 為什麼一定要納入 |
|---|---|---|
common/authz/ssp.py |
225 | 整個 SSP 的權限判斷只有這一支。app/oscal 裡 9 個檔 import 它、共呼叫 54 次。不納入等於掃了 54 個呼叫點卻看不到被呼叫的那支怎麼判 |
infra/readmodel/oscal/ssp_control_implementation_query.py |
257 | 控制項實作的查詢實作,直接組 SQL |
infra/readmodel/oscal/resource_library_query.py |
141 | 資源庫的查詢實作 |
app/flow_control/service/oscal_stage_handlers.py 等 3 支 |
342 | 稽核流程推進階段時會回頭改 OSCAL 資料,是跨模組的寫入入口 |
di_containers/dashboard_apis/oscal.py |
36 | 儀表板那側的 OSCAL 接線 |
module_frame 有 81 支檔(api 25/app 31/domain 12/infra 13/di 2),確實跟 oscal 高度糾纏(10 支 app 檔直接 import jedi_oscal_v2)。但我建議這次不掃,理由是實際 grep 出來的守門狀況兩邊差很多:
require_capability(也就是「這個角色能不能用這個功能」那種檢查),是正規做法common.authz兩邊的風險型態不一樣,檢查重點寫不到同一張卡裡——oscal 這棒要問的是「這支端點到底有沒有人在守」,module_frame 要問的是「守是守了,但守的那個權限對不對、夠不夠細」。混在一起掃,研究員會拿錯檢查清單(這正是總表 §5 要求 oscal 主專案側跟套件本體必須分開掃的同一個道理)。
建議:module_frame 另開一支母卡、獨立排隊,等 oscal 這批掃完再排。若首腦要現在就排,至少要另寫一份檢查重點。
查了總表 §0.5 三張表與已掃完的 18 支套件清單,oscal 主專案側 167 支沒有任何一支被前面的 arc 掃過。唯一沾到邊的是 §3.1 第 67 項(FR-095 H1 掃專案任務平台時順手發現資源庫範本可以被竄改),那一條指向的 resource_library_app_service.py 正是本次 O2 棒的主角——掃到的是問題,這支檔本身沒被完整掃過。
界定範圍 167 檔/21,364 行。扣掉移去套件本體那批的 Word 內容抽取器 7 支(原 O7a/O7b,2,868 行)後,實際進掃描 92 檔/17,224 行、切 10 棒(逐檔 wc -l 實算、十棒無重複檔);其餘 68 檔為資料結構宣告(空的 __init__.py、ORM model、entity 介面、純格式定義),沒有判斷邏輯,不排入掃描。
| 棒 | 在掃什麼(白話) | 檔數 | 行數 | 最大單檔 |
|---|---|---|---|---|
| O1 | 控制項實作:每條合規控制項「我們怎麼做到的」的讀寫,含唯一那支權限判斷程式 | 6 | 1,943 | 1,037 行/60KB |
| O2 | 資源庫、公版範本、SSP 匯出(含叫 LibreOffice 轉檔) | 11 | 1,772 | 530 行/32KB |
| O3a | Excel 上傳入口與確認流程(權限題) | 5 | 1,460 | 937 行/48KB |
| O3b | Excel 內容解析(惡意檔案題) | 7 | 1,047 | 428 行 |
| O4 | Word 上傳與解析全鏈(含控制項實作單獨匯入) | 9 | 1,950 | 787 行/40KB |
| O5 | SSP 六種子物件的增刪改查(元件/人員/設備/繼承授權/參考資料/系統特性) | 15 | 1,808 | 230 行 |
| O6 | 程序書文件池 + 匯入比對引擎(新舊版差異怎麼算、使用者選了要怎麼合併) | 6 | 1,917 | 751 行/36KB |
| O8a | 合規框架 PDF 解析工作 | 6 | 1,343 | 674 行 |
| O8b | 合規框架與版本增刪改查 | 9 | 1,479 | 351 行 |
| O9 | 接線總裝:路由註冊表、依賴注入、稽核階段掛鉤、人員對帳、匯入線共用接縫檔 | 18 | 2,505 ⚠️ | 620 行 |
O7a/O7b(Word 內容抽取器 7 支)不在本批——純解析無權限議題,風險型態是惡意檔案,併進 jedi-oscal-v2 套件本體那批一起掃(理由見 §1 與 §4)。本批最終 10 棒。
⚠️ O9 是唯一超過 2,000 行的一棒(2,505 行):它接手了 Excel 與 Word 兩條匯入線共用的接縫檔 _common.py(620 行)——該檔兩棒各自帶都會讓那一棒爆上限,重疊帶入則兩棒都爆。O9 排序在最後幾棒,派工前再切(可能的切法:人員對帳五支或 bundle_restore.py 另放)。runner 以派工當下的卡片 scope 為準。
白話:每一條合規控制項底下「我們公司怎麼做到這條」的文字記錄,是整個系統最核心的資料。這棒同時把唯一一支負責判斷「你能不能看/能不能改這份文件」的程式一起放進來。
api/oscal/routes/ssp/ssp_control_implementation_route.py 309
api/oscal/serializers/ssp/ssp_control_implementation.py 88
api/oscal/serializers/ssp/ssp_control_impl_objective.py 27
app/oscal/service/ssp_control_implementation_service.py 1037 ← 60KB,單檔最大
common/authz/ssp.py 225 ← 全系統唯一 SSP 權限判斷
infra/readmodel/oscal/ssp_control_implementation_query.py 257
最大單檔 1,037 行/60KB — 已達安全線上緣,若研究員回報壓縮,下次把 common/authz/ssp.py 移到 O5。
白話:客戶自己建的範本庫、原廠給的公版範本,以及把系統安全計畫匯出成 Word/PDF 的整條路。這棒優先級最高——總表第 67 項已經掃到這裡有問題。
api/oscal/routes/resource_library_route.py 62
api/oscal/routes/module_frame_template_ssp_route.py 38
api/oscal/routes/ssp/ssp_export_route.py 72
app/oscal/service/resource_library_app_service.py 530 ← 零權限檢查 + 9 段手寫 SQL
infra/readmodel/oscal/resource_library_query.py 141
app/oscal/service/export/ssp_export_app_service.py (見下)
app/oscal/service/export/ssp_docx_generator.py 258
app/oscal/service/export/ssp_libreoffice_converter.py 124 ← 唯一呼叫外部程式的檔
app/oscal/service/export/ssp_v2_content_loader.py 217
app/oscal/service/export/ssp_export_model.py 169
app/oscal/service/oscal_export_app_service.py 47
白話:使用者把 Excel 傳上來、系統開一張解析工作單,使用者看過預覽後按確認才真的寫進去。這一棒是權限題——誰能傳、誰能看預覽、誰能按確認、送上來的編號有沒有驗歸屬。
api/oscal/routes/ssp/ssp_excel_import_route.py 112
api/oscal/routes/ssp/ssp_scoped_excel_import_route.py 130
api/oscal/serializers/ssp/ssp_excel_import.py 137
app/oscal/service/ssp_excel_import_app_service.py 937 ← 48KB
app/oscal/service/import_adapter/excel_to_oscal_ssp.py 144
白話:把 Excel 檔裡九張工作表的每一格讀出來、轉成系統看得懂的資料。這一棒是惡意檔案題——超大表格、公式注入、外部連結、解析上限有沒有設。
app/oscal/service/excel_parser/__init__.py 9
app/oscal/service/excel_parser/parser.py 153
app/oscal/service/excel_parser/sheet_handlers.py 428 ← 本棒最大
app/oscal/service/excel_parser/types.py 111
app/oscal/service/excel_parser/v2_bundle.py 217
app/oscal/service/excel_parser/validators.py 66
app/oscal/service/excel_parser/version_check.py 63
O3a 與 O3b 的拆點是題目性質(權限 vs 惡意檔案),不是行數——兩種題目的檢查清單不一樣,混在一起研究員會拿錯清單。
api/oscal/routes/ssp/ssp_docx_import_route.py 105
api/oscal/routes/ssp/ssp_control_impl_import_route.py 114
api/oscal/serializers/ssp/ssp_docx_import.py 185
api/oscal/serializers/ssp/ssp_control_impl_import.py 59
app/oscal/service/ssp_docx_import_app_service.py 787 ← 40KB
app/oscal/service/ssp_control_impl_import_service.py 416
app/oscal/service/import_adapter/docx_to_oscal_ssp.py 152
app/oscal/service/import_adapter/party_match_enrich.py 78
app/oscal/service/import_adapter/v2_candidate_loader.py 54
⚠️ app/oscal/service/import_adapter/_common.py(620 行)是 Excel 與 Word 兩條匯入線共用的接縫檔,掛在 O9 掃。它不能放在 O3a 或 O4——哪一棒帶它,哪一棒就爆 2,000 行上限;重疊帶入兩棒則兩棒都爆。O3a 與 O4 的卡片裡已註明「這支共用檔在 O9」。
api/oscal/routes/ssp/ssp_components_route.py 85
api/oscal/routes/ssp/ssp_party_route.py 84
api/oscal/routes/ssp/ssp_inventory_items_route.py 84
api/oscal/routes/ssp/ssp_leveraged_route.py 78
api/oscal/routes/ssp/ssp_resources_route.py 88
api/oscal/routes/ssp/ssp_system_characteristic_route.py 51
app/oscal/service/ssp_components_app_service.py (各約 150-200)
app/oscal/service/ssp_party_app_service.py 169
app/oscal/service/ssp_inventory_items_app_service.py 194
app/oscal/service/ssp_leveraged_app_service.py
app/oscal/service/ssp_resources_app_service.py
app/oscal/service/ssp_system_characteristic_app_service.py
app/oscal/service/ssp_resources_context_service.py 230
domain/oscal/service/ssp_project_resolver.py 184 ← 「這份 SSP 屬於哪個專案」的解析
domain/oscal/service/ssp_context_resolver.py 158
api/oscal/routes/ssp/ssp_document_pool_route.py 183
api/oscal/serializers/ssp/ssp_document_pool.py 37
app/oscal/service/ssp_document_pool_service.py 313
app/oscal/service/import_diff/ssp_diff_service.py 751 ← 36KB
app/oscal/service/import_diff/decision_merge.py 318
app/oscal/service/import_diff/snapshot_views.py 315
domain/oscal/parser/docx_section_extractors.py 892 ← 單檔最大
domain/oscal/parser/docx_parser_core.py 555
domain/oscal/parser/docx_intermediate.py 72
domain/oscal/parser/control_id_matcher.py 120
domain/oscal/adapter/cmmc_ssp_adapter.py 860
domain/oscal/parser/ssp_intermediate.py 369
domain/oscal/adapter/i_ssp_docx_adapter.py 78
api/oscal/routes/framework/framework_parse_job_route.py 178
app/oscal/service/framework_parse_job_service.py 674
api/oscal/serializers/framework_parse_job/framework_parse_job_schemas.py 201
domain/oscal/service/framework_parse_job_domain_service.py 123
infra/oscal/repository/framework_parse_job_repo_impl.py 91
domain/oscal/entity/framework_parse_job_entity.py 76
api/oscal/routes/framework/oscal_framework_route.py 104
api/oscal/routes/framework/oscal_framework_version_route.py 157 ← 唯一有掛 authz 的 route 檔
api/oscal/routes/framework/framework_version_edit_route.py 132
app/oscal/service/framework_app_service.py 247
app/oscal/service/framework_version_app_service.py 229
app/oscal/service/framework_version_edit_service.py 351
api/oscal/serializers/framework/oscal_framework.py 165
api/oscal/serializers/framework/oscal_framework_version.py 34
api/oscal/serializers/framework_version_edit/schemas.py 60
白話:把所有東西接起來的那一層——哪個網址對到哪支程式、哪個物件由誰建立;以及稽核流程推進/退回階段時會回頭改 OSCAL 資料的那三支。
api/oscal/__init__.py 201 ← 路由註冊總表,能看出哪些入口是關的
di_containers/oscal/oscal_containers.py 509
di_containers/oscal/__init__.py 0
di_containers/dashboard_apis/oscal.py 36
app/flow_control/service/oscal_stage_handlers.py 142
app/flow_control/service/oscal_stage_preconditions.py 129
app/flow_control/service/oscal_stage_rollback_handlers.py 71
domain/oscal/import_pipeline/bundle_restore.py 208
domain/oscal/service/reconciliation/base.py 107
domain/oscal/service/reconciliation/person_reconciler.py 101
domain/oscal/service/reconciliation/organization_reconciler.py 101
domain/oscal/service/reconciliation/_normalizers.py 51
domain/oscal/service/reconciliation/match_method.py 10
domain/oscal/service/party_reconciliation_service.py 30
infra/oscal/repository/ssp_catalog_title_query.py 93
infra/oscal/model/framework_parse_job.py 36
infra/oscal/model/ssp_docx_parse_job.py 30
infra/oscal/model/ssp_excel_parse_job.py 30
app/oscal/service/import_adapter/_common.py 620 ← Excel/Word 共用接縫檔
⚠️ 本棒 2,505 行超過上限,派工前再切。_common.py 放這裡是因為它是兩條匯入線共用的,放進 O3a 或 O4 都會讓那一棒爆上限。可能的切法:人員對帳五支(約 370 行)或 bundle_restore.py(208 行)另放一棒。
__init__.py 空檔、infra/oscal/model|mapper(純資料表定義與欄位對應,205 行)、domain/oscal/entity|repository 介面(329 行)、api/oscal/serializers/oscal_common/(21 支純格式定義,337 行)。這些是資料結構宣告,沒有判斷邏輯,照 CLAUDE.md「純資料表不計」的精神排除。若首腦要求全覆蓋,可合併成一棒約 900 行。
總表 §0.5 寫「這部分共 122 支功能入口只驗證有沒有登入,完全沒有功能權限檢查(實際測試確認)」。我實際 grep 驗證,實數與結論都要修正:
| 實測項目 | 實數 |
|---|---|
api/oscal/routes 底下的功能入口總數 |
89 支(不是 122;122 應該是把 module_frame 的 62 支也算進去了,89+62=151 也對不上,來源不明) |
入口檔(route)掛了 common.authz 的 |
22 支檔裡只有 1 支(oscal_framework_version_route.py) |
jwt_required(只驗有沒有登入)出現次數 |
110 次 |
| 但是:權限檢查下移到下一層(app service)的呼叫次數 | 54 次(require_manager 33 次、require_participant 21 次),分布在 12 支 app service 檔 |
app/oscal 46 支檔中有掛權限判斷的 |
14 支 |
真實情況是這樣:SSP 那一支線(61 支入口)權限是有守的,只是守在下一層——入口只驗登入,真正判斷「你是不是這個專案的成員/負責人」寫在 app service 裡,呼叫 SspPermissionChecker.require_participant()(讀)或 require_manager()(寫)。這是 CLAUDE.md 明文允許的做法(「資源域守門維持 app service 層」)。框架那一支線(25 支入口)也有守,用的是 require_platform_admin(),共 18 處。
所以這批掃描要問的真正問題不是「有沒有守」,而是「守的那 54 個點,是不是每一支公開方法都守到了」——這是逐支對照題,不是全面缺口。
真正沒守的確認缺口(實查):
resource_library_app_service.py 530 行,require_/authz/Forbidden 一個字都沒有(grep 全檔零命中),而且裡面有 9 段手寫 SQL(sa.text(...))。對應的兩支入口 /oscal/resource-libraries/list 與 /oscal/resource-libraries 也沒守。這正是總表第 67 項那條「租戶管理員可以改掉原廠公版範本」的現場——第 67 項只描述了其中一條路徑(改控制項清單),這支檔裡還有另外 8 段 SQL 沒人看過。module_frame_template_ssp_route.py(1 支入口)同樣零守門。O1(控制項實作)
ssp_control_implementation_service.py 1,037 行裡有 12 次 require_* 呼叫,但這支檔的公開方法(@transaction 標的)有幾支?逐支對照「每支公開方法是不是都有守門」,找出漏掉的那幾支require_manager 與 require_participant 有沒有用錯邊——寫入的操作卻只要求 participant(等於任何專案成員都能改)common/authz/ssp.py 的 require_manager 內含 _require_ap_editable(評估計畫還能不能編輯),require_participant 沒有這層。有沒有寫入操作走了 participant 這條,結果繞過了「已定案不能再改」的限制SspPermissionChecker 的依賴全靠依賴注入(__init__ 五個參數預設都是 None),若注入漏掉,self._resolver 是 None 會直接炸還是靜默放行——讀 _require_user_is_participant 的 None 處理infra/readmodel/.../ssp_control_implementation_query.py 257 行的查詢,有沒有靠資料庫隔離擋租戶、還是完全靠上層守門O2(資源庫與匯出)— 優先級最高
resource_library_app_service.py 全檔零守門,逐支公開方法列出「誰能呼叫、能改到誰的資料」WHERE tenant_id、資料庫隔離對這幾張表是否開啟(總表第 67 項已確認 oscal.profile_imports 與 ssp_implemented_requirements 連客戶歸屬欄位都沒有)ssp_libreoffice_converter.py 是整批唯一呼叫外部程式的檔——檔名/路徑有沒有可能被使用者控制、暫存檔放哪、轉完有沒有刪、同時多人匯出會不會互相踩到/ssp/<ssp_uid>/export 只有 1 支入口,ssp_export_app_service.py 只有 1 次 require_*——匯出等同讀取整份文件,這 1 次守門守的是哪個動作O3a/O4(Excel 與 Word 上傳的權限線)
ssp_excel_import_app_service.py 三支公開方法(upload_and_parse/get_parse_result/confirm_import),只有 3 次 require_* 呼叫——逐支確認是不是每支都守到。已讀到 get_parse_result 是「先查租戶再查專案成員」兩段式,upload_and_parse 的守門藏在 _verify_source_exists 裡面,這種「守門藏在私有方法裡」的寫法最容易漏source_uid 由使用者從表單送上來(總表首腦讀碼時的疑點),有沒有檢查這個編號指到的東西是不是使用者自己的_EXCEL_MAX_SIZE 有設)、Word 那邊有沒有對應的上限、擋在哪一層(讀完整份檔案之後才擋等於沒擋)secure_filename、上傳的檔存到哪、解析失敗的殘檔會不會留著parse_uid 是不是可以猜的(流水號還是隨機碼)_common.py(620 行,兩條匯入線共用)在 O9 掃,本棒只看「呼叫它之前有沒有驗過權限」O3b(Excel 內容解析)— 惡意檔案題,與上面完全不同的清單
parser.py:42 用 load_workbook(file_path, data_only=True, read_only=False):read_only=False 代表整份檔載進記憶體(試算表炸彈),data_only=True 代表讀的是快取計算結果=/+/-/@ 開頭的字串有沒有中和,這條要跟 O2 的匯出線合看(進來沒擋+出去沒擋=完整一條路)sheet_handlers.py 428 行:工作表數/列數/欄數有沒有上限;讀到預期外型態時是回報錯誤還是默默吞掉validators.py 只有 66 行,對九張工作表的樣板少得可疑——驗出錯誤是擋住整份還是只記一筆繼續跑version_check.py 拿使用者檔案裡的字串當版本號:直接信任嗎、版本不符是擋下還是照舊解析v2_bundle.py 組裝時有沒有拿檔案內容裡的編號直接當系統內編號用O5(子物件增刪改查)
require_*——數字對不對得上(例如元件有 4 支入口但只有 4 次守門,那刪除那支守到了嗎)ssp_project_resolver.py「這份 SSP 屬於哪個專案」是整條權限鏈的起點,解析不到的時候回什麼(拋錯還是回 None 然後上層當作通過)item_uid)在改/刪的時候,有沒有確認它確實屬於網址上那份 SSP(跨 SSP 改別人的元件)O6(文件池與比對引擎)
ssp_diff_service.py 751 行:使用者選擇「這筆要/那筆不要」的決定,合併的時候有沒有再驗一次權限,還是只在進入比對畫面時驗過一次decision_merge.py 的合併決定是使用者送上來的資料結構,有沒有可能塞進不該改的欄位O7a/O7b(Word 解析器)
docx_section_extractors.py 892 行的抽取邏輯,有沒有對段落數/表格數設上限O8a/O8b(合規框架)
require_platform_admin() 守,共 18 處,只守寫入不守讀取(註解明寫「寫入僅 root 租戶」)——讀取是不是真的可以全開framework_parse_job_service.py 674 行)只有 3 次 require_platform_admin,但有 5 支入口O9(接線總裝)
api/oscal/__init__.py 是路由註冊總表,能直接看出哪些入口是關的——已讀到 SspScopedExcelImportRoute 與 Confirm 兩支是註解掉的狀態(FR-038 2A 遺留)。確認被註解掉的入口,其 app service 是不是還被別的地方呼叫得到SspPermissionChecker 的五個依賴有沒有全部接上(接不上就是權限判斷失效)| 順位 | 棒 | 理由 |
|---|---|---|
| 1 | O2(資源庫與匯出) | 已知有問題的地方,先掃。總表第 67 項已經證實這裡能改到原廠公版;530 行零守門+9 段手寫 SQL,是全批最可能有斬獲的一棒。而且這棒同時涵蓋唯一呼叫外部程式的檔 |
| 2 | O1(控制項實作+權限核心) | 把 common/authz/ssp.py 先掃過,後面五棒的判斷基準就有了。若這支本身有洞,後面棒次的結論全要重評估 |
| 3 | O3a/O3b/O4(Excel 入口、Excel 解析、Word 上傳,可換序) | 檔案上傳是外部輸入進入系統的正門;三棒互不相干。⚠️ 全機一次只跑一支掃描,「可換序」不是「同時跑」 |
| 4 | O9(接線總裝) | 掃完前四棒後再掃,能回頭驗證「依賴注入有沒有接對」對前面結論的影響;也能確認被註解掉的入口是不是真的關了 |
| 5 | O5/O6(子物件、文件池比對) | 守門看起來齊,屬於逐支核對題,斬獲期待值中等 |
| 6 | O8a/O8b(合規框架) | 用 require_platform_admin 守得最嚴,期待值最低 |
| 7 | O7a/O7b(Word 解析器) | 純解析無權限議題,檢查重點跟前面完全不同(惡意檔案),建議跟套件本體那批(第 8 順位)排在一起掃,共用同一張檢查清單 |
強烈建議:O7a/O7b 不要跟前六棒混排。它們的風險型態與 jedi-oscal-v2 套件本體(第 8 順位,364 檔)一樣是「檔案解析安全」,跟權限檢查是兩回事——這正是總表 §5 已經寫明的分離原則,只是當初沒注意到 domain 層的解析器住在主專案這一側。
🔴 總表的「191 個檔案」與「122 支功能入口」兩個數字都跟實際對不上。實數是 167 檔(建議範圍)/89 支入口。191 疑似跟 §3.1 第 43 項的「191 筆資料」抄串行。要不要順手把總表 §0.5 與 §5 的數字改掉?(我沒改,照指示不動檔)
🔴 「完全沒有功能權限檢查」的描述會誤導研究員。實際上 SSP 線有 54 個守門呼叫、框架線有 18 個,只是守在 app service 層而不是入口層——這是 CLAUDE.md 明文允許的正規做法。若卡片照抄總表的說法,研究員會拿著「找沒守門的端點」去掃,掃到的全是誤報。建議卡片改寫成「逐支公開方法核對守門是否齊全,並重點查 resource_library_app_service.py 這支確認零守門的檔」。
module_frame 要不要現在排。我的建議是不要(理由見 §1),但這 81 檔跟 oscal 有 12 處跨模組 import,首腦若認為「接線」應該包含被接的那一側,可以另立 M1/M2 兩棒(api 25+app 31 約 10,044 行,要切 5~6 棒)。
— 已裁定:_common.py 與 bundle_restore.py 的歸屬_common.py(620 行)掛 O9(重疊帶入兩棒會讓兩棒都爆上限),O3 另拆成 O3a/O3b。bundle_restore.py(208 行)留在 O9。O9 因此 2,505 行超標,排序在後、派工前再切。
被註解掉的路由(api/oscal/__init__.py:110-111,兩支 scoped Excel 匯入入口)。FR-038 2A 的遺留狀態。這是不是已經永久廢棄? 若是,對應的 app service 方法是死碼可以不掃;若只是暫時關閉,那它們是「隨時會被打開、但沒人掃過」的入口,風險更高。我不確定,建議首腦查一下 FR-038 的 2B 進度再決定要不要特別標注。
domain/oscal/parser 與 adapter 該不該算「主專案側接線」。這 7 支(O7a/O7b,2,868 行)做的是純檔案解析,性質上更像套件本體那一批。若首腦認同,可以把 O7a/O7b 從本批移出、併進第 8 順位那批(套件本體)一起掃,本批就縮成 10 棒(O3 拆 O3a/O3b 後)、界定範圍 160 檔、實際進掃描 92 檔/17,224 行。
不排入掃描的 86 檔(約 1,400 行)。我照「純資料表不計」的精神排除,但其中 infra/oscal/model/ 那 4 支資料表定義可能藏著「這張表有沒有客戶歸屬欄位」的答案(總表第 67 項就是栽在這上面)。建議至少讓 O9 那棒的研究員順手看一眼 model 目錄,不必單獨開棒。
cd /Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be
# 範圍 167 檔/21,364 行
git ls-files 'api/oscal/*.py' 'app/oscal/*.py' 'domain/oscal/*.py' 'infra/oscal/*.py' \
'di_containers/oscal/*.py' 'infra/readmodel/oscal/*.py' 'common/authz/ssp.py' \
'app/flow_control/service/oscal_*.py' 'di_containers/dashboard_apis/oscal.py' | xargs wc -l | tail -1
# 89 支功能入口
git ls-files 'api/oscal/routes/*.py' | xargs grep -c '^\s*def \(get\|post\|put\|patch\|delete\)' \
| awk -F: '{s+=$2} END {print s}'
# 54 次 app service 層守門呼叫
git ls-files 'app/oscal/*.py' | xargs grep -ho \
'require_participant\|require_manager\|require_read_access\|require_write_access' | sort | uniq -c
# resource_library 零守門(應該零輸出)
grep -n 'require_\|authz\|permission\|raise Forbidden' app/oscal/service/resource_library_app_service.py