Skip to content

[Decision] share-links mint authority: the owner of a record on an access: private object can never mint a share link — admit the share-manager (canManageShares) beside the visibility read? (amends ADR-0111 D8 rule 1) #21329

Description

@objectstack-fleet

Ruled: 5950188467 · letter A′ (new) · 2026-10-02T10:19Z

Decision card filed by the repo:cloud seat (repo:cloud#1, session session_01Wxo1xhh2bU66T73q23jzE4, R44), from objectstack-ai/cloud#2588's dev report (its seam_proposal). Measured over HTTP on cloud's hosted composition (cloud 8d93d295, objectstack pin 30c530e5). needs-user-decision, because every option amends ADR-0111 D8 rule 1, which is governed text.

The reading

  • The object: cloud's ai_conversations declares publicSharing (link_only / signed_in) and, since cloud#2585 (8d93d295), access: { default: 'private' }. Members do not read each other's conversations through the data API; the conversation routes serve the owner.
  • The owner, holding only member_default: POST /api/v1/share-links for their own conversation answers 403 PERMISSION_DENIED. The owner's route GET of the same conversation answers 200.
  • A non-owner member, the built-in read-only set and the no-bypass organization admin all get 403 (correct). admin_full_access gets 201, and an anonymous recipient resolves the link (200).
  • Why: ShareLinkService.createLink (packages/plugins/plugin-sharing/src/share-link-service.ts) requires the publicSharing opt-in AND an engine.find visibility read under the caller's context. That read is ADR-0111 D8 rule 1. On an owner-private object the owner's data-API read is refused by design, so the owner can never mint.
  • publicSharing.eligibility runs after that read.
  • canManageShares (D8 rule 2, packages/plugins/plugin-sharing/src/sharing-service.ts) is wired into revokeLink only. Measured: once owner_id carried the owner, canManageShares answered true, and POST still answered 403.
  • Unchanged at objectstack main 1caa6037.

Governing text: ADR-0111 (docs/adr/0111-record-share-management-authority-and-verb-boundary.md) D8: rule 1 (minting requires visibility) and rule 2 (the share-manager may revoke).

Options

  • A. The share-manager may mint: createLink admits visibility OR canManageShares(object, recordId, context), still behind the publicSharing opt-in. One union in createLink; no new API or spec key. The host's follow-up: cloud stamps owner_id equal to user_id on conversation writes, with a backfill.
  • B. A per-object mint-authority hook on IShareLinkService, registered by the owning plugin. Cloud registers its conversation owner rule. This is a new contract surface, and an authority the platform's explain path cannot see.
  • C. A declarable owner field in the spec, honoured by every owner consumer (canManageShares, own-scope row-level security, explain), plus A's union. It is the cleanest model, but a spec expansion across many consumers.

维护者速读 —— 私有对象上的记录,主人自己分享不了

一句话:AI 会话现在是「只有主人能看」的私有对象。但分享链接的规则要求「你得能通过数据接口读到这条记录」,主人恰恰被这条规则挡住了,所以普通成员连自己的会话都分享不出去(403)。

为什么要您拍:要改 ADR-0111 D8 第 1 条(铸造分享链接需要可见性),这是受管文本。

选项 做什么 客户可感知的后果
A 允许「分享管理者」铸造 「能读到」或「是这条记录的分享管理者(主人、全权修改者、层级上级)」两者满足其一即可铸造;撤销已经用的就是这个口径 主人能分享自己的会话,别人依旧不行;cloud 要给会话补 owner_id 并回填一次
B 每个对象自己注册一个钩子 由拥有该对象的插件自己判断谁能铸造 能用,但多一个框架契约面;以后每个私有对象都要各写一遍,平台的「解释谁有权」那条路也看不见它
C spec 里声明「主人字段」 所有判断主人的地方统一读这个字段,再加上 A 的并集 模型最干净,但要改 spec,牵动很多消费者

业务含义直译:A =「门卫认得房主」;B =「每栋楼自己雇门卫」;C =「先把房产证格式全国统一,再让门卫认」。

① 项目长远合理性:A。D8 已经把「分享管理者」定义为能撤销的人,让同一个人也能铸造,口径一致,权限判断仍在服务里一处、可解释。B 给每个私有对象开一个特例口子;C 是两年后的理想形态,但今天就要 spec 扩张。
② 实际业务拉动:已实测。普通成员在自己的会话上点「分享」直接 403,console 的分享对话框是真实的使用者。
③ 防 AI 犯错:A 不新增任何可声明或可注册的面,没有让 AI 写错的地方;B 新增一个契约面,C 新增一个 spec 键。
④ 创业阶段不扩散:A 是最小的框架改动,不加 API、不加 spec 键、不加门禁。

Prior rulings read: ADR-0111 D8(第 1 条可见性、第 2 条分享管理者可撤销);cloud#2585 的重定范围裁决(5944972219,把会话对象设为私有)。以 share link mint|createLink|canManageShares 检索 objectstack 的卡片:相关的都已关闭(#7861、#6649、#14637),没有一张裁过「主人铸造」。

推荐:A,回退 B。 自检行:只看①选 A;②③④ 是否翻转:否。置信缺口:owner_id 可以被重新指派(会话对象对管理员仍开放 update),所以 cloud 的跟进必须让 owner_id 与 user_id 保持一致,或者把会话路由改为按 owner_id 判断,不能让两者各走各的。

裁后执行段:

  • 裁 A ⇒ objectstack 的 services 车道:在 createLink 加入并集,同步改 ADR-0111 D8 第 1 条(受管 PR,由您亲手合并)。cloud 席随后接 objectstack-ai/cloud#2588 的跟进(owner_id 写入与回填、pin 前移、HTTP 端到端测试)。
  • 裁 B / C ⇒ 同一车道按选定形状实施;cloud 的跟进按形状调整。

列表那一半(普通成员列自己的链接也是 403)不需要裁决,已单独立为 #21328。

末句一问:A 分享管理者可铸造 / B 每对象钩子 / C spec 主人字段?


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdomain:servicespriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions