Repository navigation
Description
问题
sys_sharing_rule.access_level / sys_record_share.access_level 提供三档:read / edit / full。spec 里 full 的注释写着 Full Access (Transfer, Share, Delete):
// packages/spec/src/security/sharing.zod.ts:42
'full' // Full Access (Transfer, Share, Delete)但没有任何一处代码因为 full 而授予删除、转移或再共享。它在实现中与 edit 完全等价。
管理员在 Setup 里选「完全访问」,合理地以为授予了删除权;实际什么都没多给,也没有任何提示。
代码证据
'full' 在 sharing / security / spec 三块出现的全部位置:
| 位置 | 性质 |
|---|---|
plugin-sharing/src/sharing-service.ts:223 |
access_level: { $in: ['edit', 'full'] } — 读路径 |
plugin-sharing/src/sharing-service.ts:278 |
access_level: { $in: ['edit', 'full'] } — canEdit 写门 |
plugin-sharing/src/objects/sys-record-share.object.ts:157 |
枚举声明 |
plugin-sharing/src/objects/sys-sharing-rule.object.ts:182 |
枚举声明 |
plugin-security/src/explain-engine.ts:196 |
类型声明 |
spec/src/security/explain.zod.ts:102 |
类型声明 |
spec/src/security/sharing.zod.ts:42 |
上面那条注释 |
只有前两处是真逻辑,且两处都把 full 和 edit 并列处理。
实测
showcase 上把一条共享规则的访问级别设为「完全访问」,以接收人身份问判定引擎:
read: allowed=true record.visible=true decidedBy=sharing
update: allowed=true record.visible=true decidedBy=sharing
delete: allowed=false record.visible=false decidedBy=object_crud
注意 decidedBy=object_crud:删除在轮到 sharing 层之前,就被对象级 CRBD 门拒了。也就是说即使补上 full 的判断,也绕不过这一层——这不是加个 if 能解决的,需要先定清楚 sharing 能否越过对象级 CRUD 授权。
UI 上的表现:接收人在「编辑」和「完全访问」两档下看到的界面完全一致(都有编辑按钮、都没有删除项)。
两条路
A. 实现它 — 让 full 真的授予删除 / 转移 / 再共享。需要先回答上面那个安全模型问题:行级共享能不能提供对象级 CRUD 没给的能力。属于功能设计,建议单独讨论。
B. 先把 full 从可选项里摘掉 — 同一个文件里就有先例:sys_sharing_rule.recipient_type 的 queue 正是因为「声明了但求值器不认,提供它等于让人写出一条静默失效的规则」而被移除(ADR-0078):
// packages/plugins/plugin-sharing/src/objects/sys-sharing-rule.object.ts
// `queue` was removed: it is declared-but-unenforced (the evaluator returns
// no users for it), so offering it would author a silently-inert rule
// (ADR-0078). The five values below are the ones the evaluator expands.full 处境完全相同。
个人倾向 B 先行、A 另议:当前状态的问题不是「缺一个功能」,而是界面在误导管理员——他以为授予了删除权。消除误导应当优先。摘除时需要考虑存量数据(已有 access_level='full' 的 sys_record_share / sys_sharing_rule 行)如何迁移,行为上它们本来就等同 edit。
关联
- 由 fix(sharing): 共享规则新建页 — 自定义 widget 未国际化,且「接收方」永远无可选项 #3821 的 UI 验证过程中发现(三档访问级别逐档实测时)
- 已在 fix(sharing,driver-sql): a rule authored in Setup actually applies — and switching it off actually withdraws access #3850 的 PR 描述中作为 "Known gap" 记录,未在该 PR 中修复
Activity
os-zhuang commentedon Jul 28, 2026
对标主流平台后的结论:
full不应作为共享档位开发,B 方案是终局而非止血先确认 issue 的每条代码证据都在当前 main 上核实无误:
'full'仅有的两处真实逻辑(sharing-service.ts:223的buildWriteFilter、:278的canEdit)都把它与edit并列,实现上逐字节等价。在动手前我对标了主流企业平台的共享模型,结论是没有一个主流平台让批量共享规则授予删除/转移权——摘掉
full之后剩下的 read/edit 两档,正好就是业界共享规则的标准形态。平台对照
Modify All持有者自动拥有,共享规则无法授出AccessRights是权限掩码且与安全角色 AND——角色里没有该表 Delete 特权,共享给了也删不了三条行业公理
decidedBy=object_crud先拒掉 delete,按业界模型这不是需要绕过的障碍,而是正确行为。真实业务诉求的正确接法
owner_id即可unit/unit_and_below)+ 对象级 delete 权限writeScope: org/ platform adminfull想解决的每个真实场景都已有更正确的通道——这也解释了它为什么一直没长出真逻辑:没有场景真正需要它。评估中的两个补充发现
1.
edit级共享目前已经允许删除(偏宽)。sharing-plugin.ts:505-506对update和delete走同一个canEdit门,而canEdit接受edit|full。Salesforce 的 Read-Write 共享是明确不能删除的。所以真要实现 Option A,第一步不是"给 full 加能力",而是先把删除从edit档收紧——破坏性行为变更,需要独立 ADR。2. 「再共享」的 enforcement 挂载点根本不存在。
POST /data/:object/:id/shares(rest-server.ts:5641)只做enforceAuth(登录态 + auth gate),随后直接以SYSTEM_CTX写入共享行,没有任何"调用者是否有权共享这条记录"的检查,revoke同样。这可能构成提权,将单独开 issue 核实,与本任务解耦。因此:B 方案升格为终局对齐
两档共享 + 层级深度 + 管理员范围就是业界成熟答案,
full不必回来。与 OWD 那次sharingModel: 'full'移除(ADR-0090 D4)不同的是,这次full→edit行为无损(两者本来就等价),所以可以走机械转换而非留给作者判断的语义 TODO,迁移故事更简单。实施要点(authoring 拒绝、runtime 容忍、数据归一,照搬 ADR-0090 D4 模式):
SharingLevel/ShareAccessLevel收窄为read | edit,附 ADR-0078 式摘除注释;explain.zod.ts的grants保留'full'(存量行的呈现面,backfill 前不应让报告构造抛错);新增机械 conversion 处理声明式 stack 里的存量规则。Field.select去掉'full'(Setup 下拉由元数据驱动,objectui 无需改动);grant()补上目前完全缺失的 accessLevel 校验——'full'归一为'edit',未知值抛VALIDATION_FAILED;读路径的$in: ['edit','full']保留作为漏网存量行的双保险;仿backfillRuleGrants(app-showcase 权限模型复测清单(07-15 对照 main 重评):1 项回归级重大缺陷(#2930 锚点写护栏被 A4 词表打穿)+ 2 项部分修复 + 3 项未修 + 1 项建议降级 + 2 项观察 #2926 ③)加幂等 boot backfill 归一存量数据。full存量行 boot 后显示为「编辑」且接收人行为不变。若将来确有 per-record 授删的硬需求,按 Dataverse 模式设计:权限掩码而非线性档位、与对象 CRUD 做 AND、先建共享管理权、同步收紧
edit——那是独立的 ADR 级项目,不应与"消除界面误导"的修复捆绑。现在按此方案开工。
Generated by Claude Code
fix(sharing)!: remove the `full` access level — it promised delete/tr…
fix(spec): the protocol 16 → 17 conversion summaries and three descri…