Skip to content

tracking(authz): 双轨赛道下的授权改进开发任务 v2(内核链 ADR 待编号 + 补齐轨 + 地基) #2920

Description

@os-zhuang

背景:双轨赛道决策

授权系统竞争力赛道已拍板 = 双轨:主轨打「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)

  1. 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,评审中)。起草过程中发现新证据 W1compileFilter 把含 tenant_isolation 在内的全部适用策略 OR 合并rls-compiler.ts),与 ADR-0066 文档的「tenant-global AND 在上」语义存在分歧——一条宽松业务 RLS 策略在 RLS 层足以放行跨租户行(是否实际暴露取决于 driver 层 applyTenantScope 半缝是否兜住)。这使 B1 同时是「修复文档与实现的语义分歧」,ADR-0095 已把该修复列为行为保持工作中唯一的、显式声明的行为变更(安全修复)。
  2. B5 已否决(maintainer 决策,2026-07-14):PG 原生 RLS 兜底不做,理由记入 ADR-0095 Alternatives(cloud 拓扑已物理隔离;唯一受益方是 EE shared-DB 模式,代价是 PG-only 防线破坏可移植性 + GUC/连接池风险 + 测试矩阵翻倍)。仅当 shared-DB SaaS 形态成为一等产品时重启。
  3. 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. 地基层(独立并行)

  • A3 — 用户页一站式分配入口(剩余部分)

    • 现状:Positions tab 已落地packages/platform-objects/src/pages/sys-user.page.ts L141-177,ADR-0090 D3,即目标 record:related_list + add.picker 模式本身)。
    • 剩余:照抄该模式补 Permission Sets(直接授权,junction sys_user_permission_set,picker 对象 sys_permission_set)+ Business Units(junction sys_business_unit_member,picker 对象 sys_business_unit)两个 tab。两 junction 对象定义均已存在(plugin-security / platform-objects/identity)。
    • objectui:零改动plugin-detail/src/RelatedList.tsx 的 add.picker 与 name-keyed junction 已完整支持)。
    • 判据:管理员在单个用户页完成岗位/权限集/BU 三类分配;直授路径须过 delegated-admin gate(浏览器 dogfood 验证被拦/放行两侧)。
    • 估:1–2 PD
  • 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 缺列)。
    • 内容:(1) 统一三对象 managed_by 取值词表与字段类型(以 sys_capability 的 select 三态为准,migration/兼容映射 user→admin、system/config→platform/package 需在实现时确认历史数据);(2) sys_position listView 补列;(3) objectui 二态徽标扩三态(PermissionMatrixEditor.tsx L529-538 现仅 Package/Custom)+ i18n key(metadata-admin/i18n.ts)。
    • 注意:Studio AccessPillar 按 provenance 过滤掉 platform 默认集(StudioDesignSurface.tsx L2979-2986),三态徽标落 Setup 记录页链路而非 Studio 矩阵。
    • 判据:管理员一眼分清「平台发的 / 应用发的 / 自己建的」(与 feat(plugin-security): 内置行写护栏 — sys_position / sys_capability 平台/应用托管行可被删改 #2918 互补);三对象词表一致。
    • 估:2–3 PD
  • A5 — 包级 capability 声明 API(原「声明链打通」重写)

    • 现状更正:capability 单一真源已成熟(packages/spec/src/security/capabilities.ts + bootstrap-system-capabilities.ts 从 permission set 的 systemPermissions 自动派生 seed);不存在「应用声明又复制进 spec」的重复,契约名是 requiredPermissions/systemPermissions(无 inputs)。
    • 重写后的目标:给一个正式的 capability 声明入口(如 defineCapability),使应用/包自带的 capability 带 managed_by:'package' + package_id provenance 流入 registry,而非依赖「从 systemPermissions 隐式派生」;配套文档明确「capability ≠ contract,资源用 requiredPermissions 引用、包用声明 API 定义」。呼应 ADR-0094 D5 的「managed_by:'user' 类逐步退役」方向。
    • 判据:示例应用演示包级声明→boot seed→sys_capability 带包 provenance 全链;文档/skill 更新。
    • 估:2–4 PD

B. 主轨 · 内核链(严格串行,ADR-0095)

高 blast-radius,动的是授权热路径。每步落在 role × object × expected-visible-rows 矩阵快照门后推进。矩阵雏形在 packages/dogfood/test/authz-conformance.matrix.ts(集成层)——B1 动手前先把矩阵门下沉/复制到单元层plugin-security 测试内)。行为契约与 W1 例外见 ADR-0095。

  • B0 — 内核链 ADR 成文ADR-0095docs/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-0093 multi shared-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.ts computeRlsFilter(posture-gated bypass 是唯一短路点,一个 bit 同时短路两层 = W2)+ objects/default-permission-sets.tstenant_isolation 通配策略,Layer 0 落地后从 seed 退役)+ packages/core/src/security/resolve-authz-context.ts
    • 内容:专属 tenant-layer 模块,消费 ADR-0093 tenancy service;multi 模式对租户对象无条件 AND organization_id == ctx.organization_id,始终在先、与业务 RLS 分离代码路径;豁免规则按 ADR-0095 D1(PLATFORM_ADMIN posture × 对象 posture 允许)。
    • 判据:矩阵快照门锁行为;唯一允许的 delta 是 W1 修复(宽松业务策略 × 异租户行 → 不可见),作为显式安全修复带专属矩阵行。
    • 估:8–13 PD。依赖 B0 合并。
  • B2 — posture 阶梯(ADR-0095 D2,含 EXTERNAL 档位预留)

    • 落点:packages/core/src/security/resolve-authz-context.ts
    • 内容:单调 enum 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 有枚举级语义锁测试。
    • 估:8–13 PD。依赖 B1。
  • B4 — posture 从 capability 派生(ADR-0095 D3)

  • B5 — Postgres 原生 RLS backstop已否决(v2.1 修订说明第 2 条;理由见 ADR-0095 Alternatives)。


C. 补齐轨 · 企业能力(只挑 2 项)

  • C1 — 层级 RLS 企业包打磨到 GA ⭐ 杠杆最高

    • 仓库已接入(v2.1)。先复核现状声明:HierarchyScopeResolvercloud/packages/security-enterprise hierarchy/resolver.ts)+ plugin 注册 + orphan-guard 回归门已落地、conformance 8/8 绿。
    • 补:子树/汇报链缓存(避免每次 BFS)、面向客户的文档license/entitlement 门(接 security-enterprise/src/license/gate.ts)、定价包装。
    • 估:5–8 PD(复核后修正)。
  • C2 — 记录级共享 debugger(双端,契约先行)

    • 现状:前后端均为 object+operation 级、无 record 概念——framework explain-engine.ts(564 行,签名 explain(principal, object, operation),explained-by-construction 复用执行链);objectui AccessExplainPanel.tsx(九层评估流水线 + readFilter,请求体无 recordId)。是真实新工作,不是复用打磨。
    • C2-α(契约,可立即做)spec/src/security/explain.zod.ts 扩展 record 粒度入参/出参(recordId? + 行级 sharing/RLS 命中归因)。
    • C2-β(双端实现):framework explain 引擎按行评估(命中哪条共享规则/哪层过滤)+ objectui 面板加记录选择器与逐层展开:权限集 → 岗位 → 共享 → 行规则 → 有效行过滤。喂养主轨「可解释授权」叙事。
    • 估:8–13 PD(偏紧,双端并行可压日历)。

执行须知(踩过的坑 / 约束)

  1. 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。
  2. 双轨约束:层级 RLS 留企业侧(C1),别放进开源;PSG 聚合层、合规认证不在本轮排期
  3. B 组矩阵门:B 组是行为保持的分层加固,不是改「谁能看什么」;除 ADR-0095 声明的 W1 修复外,矩阵快照暴露的任何 delta 是 bug 不是 feature。先把矩阵门下沉到单元层再动 B1
  4. ObjectQL 键是 where 不是 filterfindOne/find 的过滤键写错会被静默忽略(历史上锁错 admin,dogfood 才抓到)。
  5. 谓词裸字段会 fail-closed 静默隐藏按钮/行:写 visible/RLS 谓词先查 objectstack-ui / objectstack-formula skill,os build 现会拦裸字段。
  6. 验证:改动要浏览器 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 评估评论

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions