給 FR-075 首腦的一句話:FR-080(jedi-* 插件化第一階段)八棒+六張插隊卡全部驗收通過,整條 branch 已合進
feature/FR-075(BE28cf59fd、套件 fast-forward 到da25a8d)。決策者裁(2026-09-11 晚更新):「租戶隔離破洞」的資安修正歸 FR-075 這條線;FR-080 自己的收口七項仍由 FR-080 首腦做。分工見 §四。本檔是你要讀的唯一入口;FR-080 自己的 STATE/LOG 留作歷史。
| 類別 | 內容 | 驗收 |
|---|---|---|
| 四組套件合併 | device+information-system → jedi-asset;system-config+system-menu → jedi-system-core;log-forwarding → jedi-log;participant → jedi-task-platform | 八棒各自 Done,首腦親驗 |
| 空殼補實 | jedi-bulletin 補成完整插件;asset/system-core 有不靠主專案就能起的 harness | 親跑三行指令通過 |
| 疆界清理 | 四支套件對疆界外依賴改接口;通用套件去業務知識;六支轉發殼搬 monorepo archive/ |
跨套件 import 120→105、零使用接口 16→6 |
| 出貨基線 | CM-1655:六支標 envs=dev 的結構變更補進基線+加守門(check_env_scoped_migrations.py) |
乾淨容器 init + 帶舊資料升級雙驗 |
| 今日六張插隊卡 | CM-1655/1656/1657/1658/1659/1660/1661(見 §三) | 全部首腦親驗,見各卡回寫 |
指標(基線→現在):跨套件 import 120→105/零使用接口 16→6/宿主接線 7,457→8,677/能直接裝 17→17(套件 25→21)。
CM-1661 修好了「切租戶後權限全空」,但這一修把後面更大的洞暴露出來:切到租戶 C 後,仍看得到租戶 A 的待辦任務與專案。決策者 2026-09-11 實測抓到,並定調產品模型:
垂直向下可管理(父看得到子孫),不同分支互相隔離;平台級資源(法規框架、控制項目錄、內建範本)全租戶可讀、只有原廠可寫。
現況離這個模型差多少(首腦 SQL 實證,全在 DEV,四環境一致):
| 層 | 狀態 | 證據 |
|---|---|---|
RLS 核心函式 app_tenant_allowed_for_session |
✅ 已是向下涵蓋語意 | 鑰匙 /1/102/ 看得到 152/153/162/163/164,看不到平行的 131 |
| 平台級資源(oscal.catalogs/profiles/frameworks) | ✅ 表無租戶欄、寫入限 root | require_platform_admin_route |
租戶級:flow_templates(is_builtin)、module_frames/detection_profiles(scope=SYSTEM) |
✅ 系統範本全租戶可讀 | policy 現成 |
| 租戶級:surveys/survey_folders | ⚠️ 沒有平台範本旗標,租戶 1 的 8 份問卷子租戶看不到 | 與 flow_templates 不一致,要決策者裁要不要加 scope |
| 專案級:compliance.projects | ❌ policy 4 條寫好但 RLS 被 DISABLE | 6/25 2026-06-25-align-poc-to-stg-... 第 124 行,標 envs=poc,理由只寫「以 STG 為主」 |
| 專案級:compliance.job_executions | ❌ 有 tenant_id、零 policy | 11,065 列 |
| 專案級:compliance.workflow_executions | ❌ 只有 3 條 policy(缺 SELECT)、RLS 關 | 11,016 列 |
| 其餘有 tenant_id 但 RLS 沒生效的表 | ❌ workflow_templates/information_systems/poams/evidence_classification_*/user_roles/user_tenants/tenant_drive_integrations/log_forwarding_settings/framework_parse_jobs | 共 13 張,見下方 SQL |
**三支 view 沒開 security_invoker |
❌ PG16 預設用 owner(cmmgr,superuser)查底層,整個繞過 RLS** | vw_user_job_queue(待辦列表)、v_user_capabilities、v_user_routes/v_role_routes |
任務詳細 API GET /grc/project/<project_uid>/job/<job_uid> |
❌ 收 project_uid 不驗,只用 job_uid | 真 uid/全零 uuid/garbage 三種都 200 且回應 md5 相同 |
實證 SQL(cm_app 帳號、不設 super_admin):
set app.is_super_admin='f'; set app.user_id='17'; set app.allowed_tenant_paths='/1/999/'; -- 不存在的租戶
select count(*) from public.vw_user_job_queue where user_id=17; -- 39(應為 0)
select count(*) from compliance.projects; -- 213(應為 0)列出全部缺口的 SQL:
select n.nspname||'.'||c.relname, c.relrowsecurity, (select count(*) from pg_policy p where p.polrelid=c.oid)
from pg_class c join pg_namespace n on n.oid=c.relnamespace
where c.relkind='r' and n.nspname in ('public','compliance','survey','config','asset','oscal')
and exists (select 1 from pg_attribute a where a.attrelid=c.oid and a.attname='tenant_id' and not a.attisdropped)
and not c.relrowsecurity order by 1;
select c.relname, c.reloptions from pg_class c where c.relkind='v' and pg_get_userbyid(c.relowner)='cmmgr';為什麼今天才發現:以前沒人切過租戶——切租戶要先被指派成別租戶的角色,而那個功能在 CM-1661 修好前根本不能用。修好一個洞,露出後面一個更大的。跨租戶指派 STG/POC 目前 0 筆,客戶端還沒炸。
修法方向(決策者已定語意,工量估一支 migration + 一輪驗證,不是重新設計):
projects/workflow_templates/tenant_drive_integrations:policy 現成,ENABLE ROW LEVEL SECURITY 即可workflow_executions:補 SELECT policy 再開job_executions/information_systems/poams/user_roles/user_tenants/其餘:照 RLS_DESIGN.md 標準模式各補 4 條ALTER VIEW ... SET (security_invoker = on)scope=SYSTEM 旗標比照 flow_templates——決策者裁session_scope else 段放行,不會斷建議:先派一棒掃描卡(只盤不修)把 13 張表+3 view+問卷旗標逐項對照上表三層模型,列「該是哪層/現在是哪層/差什麼/誰在讀」,再開修正卡。決策者提過「當初設計時合規資源庫有踩過雷」,掃描時把 docs/changelog/2026-06-29-feat-tenant-scope-data-model-b2.md 與 2026-06-30-feat-compliance-framework-platform-write.md 讀進去,那是 6/29 定的三層模型原文。
| 卡 | 白話 | BE | 套件 |
|---|---|---|---|
| CM-1655 | 出貨安裝包缺六項結構(含一項會讓已發照客戶寫入全 500);補進基線+守門 | 1fed71ac |
— |
| CM-1656 | 主專案直接讀被第 6 棒拆掉的問卷 ORM 屬性,儲存整筆回滾 | 0f56491b |
— |
| CM-1657 | 補值覆蓋率盤點:8 處拔關聯、0 條正在空白、9 種潛伏缺口;根因是三個補值檔覆寫 6/4/2 條而基底有 7 條 | f2ed9633 |
— |
| CM-1658 | 檢測任務在待辦列表顯示成「一般」(第 7 棒回歸)+ 開失效問卷 500→404 | e740ee1e |
879473e |
| CM-1659 | 補值守衛(漏補值會叫)+三個 mixin 補到 7 條 | e8e44c64 |
3d60145 |
| CM-1660 | 填答頁補「這份問卷屬於誰」資訊區(FE,已直接進 FR-075 40291d4) |
7d14a901(patch 留檔) |
— |
| CM-1661 | 切租戶後權限全空:C(users RLS 加本人 SELECT 例外)+A(兩支權限查詢不再 join users) | 7cf63e08(reword 自 98e2122c) |
da25a8d |
CM-1661 動了 public.users 的 SELECT policy:只放寬看、只放寬本人一列、不放寬改;migration 2026-09-11-cm1661-users-rls-self-visible.sql 已進基線,STG/POC 未套。FR-075 掃描時請知悉。
兩顆 reword:兩個 runner 共用 worktree 撞出一顆訊息對不上的 commit,合併前已 reword(98e2122c→7cf63e08、空 commit acde6b7c 已併入移除),tree 一字未動。教訓:並行派工要在 prompt 加「commit 用 git commit -- <檔名> 限定路徑」。
FR-075 只接一件:§二租戶隔離破洞(13 張表 RLS+3 支 view+問卷平台旗標+任務詳細不驗 project_uid),開在資安總表底下與 FR-086 B1 併看。
下列七項由 FR-080 首腦做,FR-075 不碰;順序是 CM-1662 arc review 先跑完、Critical 修完,才發版:
envs=dev 一起審(CM-1655 已把六支改 *,M3 那條 cm1624 在其中;孤兒數三環境已查 0)-fr080 monorepo)my-tasks-detection.steps.js:323 改斷言git worktree remove 兩個 -fr080(BE、套件),拆之前先把 pyproject override 改指回原資料夾 monorepo(兩邊現在同 commit)writing-feature-specs)、母卡 CM-1619 改 Done、design.md 狀態改「已落地」、記憶同步 docs/claude/memory/docs/review/2026-09-11-fr080-arc-review.md| 項目 | 值 |
|---|---|
| BE 8000 / SocketIO 8002 | 從原資料夾 compliance-manager-be(FR-075,含合併)起;.env 已補 PORT=8000 |
| venv | 原資料夾 venv 已 poetry install,14 支 editable 指向 jedi-python-package-fr080;六支舊殼 wheel 已 uninstall(留著會與新套件重複宣告表,SQLAlchemy 炸) |
| 套件 monorepo | 原資料夾與 -fr080 同 commit da25a8d;原資料夾根目錄多六個 untracked 舊套件目錄(dist/coverage 殘留,git 不追蹤,可刪) |
| DEV DB | CM-1655 六支+CM-1661 一支已套;出貨基線庫同;STG/POC 未動 |
| 123 的 agent | 已從 STG re-enroll 到 DEV(10.8.0.10:8000),STG 那列變死資料要手動撤銷;還原 re-enroll --endpoint https://192.168.50.188 |
| 備份 tag | backup/FR-075-pre-merge-fr080(BE 86af8892、套件 8aa6f06)、backup/FR-080-pre-reword(3cce33d6) |
| 未 push | BE FR-075 領先 origin 20 顆、套件 FR-075 領先 34 顆、FE FR-075 領先 1 顆 |
28cf59fd;FR-080 branch 與 worktree 留著等拆)