建議 model:Opus,effort:high——全案回歸面最大的一張,改的是每個 @transaction 必經的路,壞法是「查不到」不是報錯。本卡由 CM-1559 拆出,決策者 2026-09-14 裁延後至 1.20.0 之後、SaaS 上線前必做。前置:.1a CM-1767、第二刀 CM-<第二刀卡號>。動手前先回寫本卡問首腦要不要現在做——這張沒有可信的 DEV 驗證環境(見下)。
問題是什麼(白話)
session_scope() 在完全沒有使用者身分時(db.py:115-119 的 elif is_pg: 分支)直接給超級管理員。任何在沒身分下跑的 @transaction 都以最高權限執行:漏掛 JWT 檢查的路由、公開端點、沒還原 context 的背景執行緒全部踩到。正解是「繞 RLS 應該是一個動作,不是一個預設」——無身分改成拒絕(fail-closed),真的需要跨租戶的路徑各自明確宣告。
為什麼延後:要關的洞落地版目前打不到(盤點沒找到現存「沒掛 JWT 又查 RLS 表」的路由);而改壞的路徑有十幾條且靜默;Drive 兩張表在 DEV 的擁有者是 cm_app(表擁有者不受 RLS 約束),DEV 對 Drive 路徑一定假綠、要 STG 才驗得出,而 STG 是上版動作。
依賴 fail-open 的路徑(CM-1559 第一步盤點 2026-09-06,動手前重跑一次核對)
- A 引導型(要有身分才查得到身分):JWT 身分解析 jedi_iam/middleware/jwt_mw.py:87→core.py:96→user_service.py:97(壞法:全站 401);登入 login_route.py:33;忘記密碼 user_change_password_service.py:35,80,126;agent 註冊查 enroll token agent_enrollment_service.py:200。修法:elevated_readonly_session() 只包那一句查詢;agent 註冊拆兩段。
- B 背景排程(core/scheduler.py 8 支):drive_sync_worker(:146,靜默空轉)、license_expiry_state_machine(過期租戶永不轉唯讀)、detection_execution_timeout(卡住的掃描永不收斂)、webhook_channel_renewer;framework_parse_job_cleanup 與 job_binding_orphan_cleanup 由 .1a 接好。修法:沿用 .1a 的 system_context(name)。
- C 機器端點(無 JWT 設計如此):agent 控制面 jedi_remote_agent/api/remote_agent_route.py:182-211(所有 agent 掉線)、agent 檔案下載授權 agent_file_access_service.py:110(讀回空→404,看起來像權限正常)、Google Drive webhook api/cloud_integration/routes/google_drive_webhook_route.py:39(tenant 在 URL)。修法:已知租戶建真實 context 走 build_user_context()。
- E 確認不壞:socket 事件已 fail-closed(socketio_auth.py:255)、setup 精靈給了 /1/ 路徑、api_logs/login_tokens 無 RLS、cmmgr 維運腳本 bypassrls。
在哪裡
~/Projects/Jedicogy/module/jedi-python-package/jedi-common/jedi_common/session/database/db.py:115-119 elif is_pg 無 context 分支(改 fail-closed+WARNING log)
~/Projects/Billows/Audit-Manager/compliance-manager-be/core/scheduler.py 其餘 6 支排程接 system_context
~/Projects/Jedicogy/module/jedi-python-package/jedi-iam/jedi_iam/middleware/jwt_mw.py:87 JWT 解析改窄提權
~/Projects/Jedicogy/module/jedi-python-package/jedi-iam/jedi_iam/infra/elevated_session.py:38 窄提權樣板
(A/B/C 其餘檔案見上段行號)
怎麼修(順序不能反)
- ① 重跑盤點:對照 2026-09-06 清單 grep 一次,新增的無 context 路徑補進來;STG 的 RLS 開啟表清單與 DEV 比對(唯讀 docker exec psql)。回寫本卡等首腦看過。
- ② 先接線後下刀:A 類窄提權、B 類 system_context、C 類 build_user_context 全部接完並各自手測。
- ③ 下刀:elif is_pg 改成
SET LOCAL app.is_super_admin='f'、不設 allowed_tenant_paths,並 logger.warning('session_scope entered without user context: %s', <端點或 job 名>)——沒有這行,未來第 N 條靜默路徑沒人會發現。
- ④ 拿掉 .1a 守衛④的白名單(8 支排程全部有 context)。
要寫測試
- 無 context 進 session_scope → app.is_super_admin 為 'f' 且查 users 回 0 列(以 cm_app 連線)。突變:把 elif 改回 't' 要紅。
- 每支排程 tick 進 session_scope 時 get_user_context() 不為 None(.1a 守衛去白名單版)。
手測