本卡為 FR-085 母案。掃 jedi-common 套件(25 支 jedi-* 套件的共用地基)91 檔,切三棒。只掃不修。 子卡清單在末段。
jedi-common 是所有 jedi 套件與主產品共用的底層:每一次資料庫存取都經過它的 session_scope(它負責告訴資料庫「現在是誰在查、能看哪些客戶的資料」,也就是 RLS 隔離的注入點);每一個錯誤回給前端的格式由它決定;每一行 log 怎麼寫、寫到哪裡也是它。它出問題等於 25 支全中。 這個 arc 要回答:資料庫隔離會不會被繞過或注入、錯誤訊息會不會把內部細節洩給前端、log 會不會把密碼或可偽造的身分寫進去、回給前端的資料會不會夾帶不該有的欄位。
session.database 201、handler.exception 184、session.auth 96、utils.response_util 78),爆炸半徑是全站。session/database/db.py:93-114,SET LOCAL app.user_id = '{...}'、app.allowed_tenant_paths = '{...}'),沒有 bind parameter。若值能帶單引號,就能脫逸字串再接一句 SET LOCAL app.is_super_admin = 't'。這是獨立於 CM-1559 的注入面。app.can_manage_orgs = 't'(db.py:98),沒有任何條件判斷。X-UserId(logger/middleware.py:13、decorator.py:11),任何呼叫端可偽造稽核紀錄的操作者;BE 與 FE 都沒有任何地方設定這個 header。handler/sql_exception.py:37-38),表名、欄位名、約束名外洩;信封組裝失敗時把例外訊息當 data 回前端(utils/response_util.py:26)。page_size 沒有上限(interfaces/schema/common.py:13,page 有 min=1、page_size 完全無界)。utils/gen_comment.py 帶 OpenAI key 直讀環境變數(:8)、用未定義變數 file_path 開檔覆寫原始碼(:49)、吞光例外(:54)。session/+identity/+handler/。唯一能造成「跨租戶看到別人資料」的區塊:RLS 注入、身分 contextvar、例外洩漏三者互相咬合,拆開會漏掉「fail-open + 例外訊息回前端」的合流。CM-1559 落在這一棒(當已知基準線,不重報)。logger/。唯一一條「資料離開 process」的路(stdout/檔案/DB system_logs/OTLP gRPC)。自成 DDD 四層、與其他兩棒零耦合,心智模型不同(看「什麼被寫出去」而非「誰能讀」)。interfaces/+utils/+enums/+constants/+root 的 .env、publish.sh。共同問題是「什麼會被序列化回前端、什麼欄位會被過濾」,純資料整形+打包設定。CM-1598(.env 受版控)落在這一棒。接縫:utils/response_util.py(在 C3)與 handler/handler.py(在 C1)是「例外 → 信封」的兩端,C1 卡片明寫可越界讀 response_util.py、C3 卡片明寫可越界讀 handler.py,重複報由首腦驗收挑掉。
建議順序 C1 → C2 → C3(依風險密度)。一次只派一棒,每棒獨立驗收完才派下一棒(FR-081 換來的紀律)。