整理卡 CM-2150(母卡 CM-2139)|整理日期 2026-09-25|只整理、不執行:沒有開卡、沒有改 FR-114 任何檔、沒有改總表。 出處:總表
docs/features/security-scan-consolidated/README.md(§3.1 第 118~180 項、§4 分組、§7 第 33/35 項)、裁定表decision-draft.md末尾、FR-116/FR-118 站 README「修正線要接的」、各棒報告。「修正分支現況」欄是本棒 2026-09-25 開fix/security-b1工作區(BE HEAD9ff0a5060、套件 HEADab68291b)實查的結果。
讀者:FR-114 首腦。你懂程式、但沒看過掃描線 09-21 重啟後那 40 棒報告。 用法:四段各一張表,一列一件,讀完就能開卡。
幾個詞:
fix/security-b1,FR-114 的工作區,還沒合回主線。scripts/init/02-schema.sql)。動了資料庫結構或隔離規則就要重產;重產屬決策者裁示。🔴 開卡前先看這四件:
| # | 哪張卡 | 缺口是什麼(白話) | 在哪裡 | 怎麼修 | 決策者裁定 | 開卡建議 |
|---|---|---|---|---|---|---|
| 1-1 | CM-2037(2-5,Done) | 🔴 稽核團隊名單「查得到輪次才檢查你是不是專案成員」。別家客戶的輪次被資料庫隔離藏起來、查回來是空的,於是整段檢查跳過、名單(姓名/Email/電話)照樣回去。擋住了同客戶跨專案,沒擋住跨客戶 | 修正分支 app/flow_control/service/assessment_plan_app_service.py:714-722 list_ap_parties(本棒實查::719 if curr_user_id is not None、:721 if rnd is not None) |
查不到輪次就回 404。照同檔另一支 resolve_ap_and_check_participant 的寫法。curr_user_id 也要一起改必填(見 1-4) |
第 42 項:退回 CM-2037(主專案改、不發版) | 退回 CM-2037;可與 1-2、1-4 同一棒 |
| 1-2 | CM-2037 範圍外(第 66 項,已升高) | 稽核計畫選單與儀表板兩支只查登入、不查專案成員。儀表板還不比對「這一輪是不是這個專案的」。CM-2037 只修了 audit_round_route.py 那 8 支,這兩支沒卡接 |
api/flow_control/routes/assessment_plan_route.py:38 選單 GET、:108 ApDashboardResource.get;repo infra/flow_control/repository/flow_control_project_repo_impl.py:511 _resolve_dashboard_round_id(:549/:632 兩處呼叫) |
①選單與儀表板在服務層補「是專案成員」檢查(走 common.authz 的 assert_project_participant);②_resolve_dashboard_round_id 解出輪次後比對 project_id 等於網址專案,不符就回 404 |
無(修法無爭議) | 新卡,與 1-1 同批(同一支檔、同一種漏) |
| 1-3 | CM-2041(2-9,Done) | CM-2041 修了第 118/119 項的兩支刪除,但第 129 項零修法:把程序書掛到控制項時,文件編號換內部 ID 那一步查的是全系統,沒限定「只能是這份計畫池子裡的」。可以把別人的文件掛過來、再從回應拿到檔案代號去下載(同客戶跨專案) | 主專案 app/oscal/service/ssp_document_pool_service.py:159 add_control_mappings(本棒實查:resolve_doc_uids_to_ids(doc_uids) 沒帶計畫範圍);套件 jedi-compliance-audit infra/repository/ssp_document_pool_query.py:205-206。查核項目那支掛載方法同病、要一起改 |
把計畫範圍傳進 resolve_doc_uids_to_ids(),查詢條件加「屬於這份計畫的池子」。樣板照抄 app/module_frame/service/module_frame_reference_document_service.py:161,173 的 _get_doc_or_404。要改套件 |
無 | 新卡(或補 CM-2041);jedi-compliance-audit 要發版 |
| 1-4 | CM-2037 的寫法 | 套件守門寫成 curr_user_id: int = None、「有傳才檢查」。以後任何新呼叫端忘了傳,會安靜放行、不報錯 |
套件 jedi-compliance-audit:app/service/audit_round_app_service.py:223 list_rounds、:232 get_round、:900;poam_app_service.py:257 list_items、:284 get_item;assessment_result_app_service.py:404 get_findings、:709 list_risks(本棒實查共 7 支)。主專案 list_ap_parties(1-1)同型 |
7 支+list_ap_parties 的 curr_user_id 拿掉預設值改必填,呼叫端全部補傳 |
第 38 項:改必填,修正分支上順手改、合回前;套件要發版 | 併 1-1 同一棒(同是 CM-2037 退回範圍) |
| 1-5 | 手測陷阱(非缺口,是驗收會驗錯) | 開發機主 checkout 的 .venv 有 12 個 .pth 指到修正分支的套件工作區,但主 checkout 的路由還是舊的、沒傳 curr_user_id(本棒實查:主 checkout audit_round_route.py 24 處 vs 修正分支 32 處)。在主 checkout 手測「輪次讀取守門」,套件新守門一次都不會觸發,會誤判成「沒修好」或「修好了」 |
主 checkout .venv/lib/python*/site-packages/*.pth;總表 §0.5「已修要打折看」 |
輪次守門手測只在修正分支工作區或 190(1.21.0b2)做。合回後照 FR-114 STATE 第 5 步清掉那 12 個 .pth |
無 | 不開卡;寫進 1-1 那張卡的驗收段 |
| 1-6 | CM-2065(5C-4,Done,已發版) | 🔴 第 154 項(高,不必登入):每個請求在檢查身分之前,攔截器就把請求內容拿去「遮密碼」,那段比對遇到特製內容越算越久,幾個請求就卡住全部工人、所有客戶停擺。CM-2065 改了同一段比對(加上吃 JSON 跳脫序列),讓它再慢約 8 倍。jedi-common 1.3.0 已含 CM-2065(本棒實查 tag jedi-common-v1.3.0 包含 a9562dd0),190 上的 1.21.0b2 已經帶著這個惡化版 |
套件 jedi-common jedi_common/utils/common_utils.py:145 mark_password(比對規則 :159-160);主專案 common/middleware/app_mw.py:167(寫日誌)、:172(寫 api_log),都在遮罩前沒限長度 |
兩層:①套件把比對規則改成線性時間的寫法(根因);②攔截器遮罩前先截長度,超過就截斷並標「已截斷」。修完用同一組長度重測,確認耗時與長度成正比 | 總表 §7 第 33 項:發版前必須一起修(決策者要求轉告 FR-114) | 新卡、排最前;jedi-common 要發版(1.3.1),BE 改 pin。建議與 2-O 同卡(同一個攔截器,見第二段) |
| 1-7 | 總表第 133 項的修法(總表登記的舊修法錯了) | 第 133 項(刪框架/刪版本不檢查還有沒有客戶在用)總表舊修法是「照叫編輯路徑那支 _require_no_references()」。但那支查的是「基準線指向公版目錄」,而建資源庫一律先複製再引用副本,正常流程永遠零筆(DEV 591 筆基準線、指向公版 0 筆)——照原修法等於沒補。編輯公版目錄那六支、匯入覆蓋那一道呼叫的也是同一支,從來沒擋過東西 |
刪框架 app/oscal/service/framework_app_service.py:185、刪版本 framework_version_app_service.py:224;編輯路徑 framework_version_edit_service.py:207/218/230 呼叫、:258-266 定義;匯入覆蓋 framework_parse_job_service.py:386-403;正確該查的欄 compliance.module_frames.oscal_framework_version_uid(resource_library_app_service.py:512 寫入) |
三處(刪版本/編輯公版目錄/匯入覆蓋)改成用系統層跨客戶查詢查 module_frames.oscal_framework_version_uid 有沒有未刪除的資源庫在用,有任何引用就拒絕。「版本必須是草稿」那道照舊留著 |
第 46 項:三處同卡換;第 133 項維持中 | 新卡(主專案,不發版)。同卡可順手記「刪主版本、刪有子版本的版本會吐 500」(非資安) |
| 1-8 | CM-2052(代理程式通行證,Done)連帶 | 🔴 修正線啟動會炸:09-23 修 CM-2052 那顆 commit(套件 monorepo c4acc687)給 jedi-remote-agent 的 AgentTaskService 建構子加了一個必填零件 remote_agent_domain_service,但修正線 BE 的組裝表沒跟著接。修正線一啟動、走到代理程式任務那條路,會直接建構失敗(TypeError 缺參數)。這是修正線自己的 bug,不是掃描線發現的資安問題,FR-120 DI 比對腳本跑修正線基準時抓到的 | 修正線 BE worktree di_containers/agent_task/agent_task_containers.py:36 agent_task_service = providers.Factory(AgentTaskService, ...) 只給 agent_task_domain_service 與 lifecycle_listener;套件端 jedi_remote_agent/app/service/agent_task_service.py:47 宣告必填 | 在那個 Factory 補 remote_agent_domain_service=remote_agent_container.remote_agent_domain_service(主專案 di_containers/flow_control/flow_control_containers.py:437 已有同樣接法可抄) | 無(不是裁定項,是合回前必修) | 併回 CM-2052 或開一張連帶卡;合回主線前必修。兩份比對表:主線基準 docs/features/FR-120-2609-host-residual-security-scan/di-wiring-audit.md、修正線基準同資料夾 di-wiring-audit-fixline.md(「必填缺接」那節就是這一處;「🔴」那節多出的 4 處是修正線新加零件在修正線容器沒接,一併核) |
跟 FR-114 STATE 的衝突:STATE §1 寫「程式面 50/53 全 Done」「已發版 18 支套件」。1-1、1-3、1-4、1-6 會讓 CM-2037/CM-2041/CM-2065 三張 Done 卡重開或出新卡,jedi-common、jedi-compliance-audit 需要再發一版;1-6 會影響 STATE §2 第 13 條「正式 1.21.0 前必做」——建議把第 154 項加進那條清單。
從新卡清單剔除的(不要派):
| 項次 | 為什麼剔除 |
|---|---|
| 第 118/119 項 | CM-2041 已修在修正分支(套件 delete_by_uid 本身仍只認編號,已登記為 CM-2041 的已知限制,不另開) |
| 第 122 項 | CM-2055 已修(修正分支 f85a82edb:ssp_docx_generator.py:62 autoescape=True) |
| 第 126 項 | CM-2055 已修(同 commit:ssp_control_impl_import_service.py:140/164 改用 set_text_cell) |
| 第 159/160 項 | 已修:第 159 項 CM-2113(job_force_start_service.py:139 核對任務屬於網址專案)、第 160 項 CM-2148(:59 補成員檢查) |
| 第 166/167 項 | 第 36 項裁拆網址,見第四段 4-1 |
| 第 170 項 | 第 43 項裁拆網址,入口消失、問題跟著消失,見第四段 4-2 |
| 第 129 項 | 已列在第一段 1-3(CM-2041 缺口) |
| 第 133 項 | 已列在第一段 1-7 |
| 第 154 項 | 已列在第一段 1-6 |
| 第 168 項 | 修法由第 37 項裁定決定,排在 2-P(下表),不是剔除 |
每一列=一張建議新卡。 「發版」欄寫要發哪支套件;「基線」欄是出貨基線要不要重產。
| 卡 | 項次 | 一句話 | 嚴重度 | 該補檢查的位置(檔:行) | 併卡理由 | 發版 | 基線 |
|---|---|---|---|---|---|---|---|
| 2-A | 120+123+125+134+137+138+153 | 🔴 合規範本寫入有七處漏守:編控制項清單、Excel 匯入覆蓋、Word 匯入覆蓋三條路不檢查權限與歸屬;編輯範本時改「分享範圍」有檢查、改「內容」沒有;改流程圖的檢查包在 if 裡;刪改子項檢查網址編號、動手改另一個;只有「建立」權限能用 Excel 匯入覆蓋既有範本 | 高×3(120/123/125)、中×4 | 120:app/oscal/service/resource_library_app_service.py:364/412(+同路徑 _init_ao_workflows);123:ssp_excel_import_app_service.py:803-817 上傳端、:441/:478 確認端;125:ssp_docx_import_app_service.py:138-166 上傳端、:335 確認可換目標、:358-387;134:app/module_frame/service/module_frame_service.py:117(守的那半在 :112);137:module_frame_item_service.py:62-65 檢查移到 if 外、:84 寫入;138:module_frame_item_service.py:161(改)、:229(刪)、:247;153:module_frame_import_service.py:124-129(is_update 為真時加查 module-frame.update) |
同一塊地(合規範本寫入),總表明寫「三條必須一起修,只補一條另外兩條照樣進得去」;153 底下直接呼叫 134/138 那兩支 | 無(主專案) | 否 |
| 2-B | 128+149 | 🔴 SSP 匯出成 Excel 範本只查「你能不能讀資源庫」、不查「這份計畫是不是你的」,跨客戶一個 GET 就下載整份計畫;空白範本附帶全公司 email、設備 IP、資訊系統清單 | 高(128,跨客戶)、低(149) | 128:app/module_frame/service/ssp_import_template_app_service.py generate_for_ssp 第一行補 require_participant(ssp_uid)(照隔壁 export 抄,DI 在 di_containers/module_frame/module_frame_containers.py),入口 ssp_import_template_route.py:82-110;同檔 generate()(:223)順手補程式層檢查;149:同檔 :600 方法、:640-641 撈下拉資料改依呼叫者權限縮減 |
同一支服務檔,總表第 128/149 項都寫「修第 128 項時順手補」 | 無 | 否 |
| 2-C | 135+136+139+140+141+142+143+144+145 | 範本模組九項、十二個讀取入口不檢查權限,其中人員名單、設備清單、系統元件、繼承授權、系統特性跨公司都讀得到 | 中×8、低(145) | 全部補 @require_capability("module-frame.read"):135 api/module_frame/routes/module_frame_route.py:25-27、:45-47;136 module_frame_item_route.py:31-33;139 module_frame_reference_document_route.py:61-63;140 module_frame_control_objective_default_route.py:50-52、:109-111;141 module_frame_party_route.py:26-28;142 module_frame_inventory_route.py:19-20;143 module_frame_components_route.py:19-20;144 module_frame_leveraged_route.py:30-31+module_frame_system_characteristic_route.py:29-30;145 module_frame_ssp_resources_route.py:32-34 |
同一批讀取入口、同一行修法,總表要求一張卡。⚠️ 先確認 module-frame.read 權限點存在且現有角色都拿得到,否則症狀是永遠 403 且畫面沒錯誤訊息;135 選單那支的角色設計要先問決策者(總表第 135 項左欄);145 runner 另建議補 api/oscal/routes/module_frame_template_ssp_route.py,待決策者定 |
無 | 視權限點種子:若要補種子 migration → 要重產 |
| 2-D | 146+147 | **範本底下六類附屬資料寫入、Excel 批次存檔控制項清單,只問「查得到嗎」不問「是不是你家的」 | 中×7 | 146:六支服務的 _template_ssp_id() 解出範本後各加 assert_scope_writable(mf.tenant_id, mf.scope)(module_frame_party_service.py:86、module_frame_components_service.py:72、module_frame_inventory_service.py:77、module_frame_leveraged_service.py:84、系統特性、SSP 資源各一);147:module_frame_template_import_service.py:329 補同一行,同批補 validate_items(:265)與兩支下載(:173/:187) |
同型(查得到就放行),總表建議合成一張橫向卡;六支要一起補,補五支等於沒補** | 無 | 否 |
| 2-E | 121+175 | 建資源庫的入口只驗登入;而且不檢查框架版本發佈了沒,草稿也能拿去複製 | 中、低 | 121:api/oscal/routes/resource_library_route.py:50 補能力點(範本 ModuleFrameRoute.post),Excel 匯入、Word 匯入那兩條建資源庫的路也要一起補;175:resource_library_app_service.py:460-467 在 get_version 之後補「必須已發佈」,補這一支三個入口一次蓋到 |
同一支 create_resource_library,FR-118 README 修正線第 1 件 |
無 | 否 |
| 2-F | 124+127+130+176+179 | 壓縮炸彈四個入口、兩個 repo:SSP 的 Excel/Word 上傳、稽核計畫 Word、稽核結果 Excel 都只量壓縮後大小,解開整份塞記憶體;稽核結果 Excel 還一路讀到上傳者決定的最後一列(4.9KB 檔吃 355MB) | 中×5 | 主專案:app/oscal/service/excel_parser/parser.py:42(read_only=False,124/130 同一行)、ssp_excel_import_app_service.py:124-126;ssp_docx_import_app_service.py:50/131 限制、:759 解析(一份上傳會被打開三次,檢查要放第一次開檔前)。套件 jedi-compliance-audit:import_adapter/registry_base.py:24(176)、ar_report_parser/airasia_cmmc_l1_ar_v1.py:162-164+registry.py:17(179) |
總表明寫「病灶四個入口兩個 repo、共用同一支檢查函式、同一張卡」;FR-116 README 修正線第 4 件。上限數字參考 config/config.py:194-200,但那組是照檢測規則包訂的,合不合適由開卡的人判斷 |
jedi-compliance-audit | 否 |
| 2-G | 173 | 一份幾 KB 的特製 Word 讓 SSP 匯入解析卡到 120 秒逾時,四個請求讓整個 API 對所有客戶停擺,六個位置 | 中 | domain/oscal/parser/docx_section_extractors.py:538-541、:545-549、:74-86;domain/oscal/parser/control_id_matcher.py:20、:50-76;轉接器「標籤:值」切法與兩處找排第幾(詳見總表第 173 項) |
🔴 兩支檔各有一條比對規則,同一份檔會先後跑到,只修一邊等於沒修——驗收要用同一份惡意檔從上傳整條跑一次,不能只各自單元測試。與 2-A 第 125 項、2-F 第 127 項同一條上傳路,排程一起看 | 無 | 否 |
| 2-H | 131+152+177 | 比對規則沒防長輸入:Excel 版本號那格(跑在版本檢查之前,不用合法範本)、Excel 範本匯入檢核的網頁標籤比對、稽核計畫 Word 解析器三條規則,送超長字串就卡住一條工人 | 中(131)、低×2 | 131:app/oscal/service/excel_parser/parser.py:143/148/151-153——最好直接刪掉這份、改用既有的 version_check.parse_semver;152:app/module_frame/service/module_frame_import_service.py:52 開頭擋長度、:23 規則改 <[^<>]{1,200}>;177:套件 ap_report_parser/airasia_cmmc_l1_v1.py:57/:62/:107-113,:205 起先截長度 |
同型,總表寫「一起修」 | jedi-compliance-audit(177) | 否 |
| 2-I | 171+172 | 特製的 CMMC PDF 把解析拖垮:頁數沒上限、每頁不釋放;目錄行比對遇超長一行平方級變慢 | 低×2 | 套件 jedi-oscal-v2:infra/adapter/base_parser_adapter.py:37-57 開檔後先擋總頁數、每頁 page.close();infra/adapter/cmmc/cmmc2_lv2_parser_adapter.py:73 _TOC_PATTERN、:81 開頭 len(line) > 500 直接當內文、:407 改 str.find。主專案 framework_parse_job_service.py:215 前可再擋一次 |
同一支檔、同一次發版;第 45 項裁與 jedi-oscal-v2 依賴清理同次發版 | jedi-oscal-v2 | 否 |
| 2-J | 132+174 | 解析失敗把原始錯誤訊息回給前端:PDF 那側吐套件結構與 SQL,Word 那側吐伺服器暫存檔完整路徑 | 中、低 | 132:app/oscal/service/framework_parse_job_service.py:228 拿掉 : {e}(本棒實查仍在),:215-219 那個 try 也包住寫資料庫、一併涵蓋;174:domain/oscal/parser/docx_parser_core.py:23(訊息不接 original)、:171-172/:193-194,服務層 ssp_docx_import_app_service.py:220/:226 不用 str(e) |
同一種修法,總表 §4 🅶 組寫「一張卡兩邊一起改」 | 無 | 否 |
| 2-K | 148+150 | Excel 範本公式注入:上傳時塞進去的公式、或任何人把自己暱稱改成公式,會在別人下載範本開啟時執行(連空白範本也算) | 中×2 | 改用 jedi-common 的 set_text_cell(已在 1.3.0,本棒實查 export_safety.py:29),五處六行逐一列成驗收項:app/module_frame/excel_template/lookup_builder.py:47、:91、:93;generator.py:578、:319、:247(本棒實查這兩支檔尚未用 set_text_cell)。⚠️ generator.py:543 _apply_autofill_formulas 是系統刻意寫的公式,不能一起改;只修 578 會守一半 |
總表 §7 第 31 項已裁「合一張卡」,含帳號模組的使用者匯入範本;上傳端 sheet_handlers.py:64 已裁「只記警告日誌、不改內容」(§7 第 32 項) |
無(jedi-common 1.3.0 已含 set_text_cell) |
否 |
| 2-L | 151 | 幾 KB 的 YAML 讓伺服器算到當掉(引用展開無上限) | 低 | infra/module_frame/adapter/yaml_to_module_frame_parser_adapter.py:14 parse 開頭改自訂 SafeLoader、遇 alias 拒絕;:35 加層數與節點數上限;格式錯目前炸 500 要改回「格式錯誤」 |
單獨一張(也可併 2-H 同一輪) | 無 | 否 |
| 2-M | 155+156+157+158 | 規劃頁任務的四個入口不核對「這張任務屬不屬於網址上那個專案」:清單、批次匯入確認(可順便改別的專案的任務)、匯出、匯入驗證兩步 | 中×2、低×2 | 155:app/flow_control/service/job_service.py:269 list_jobs 開頭補 assert_project_participant、專案編號改必填(本棒實查未修);156:job_import_service.py:398 confirm_import、白名單 :413 改用「這個計畫底下的任務」並核對計畫的專案=網址專案;157::104 export_excel 核對計畫的專案=網址專案;158::198 validate_import、:315 revalidate_items 開頭補「計畫屬於網址專案+你是成員」(本棒實查四支都未修) |
總表 §4 🅰「第八種長相」:五個入口要逐一列驗收項。決策者原裁第 156 項併 FR-114 卡 2-7(CM-2039),但 2-7 已 Done,所以改開新卡;第 159/160 項已修(見剔除表)。「任務屬於哪個專案」的判斷請用 CM-2113 的唯一歸屬判斷(resolve_project_id_for_job),見本段末 |
無 | 否 |
| 2-N | 161 | 「AI 金鑰只限平台管理員」開關一放開,原廠 AI 金鑰會被送到客戶自己指定的伺服器(今天打不到) | 中 | app/system_config/service/ai_provider_key_resolver.py:133/:154(位址跟金鑰同層取);app/system_config/service/tenant_storage_config_seeder.py:52-55(新租戶不抄金鑰);開關說明 common/constant/ai_service_config.py:29 |
單獨 | 無 | 否 |
| 2-O | 163+164 | 操作日誌兩個洞:網址加長就不留紀錄(欄位超長寫入失敗);來源 IP 全記成前端代理 | 中、低 | 163:common/middleware/app_mw.py:160-197 寫入前把所有有上限的欄位截斷(網址 500、IP 255、瀏覽器資訊 5000),寫入失敗至少留一筆替代紀錄;164:app_mw.py:189、common/integrity/adapters.py:268-272、jedi-iam jedi_iam/api/routes/login_route.py:26 三處統一,不能直接改讀 X-Forwarded-For,要讓後端只信 nginx 那一跳 |
同一個攔截器;決策者已裁「同卡截所有欄位」「三處讀 IP 一起統一」。建議與 1-6 第 154 項同卡(同一個 before_request) |
jedi-iam(164 那處) | 否 |
| 2-Q | 162 | 證據分類跑超過 30 分鐘逾時,原廠 AI 金鑰以明文寫進後端日誌 | 中 | 套件 jedi-evidence-classification infra/classifier_container_runner.py:189-190(raise ... from None,更根本改 --env-file);主專案 infra/support/diag_masking.py:164 _LOG_SECRET_LINE_RE 補認 KEY=值 |
⚠️ 套件那半要照外部套件異動規範先提醒、決策者點頭才動 | jedi-evidence-classification | 否 |
| 2-R | 165 | 沒買問卷模組的客戶照樣能用問卷的「填答」那半(14 支方法沒掛授權檢查) | 低 | 套件 jedi-survey api/routes/task_survey_route.py、question_answer_route.py、question_answer_history_route.py、question_answer_history_detail_route.py,每支 @jwt_required() 下加 @require_license("survey")(行號見 FR-115 W1 報告總覽表) |
決策者已裁三個入口一組一張卡 | jedi-survey | 否 |
| 2-S | 169 | 把稽核「判定」接到「風險」時,套件不檢查兩者是不是同一份稽核結果(唯一呼叫端有擋,是地雷) | 低 | 套件 jedi-oscal-v2 app/service/assessment_risk_service.py:109-125 link_findings 開頭逐一比對 ar_result_id、:132-143 get_risk_findings 同樣過濾;呼叫端現有那道留著 |
守在套件;可併 2-I 同次 jedi-oscal-v2 發版 | jedi-oscal-v2 | 否 |
| 2-T | 178 | 兩張「解析工作單」表的資料庫隔離規則是 5 月已判定壞掉、SSP 那張早修掉的舊寫法,7 月建表照抄——DEV 實測子公司看得到母公司的工作單 | 低 | scripts/sql/2026-07-02-ap-docx-parse-jobs.sql:40-42、scripts/sql/2026-07-03-ar-xlsx-parse-jobs.sql、scripts/init/02-schema.sql:24943。照 2026-05-01-fix-ssp-docx-parse-jobs-rls.sql 改成 app_tenant_allowed_for_session(tenant_id)+超級管理員放行 |
兩張表一起修(FR-116 README 修正線第 5 件) | 無 | 🔴 要重產(新 migration,屬決策者裁示;只套 DEV) |
| 2-U | 180 | 確認匯入稽核結果時,佐證資料照前端送來的存、不核是不是這一輪的 | 低 | 主專案 api/project/serializers/ar_import.py:38;套件 jedi-compliance-audit ar_import_app_service.py:301、assessment_result_app_service.py:552-580:確認時比對工作單存的候選池、連結只收 http/https;一般新增觀察網址 audit_round_route.py:286-311 同修 |
🔴 檔案那半要等總表第 34 項(檔案預覽補歸屬檢查)才真正關得起來,開卡時寫明依附 | jedi-compliance-audit | 否 |
| 2-P | 168 | **專案經理能改寫、再刪掉稽核人員寫的「改善建議」 | 低 | 主專案 api/project/routes/audit_round_route.py:440 RiskRemediationsRoute.post、serializer api/project/serializers/audit_round.py:211-212(uuid/lifecycle 無值域限制);套件 poam_app_service.py:310 add_remediation |
第 37 項已裁「稽核方專屬」:類型是「建議」那筆拒絕覆蓋、拒絕刪除**,不做另存留痕 | jedi-compliance-audit | 否 |
特別標的幾件(卡上要寫清楚):
「任務屬於哪個專案」要不要再裁:總表 §7 第 35 項寫 CM-2108「方案待決策者裁」,但 FR-114 LOG 第 5 棒記載決策者已裁「掃描線 CM-2108 插單四件同批」,CM-2113(輪次鏈唯一判斷)已 Done。看起來總表那句已過期,2-M 直接用 CM-2113 的判斷即可——請首腦開卡前對照 CM-2113 卡確認。本棒不改總表。
數字:第二段 21 張新卡(2-A~2-U),加第一段新卡/重開 6 件(1-1 退回、1-2、1-3、1-6、1-7、1-8;1-4 併 1-1,1-5 不開卡),合計建議 27 張。若 2-L 併 2-H、2-S 併 2-I、2-O 併 1-6,可壓到 24 張。
第 118~180 項 63 條逐條去向(本棒腳本核過,無遺漏無重複):新卡 2-A~2-U 涵蓋 51 條;第一段 3 條(第 129、133、154 項);拆網址 3 條(第 166、167、170 項);已修 6 條(第 118、119、122、126、159、160 項)。
| 項次 | 一句話 | 裁定 | 備註(照抄) | 修正線要做什麼 |
|---|---|---|---|---|
| 第 36 項 | 任務設定樹、目前 SSP 兩支網址:補守門/拆 | 選 B:拆網址 | 與第 44、43 項同批;套件 api/routing.py 拆兩支、要發版 | 開拆網址卡(第四段 4-1),jedi-compliance-audit 發版 |
| 第 37 項 | 改善建議:稽核方專屬/經理可改但留痕 | 選 A:稽核方專屬 | 第 168 項修法=類型是「建議」那筆拒絕覆蓋與刪除;不做另存留痕 | 開 2-P |
| 第 38 項 | 修正分支守門參數:改必填/維持選填 | 選 A:改必填 | 修正分支 fix/security-b1 順手改,FR-114 合回前;套件要發版 | 第一段 1-4,併進 CM-2037 退回 |
| 第 39 項 | 回退標記讀取:列死碼/先問產品 | 選 B:不清、記功能待補 | 階段回退作廢表已寫、讀的那半沒接;功能上不會抓錯(輪次 ssp_id 決定現用);記「凍結歷史標記作廢/瀏覽」功能待辦,三支讀取保留 | 不歸修正線。三支讀取方法不要當死碼清掉 |
| 第 40 項 | 複製 SSP 參照:修程式不補快照/修程式也補快照/先不開卡 | 選 A:修程式、舊快照不動 | §3.2 第 36/37 項同卡修在套件;DEV 47 份凍結快照留著不清不補(凍結證據不事後動);STG/POC 出貨前視情況再查 | 開一張非資安卡(總表 §3.2 第 36+37 項,修在 jedi-oscal-v2 ssp_clone_service.py:170-176、oscal_io_service.py 再匯入那幾處);修第 37 項前先用一份 Word 在 DEV 跑兩次確認。不寫資料修補 |
| 第 41 項 | 凍結保護:套件加第二道/維持一層 | 選 A:套件加第二道 | 凍結是套件自己定義的(snapshot_ssp/FROZEN_STATUS「immutable marker」),套件 update_* 自己擋 frozen;與第 45 項同次發版 | jedi-oscal-v2 ssp_service.update_* 遇已凍結就拒絕(先確認凍結當下那一步不會被擋),與第 45 項同卡 |
| 第 42 項 | CM-2037 團隊名單:退回改 404(點頭/不點頭) | 點頭:退回 CM-2037 | list_ap_parties 改「查不到輪次就 404」;主專案改不發版 | 第一段 1-1 |
| 第 43 項 | 稽核中重排:一律走退回/允許重生 | 選 B:拆網址 | generate-draft 前端零呼叫、後端只有該路由呼叫、v1.20.0 release note 已點名退役;連同 launch-audit/start-auditing/ar/finalize 三支一起裁;e2e step 同拆;第 170 項隨之消失 | 開拆網址卡(第四段 4-2) |
| 第 44 項 | 更新稽核計畫網址:拆/補守門 | 選 B:拆網址 | 與第 36、43 項同批 | 開拆網址卡(第四段 4-3) |
| 第 45 項 | 套件依賴清理:同次發/分開發 | 選 A:同次發版 | jedi-oscal-v2:第 171/172 項修+defusedxml 補宣告+拿 pyyaml/ImportType.YAML,JSON+第 41 項凍結第二道+§3.2 第 36/37 項,一次發 | 套件 pyproject.toml:15 補 defusedxml、拿掉 pyyaml,順手拿掉 ImportType.YAML/JSON;與 2-I、第 41、40 項同一次 jedi-oscal-v2 發版 |
| 第 46 項 | 另兩道引用檢查:同卡換/只修刪除 | 選 A:三處同卡換 | 刪版本/編輯公版目錄/匯入覆蓋三處改查 module_frames.oscal_framework_version_uid,有任何客戶引用即拒絕;理由是保護稽核依據可追溯(業界慣例已引用版本不硬刪);第 133 項維持中 | 第一段 1-7 |
| 第 47 項 | 捨棄解析工作單:收緊/維持 | 選 A:收緊 | 捨棄解析工作單改稽核員或管理者,與 Excel 側一致;套件一行、同次發版 | jedi-compliance-audit ap_docx_import_app_service.py:172 守門換成 resolve_ap_and_check_auditor |
| 第 48 項 | blsadmin 旗標:測試資料/產品允許 |
選 A:測試資料 | 首腦唯讀查三環境:DEV admin+blsadmin(102)、STG 只 admin、POC 只 admin;STG/POC 乾淨,DEV blsadmin 拿不拿掉屬整潔不裁 | 不開卡 |
| 第 49 項 | 對照查詢輪次編號:改必填/維持 | 選 A:改必填 | get_wf_ids_by_control_ids round_id 必填;套件一行、同次發版 | jedi-compliance-audit wf_control_mapping_lookup_query.py:30-53 的 round_id 拿掉預設值 |
| 第 50 項 | 任務入口與批次(U7):掃/不掃 | 選 A:掃 | U7 進下階段主專案掃描(決策者 2026-09-25 裁) | 不歸修正線(掃描線下階段) |
| 第 51 項 | 權限共用層那句:照盤點更正(點頭/不點頭) | 選 A:更正 | 總表 §0.5 補句;common/authz 排 U1 第一棒 | 不歸修正線 |
| 第 52 項 | 系統設定守門補掃:併 U12/單獨一棒/不補 | 選 A:補掃 | 併 U12 | 不歸修正線 |
| 第 53 項 | 組裝檔專掃:工具掃 17 支/工具掃全部/腳本對照全部 | C 先、A 後、B 不做 | 先開實作卡寫腳本比對 75 支建構參數 vs 容器參數;U13a/U13b 兩棒帶著腳本結果掃 17 支沒碰過的 | 不歸修正線。腳本實作卡由掃描線開 |
| 第 54 項 | 人員對帳跨公司比對:補併 U12(點頭/不點頭) | 選 A:補 | 併 U12(與第 52 項合計約 1,770 行) | 不歸修正線 |
照目前修正分支版號(pyproject.toml)往上推;版號由 FR-114 首腦依實際改動定。發版前同一支套件的改動全部做完、驗完才發(FR-114 STATE 已知的坑:iam 補發三次)。
| 套件 | 現在版號 | 這一包含什麼 | 建議下一版 |
|---|---|---|---|
| jedi-oscal-v2 | 2.4.0 | 第 171/172 項(2-I)+第 45 項依賴清理(defusedxml 補、pyyaml 拿、ImportType.YAML/JSON 拿)+第 41 項凍結第二道+§3.2 第 36/37 項(第 40 項)+第 169 項(2-S,可選同包) |
2.5.0(有新行為:凍結拒寫) |
| jedi-compliance-audit | 1.2.0 | 第 36 項拆兩支網址(4-1)+第 38 項 7 支 curr_user_id 必填(1-4)+第 47 項捨棄收緊+第 49 項 round_id 必填+第 37 項/第 168 項建議不可覆蓋刪除(2-P)+第 129 項掛載限計畫(1-3)+壓縮炸彈與列數上限(2-F 的 176/179)+第 177 項(2-H)+第 180 項(2-U) |
1.3.0(拆網址、必填參數是不相容改動,呼叫端要同步) |
| jedi-common | 1.3.0 | 🔴 第 154 項 mark_password 線性化(1-6) |
1.3.1,正式 1.21.0 前必發 |
| jedi-iam | 1.4.3 | 第 164 項 login_route.py:26 讀 IP 統一(2-O) |
1.4.4 |
| jedi-survey | 1.2.0 | 第 165 項 14 支補 require_license("survey")(2-R) |
1.2.1 |
| jedi-evidence-classification | 1.3.0 | 第 162 項逾時不吐金鑰(2-Q;先照外部套件異動規範取得決策者點頭) | 1.3.1 |
⚠️ 拆的是網址(路由),不一定是背後的方法。4-2 的 launch-audit/start-auditing/finalize 背後的套件方法也被畫面上的「階段推進」按鈕呼叫(修正分支 app/flow_control/service/oscal_stage_handlers.py:46/:62/:82),方法不能刪,只拆直打的網址。
| # | 網址 | 在哪裡 | 前端零呼叫的證據(本棒 2026-09-25 grep) | e2e 有沒有在打 | 拆時要一起拆什麼 |
|---|---|---|---|---|---|
| 4-1a | 任務設定樹 GET /project/<project_uid>/ap/<ap_uid>/task-setup/tree(第 36 項/第 166 項) |
套件 jedi-compliance-audit api/routing.py:33-36(ProjectTaskSetupTreeResource);服務 app/service/task_setup_service.py:18 |
修正分支 FE:零命中(TaskSetupView.vue 已在 CM-2047 拆掉)。⚠️ FE feature/review 主線還有 src/views/project/TaskSetupView.vue:109 在打,合回後才消失——拆網址要排在 FE 合回之後,或同批 |
無(site-regression 零命中) | 路由那段;套件 TaskSetupService 與 plugin/contract.py:55 那一欄、主專案 di_containers/flow_control/flow_control_containers.py:469-470、core/plugins/compliance_audit.py:123 的組裝;infra/repository/flow_control_task_setup_repo_impl.py:247 _resolve_ssp(若無其他呼叫者)。FE i18n task-setup.json 與 menu 字串可一起清。拆前確認沒有 AI 儀表板或外部整合在用(第 36 項原文要求,掃描那棒沒做) |
| 4-1b | 目前 SSP GET /project/<uid>/current-ssp-uid(第 36 項/第 167 項) |
套件 api/routing.py:31(ProjectCurrentSspRoute);服務 app/service/project_current_ssp_service.py:35 |
FE 只剩定義沒人叫:src/config/api/api.js:263 PROJECT_CURRENT_SSP、src/service/SspService.js:189 getCurrentSspUid(),全 FE 零呼叫者 |
🔴 有:site-regression/support/data-factory/ssp-factory.js:13-14 getLivingSspUid() 直打,被 steps/project-management/ssp-helpers.js:9 引用。另一支同名函式 task-survey-factory.js:15 改走 GET /grc/project/{uid} 取 ssp.id,可照它改寫 |
路由;ProjectCurrentSspService 與組裝(flow_control_containers.py:249-250、core/plugins/compliance_audit.py:121、套件 plugin/contract.py:55);FE api.js:263 與 SspService.getCurrentSspUid;e2e ssp-factory.js 改走 /grc/project/{uid}(到 test repo 做) |
| 4-2a | 重生草稿 POST /audit-round/<round_uid>/ap/generate-draft(第 43 項/第 170 項) |
主專案 api/project/__init__.py:52、api/project/routes/audit_round_route.py:172 AuditRoundApGenerateDraftRoute;服務 app/flow_control/service/assessment_plan_app_service.py:672 generate_draft_for_round(唯一呼叫者是該路由 audit_round_route.py:180) |
FE 零命中(api.js 連定義都沒有);v1.20.0 release note(docs/spec-site/current/release-notes/v1.20.0.md:110)已點名「前端零呼叫、只有 e2e step 在打,待開卡裁決後退役」 |
🔴 有:site-regression/steps/journeys/j5a-negatives.steps.js:99(「AP 重生草稿」) |
路由+generate_draft_for_round 方法(後端無其他呼叫者,可一起刪);e2e 那一條 step 與對應 scenario |
| 4-2b | POST /audit-round/<round_uid>/launch-audit |
api/project/__init__.py:46、audit_round_route.py:92 AuditRoundLaunchAuditRoute |
FE 只有 api.js:213 註解與 :287 GRC_LAUNCH_AUDIT(另一條 /grc/project/.../ap/.../launch-audit 的舊常數)定義,全 FE 零呼叫者。畫面走 StageService(/project/:p/audit-round/:r/stage/advance) |
🔴 有,而且是前置推進工具:support/data-factory/audit-round-factory.js:40-43 launchAudit()、ssp-factory.js:19-21;feature journeys/j4-phase-guards.feature:13/20、j5-state-machine-negatives.feature:32/42/52、modules/project-management/project-ssp-edit.feature:22;steps lifecycle.steps.js:289、j5a-negatives.steps.js:95 |
只拆路由,不刪套件 audit_round_app_service.launch_audit(階段推進在用)。e2e:factory 改用 advanceStage(audit-round-factory.js:254 已有、檔頭 :18-22 已寫「前置推進必須改用 advanceStage」),j4/j5 負向測試改打階段推進端點或刪除。e2e 改動量大,建議先在 test repo 開一棒改完再拆網址,否則回歸全紅 |
| 4-2c | POST /audit-round/<round_uid>/start-auditing |
api/project/__init__.py:47、audit_round_route.py:105 AuditRoundStartAuditingRoute |
同 4-2b(api.js:214 只有註解) |
🔴 有:audit-round-factory.js:51-53 startAuditing();j4/j5 同上;j5a-negatives.steps.js:96 |
同 4-2b:只拆路由,套件 start_auditing 保留(oscal_stage_handlers.py:62 在用) |
| 4-2d | POST /audit-round/<round_uid>/ar/finalize |
api/project/__init__.py:73、audit_round_route.py:360 AuditRoundFinalizeRoute |
FE 零命中 | 🔴 有:audit-round-factory.js:118-120 finalizeRound();steps/journeys/j5-negatives.steps.js:41 |
同 4-2b:只拆路由,套件 finalize_audit 保留(oscal_stage_handlers.py:82 在用) |
| 4-3 | 更新稽核計畫 PUT /grc/project/<pid>/ap/<ap_uid>(第 44 項) |
主專案 api/flow_control/__init__.py:106、api/flow_control/routes/assessment_plan_route.py:51-91 AssessmentPlanDetailResource.put;服務 app/flow_control/service/project_service.py:536 update_assessment_plan(空殼,return None, False) |
FE 只有 api.js:204 GRC_AP 定義(註解寫 PUT),全 FE 零呼叫者 |
無(site-regression 零命中) | put 方法+AssessmentPlanUpdateRequestSchema(若無他用)+project_service.update_assessment_plan 空殼+路由裡 Drive 改名同步那段呼叫;FE api.js:204 常數。⚠️ 同一個 Resource 還掛著 GET,只拆 PUT、不拆整個路由。同檔 DELETE 已於 2026-07-21 退役,可照那段寫法 |
拆的順序建議:4-3(無 e2e、主專案)→ 4-2a(一條 e2e step)→ 4-1(等 FE 合回、改一個 e2e factory、發套件)→ 4-2b/c/d(先到 test repo 把前置推進改成 advanceStage,再拆)。
module_frames.oscal_framework_version_uid,第 133 項維持中。blsadmin 是測試資料,不開卡。