问题
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。
关联
问题
sys_sharing_rule.access_level/sys_record_share.access_level提供三档:read/edit/full。spec 里full的注释写着 Full Access (Transfer, Share, Delete):但没有任何一处代码因为
full而授予删除、转移或再共享。它在实现中与edit完全等价。管理员在 Setup 里选「完全访问」,合理地以为授予了删除权;实际什么都没多给,也没有任何提示。
代码证据
'full'在 sharing / security / spec 三块出现的全部位置:plugin-sharing/src/sharing-service.ts:223access_level: { $in: ['edit', 'full'] }— 读路径plugin-sharing/src/sharing-service.ts:278access_level: { $in: ['edit', 'full'] }—canEdit写门plugin-sharing/src/objects/sys-record-share.object.ts:157plugin-sharing/src/objects/sys-sharing-rule.object.ts:182plugin-security/src/explain-engine.ts:196spec/src/security/explain.zod.ts:102spec/src/security/sharing.zod.ts:42只有前两处是真逻辑,且两处都把
full和edit并列处理。实测
showcase 上把一条共享规则的访问级别设为「完全访问」,以接收人身份问判定引擎:
注意
decidedBy=object_crud:删除在轮到 sharing 层之前,就被对象级 CRBD 门拒了。也就是说即使补上full的判断,也绕不过这一层——这不是加个if能解决的,需要先定清楚 sharing 能否越过对象级 CRUD 授权。UI 上的表现:接收人在「编辑」和「完全访问」两档下看到的界面完全一致(都有编辑按钮、都没有删除项)。
两条路
A. 实现它 — 让
full真的授予删除 / 转移 / 再共享。需要先回答上面那个安全模型问题:行级共享能不能提供对象级 CRUD 没给的能力。属于功能设计,建议单独讨论。B. 先把
full从可选项里摘掉 — 同一个文件里就有先例:sys_sharing_rule.recipient_type的queue正是因为「声明了但求值器不认,提供它等于让人写出一条静默失效的规则」而被移除(ADR-0078):full处境完全相同。个人倾向 B 先行、A 另议:当前状态的问题不是「缺一个功能」,而是界面在误导管理员——他以为授予了删除权。消除误导应当优先。摘除时需要考虑存量数据(已有
access_level='full'的sys_record_share/sys_sharing_rule行)如何迁移,行为上它们本来就等同edit。关联