背景:双轨赛道决策
授权系统竞争力赛道已拍板 = 双轨 :主轨打「AI-native / 开源」叙事(结构化授权可 lint/explain/diff + 开源自托管 + 包 provenance),补齐轨只挑 2 项接近「能卖」的企业能力。据此重排开发任务,「层级 RLS 开源落地」删除 (留企业侧当卖点,IHierarchyScopeResolver 可插拔 seam 已就位、开源版 fail-closed 到 owner-only)、合规认证 / PSG 不排期 (按需触发 / 后置)。
已拆出的独立 issue:#2917 (管理员手册)、#2918 (行写护栏)。本 issue 汇总其余全部开发任务 ,交由接手 agent 执行。
修订说明
v2(2026-07-14) :原版经落点级核实后重写,核实证据见评估评论 。要点:「内核链 ADR-0094」引用失效(编号被占)改为新前置任务 B0;B1 落点更正(rls-engine.ts 不存在);原 B3 并入 B2;原 A5 前提不成立已重写;A3 已完成过半估算下调;「待核实 Q7」无出处移除。
v2.1(2026-07-14) :
B0 已落地 :ADR-0095 成文,PR docs(adr): ADR-0095 — authz kernel chain: tenant isolation as Layer 0, posture ladder, capability-derived posture (B0 of #2920) #2924 (draft,评审中)。起草过程中发现新证据 W1 :compileFilter 把含 tenant_isolation 在内的全部适用策略 OR 合并 (rls-compiler.ts),与 ADR-0066 文档的「tenant-global AND 在上」语义存在分歧 ——一条宽松业务 RLS 策略在 RLS 层足以放行跨租户行(是否实际暴露取决于 driver 层 applyTenantScope 半缝是否兜住)。这使 B1 同时是「修复文档与实现的语义分歧」,ADR-0095 已把该修复列为行为保持工作中唯一的、显式声明的行为变更(安全修复)。
B5 已否决 (maintainer 决策,2026-07-14):PG 原生 RLS 兜底不做 ,理由记入 ADR-0095 Alternatives(cloud 拓扑已物理隔离;唯一受益方是 EE shared-DB 模式,代价是 PG-only 防线破坏可移植性 + GUC/连接池风险 + 测试矩阵翻倍)。仅当 shared-DB SaaS 形态成为一等产品时重启。
C1 解锁 :cloud 仓库已接入本会话 scope,可以评估与执行。
依赖与执行顺序
立即并行开工 (不碰内核热路径):A3、A4、A5 + C2-α(explain 契约扩展)+ C1。
串行主线 (工程日历瓶颈):B0(评审中)→ B1 → B2 → B4。B1 动手前先把矩阵门下沉到单元层。
C2-β (双端实现):契约定稿后可与 B 后段并行。
估算:本 issue 剩余范围合计 ≈ 35–59 PD (B0 已出稿;B5 已否决;含 C1 5–8 PD 待复核)。B 组内核链是关键路径,加人压不动。
A. 地基层(独立并行)
B. 主轨 · 内核链(严格串行,ADR-0095)
高 blast-radius,动的是授权热路径 。每步落在 role × object × expected-visible-rows 矩阵快照门后推进。矩阵雏形在 packages/dogfood/test/authz-conformance.matrix.ts(集成层)——B1 动手前先把矩阵门下沉/复制到单元层 (plugin-security 测试内)。行为契约与 W1 例外见 ADR-0095。
C. 补齐轨 · 企业能力(只挑 2 项)
执行须知(踩过的坑 / 约束)
worktree-first(Prime Directive Migrate documentation site to Fumadocs with monorepo structure and shared content #11 ) :改文件前每仓开专属 worktree(framework / cloud / objectui 各自),别在共享 main checkout 上动手,会被并发 agent reset 抹掉。guard hook 会拦 Edit/Write。
双轨约束 :层级 RLS 留企业侧 (C1),别放进开源;PSG 聚合层、合规认证不在本轮排期 。
B 组矩阵门 :B 组是行为保持的分层加固,不是改「谁能看什么」;除 ADR-0095 声明的 W1 修复外,矩阵快照暴露的任何 delta 是 bug 不是 feature。先把矩阵门下沉到单元层再动 B1 。
ObjectQL 键是 where 不是 filter :findOne/find 的过滤键写错会被静默忽略(历史上锁错 admin,dogfood 才抓到)。
谓词裸字段会 fail-closed 静默隐藏按钮/行 :写 visible/RLS 谓词先查 objectstack-ui / objectstack-formula skill,os build 现会拦裸字段。
验证 :改动要浏览器 dogfood 实测 + 截图,别只读代码推断(尤其 A3/A4/C2 的 UI)。
关联
#2917 · #2918 · epic #2776 (Permission Model v2 parking lot)· #2909 (两存储类型审计)· ADR-0095 / PR #2924 (B0)· ADR-0066 / 0073 / 0090 / 0093 / 0094 · v1→v2 评估评论
背景:双轨赛道决策
授权系统竞争力赛道已拍板 = 双轨:主轨打「AI-native / 开源」叙事(结构化授权可 lint/explain/diff + 开源自托管 + 包 provenance),补齐轨只挑 2 项接近「能卖」的企业能力。据此重排开发任务,「层级 RLS 开源落地」删除(留企业侧当卖点,
IHierarchyScopeResolver可插拔 seam 已就位、开源版 fail-closed 到 owner-only)、合规认证 / PSG 不排期(按需触发 / 后置)。已拆出的独立 issue:#2917(管理员手册)、#2918(行写护栏)。本 issue 汇总其余全部开发任务,交由接手 agent 执行。
修订说明
v2(2026-07-14):原版经落点级核实后重写,核实证据见评估评论。要点:「内核链 ADR-0094」引用失效(编号被占)改为新前置任务 B0;B1 落点更正(
rls-engine.ts不存在);原 B3 并入 B2;原 A5 前提不成立已重写;A3 已完成过半估算下调;「待核实 Q7」无出处移除。v2.1(2026-07-14):
compileFilter把含tenant_isolation在内的全部适用策略 OR 合并(rls-compiler.ts),与 ADR-0066 文档的「tenant-global AND 在上」语义存在分歧——一条宽松业务 RLS 策略在 RLS 层足以放行跨租户行(是否实际暴露取决于 driver 层applyTenantScope半缝是否兜住)。这使 B1 同时是「修复文档与实现的语义分歧」,ADR-0095 已把该修复列为行为保持工作中唯一的、显式声明的行为变更(安全修复)。依赖与执行顺序
B0(评审中)→ B1 → B2 → B4。B1 动手前先把矩阵门下沉到单元层。估算:本 issue 剩余范围合计 ≈ 35–59 PD(B0 已出稿;B5 已否决;含 C1 5–8 PD 待复核)。B 组内核链是关键路径,加人压不动。
A. 地基层(独立并行)
A3 — 用户页一站式分配入口(剩余部分)
packages/platform-objects/src/pages/sys-user.page.tsL141-177,ADR-0090 D3,即目标record:related_list+add.picker模式本身)。sys_user_permission_set,picker 对象sys_permission_set)+ Business Units(junctionsys_business_unit_member,picker 对象sys_business_unit)两个 tab。两 junction 对象定义均已存在(plugin-security / platform-objects/identity)。plugin-detail/src/RelatedList.tsx的 add.picker 与 name-keyed junction 已完整支持)。A4 — 权限来源三态统一 + 露出(platform / package / admin)
sys_capability= platform/package/admin(select,listView 已有列);sys_permission_set= platform/package/user(text,列已有);sys_position= system/config/user(text,listView 缺列)。managed_by取值词表与字段类型(以sys_capability的 select 三态为准,migration/兼容映射 user→admin、system/config→platform/package 需在实现时确认历史数据);(2)sys_positionlistView 补列;(3) objectui 二态徽标扩三态(PermissionMatrixEditor.tsxL529-538 现仅 Package/Custom)+ i18n key(metadata-admin/i18n.ts)。StudioDesignSurface.tsxL2979-2986),三态徽标落 Setup 记录页链路而非 Studio 矩阵。A5 — 包级 capability 声明 API(原「声明链打通」重写)
packages/spec/src/security/capabilities.ts+bootstrap-system-capabilities.ts从 permission set 的systemPermissions自动派生 seed);不存在「应用声明又复制进 spec」的重复,契约名是requiredPermissions/systemPermissions(无inputs)。defineCapability),使应用/包自带的 capability 带managed_by:'package'+package_idprovenance 流入 registry,而非依赖「从 systemPermissions 隐式派生」;配套文档明确「capability ≠ contract,资源用requiredPermissions引用、包用声明 API 定义」。呼应 ADR-0094 D5 的「managed_by:'user'类逐步退役」方向。sys_capability带包 provenance 全链;文档/skill 更新。B. 主轨 · 内核链(严格串行,ADR-0095)
B0 — 内核链 ADR 成文 → ADR-0095(
docs/adr/0095-authz-kernel-tenant-layer-and-posture-ladder.md),PR docs(adr): ADR-0095 — authz kernel chain: tenant isolation as Layer 0, posture ladder, capability-derived posture (B0 of #2920) #2924 评审中。回答了拓扑问题(Layer 0 的承重场景 = ADR-0093multishared-DB 模式;ADR-0073 的「跨租户 RLS 不存在」声明限定于物理拓扑);否决 PG 兜底;记录 W1 分歧。B1 — 拆租户隔离为 Layer 0(ADR-0095 D1)
packages/plugins/plugin-security/src/rls-compiler.ts(租户过滤与业务 RLS 现为同一 pass、OR 合并 = W1)+security-plugin.tscomputeRlsFilter(posture-gated bypass 是唯一短路点,一个 bit 同时短路两层 = W2)+objects/default-permission-sets.ts(tenant_isolation通配策略,Layer 0 落地后从 seed 退役)+packages/core/src/security/resolve-authz-context.ts。tenancyservice;multi 模式对租户对象无条件 ANDorganization_id == ctx.organization_id,始终在先、与业务 RLS 分离代码路径;豁免规则按 ADR-0095 D1(PLATFORM_ADMIN posture × 对象 posture 允许)。B2 — posture 阶梯(ADR-0095 D2,含 EXTERNAL 档位预留)
packages/core/src/security/resolve-authz-context.ts。PLATFORM_ADMIN > TENANT_ADMIN > MEMBER > EXTERNAL,每档恰好一条注入规则、严格嵌套(rung n 可见集 ⊇ rung n-1,作为被测不变量)。EXTERNAL 语义现在锁死(仅显式共享、永不 OWD、误配只能更少),实现等 portal/external 主体类型出现后另立 issue(对齐 ADR-0093 membership)。resolve-authz-context.test.ts升级为 role×object×expected-rows 矩阵快照 + 嵌套不变量断言;EXTERNAL 有枚举级语义锁测试。B4 — posture 从 capability 派生(ADR-0095 D3)
resolve-authz-context.ts+plugin-security/src/permission-evaluator.ts(hasSuperuserReadBypass/hasSuperuserWriteBypassL208-228 是现成派生范本)。role='admin'降为「授予 platform_admin 岗位的一个来源」(mapMembershipRole归一化转为授予侧关注点);enforcement 时任何路径不得直接查 better-auth role(消灭 ADR-0092 D4/D5: sys_user 编辑对"同时持有 organization_admin 的平台管理员"被权限合成挡住(explicit deny 胜 wildcard allow) #2836 类双轨合成冲突)。B5 — Postgres 原生 RLS backstop→ 已否决(v2.1 修订说明第 2 条;理由见 ADR-0095 Alternatives)。C. 补齐轨 · 企业能力(只挑 2 项)
C1 — 层级 RLS 企业包打磨到 GA ⭐ 杠杆最高
HierarchyScopeResolver(cloud/packages/security-enterprisehierarchy/resolver.ts)+ plugin 注册 + orphan-guard 回归门已落地、conformance 8/8 绿。security-enterprise/src/license/gate.ts)、定价包装。C2 — 记录级共享 debugger(双端,契约先行)
explain-engine.ts(564 行,签名explain(principal, object, operation),explained-by-construction 复用执行链);objectuiAccessExplainPanel.tsx(九层评估流水线 + readFilter,请求体无recordId)。是真实新工作,不是复用打磨。spec/src/security/explain.zod.ts扩展 record 粒度入参/出参(recordId?+ 行级 sharing/RLS 命中归因)。执行须知(踩过的坑 / 约束)
framework/cloud/objectui各自),别在共享 main checkout 上动手,会被并发 agent reset 抹掉。guard hook 会拦 Edit/Write。where不是filter:findOne/find的过滤键写错会被静默忽略(历史上锁错 admin,dogfood 才抓到)。objectstack-ui/objectstack-formulaskill,os build现会拦裸字段。关联
#2917 · #2918 · epic #2776(Permission Model v2 parking lot)· #2909(两存储类型审计)· ADR-0095 / PR #2924(B0)· ADR-0066 / 0073 / 0090 / 0093 / 0094 · v1→v2 评估评论