Skip to content

[#5852 契约半边] HierarchyScopeContext 未声明 organizationId / tenantId 哪个权威 —— producer 只填一个、consumer 只读另一个,两边都「符合契约」 #5858

Closed

Description

@os-zhuang

Part of #5852(contract-first 拆分第一棒,由分诊座位拆)。本单只做 spec 契约面;producer 填充与断言在 #5852 的 identity 半边,cloud consumer 同步在 objectstack-ai/cloud 的对应单。

事实(已核 origin/main)

packages/spec/src/contracts/sharing-service.ts:396:

export interface HierarchyScopeContext {
  userId: string;
  organizationId?: string | null;
  tenantId?: string | null;
}

两个字段都是 optional、都可为 null,doc 没有任何一句说哪一个承载「调用方的活动组织」。于是:

  • producer(packages/plugins/plugin-sharing/src/sharing-service.ts:875-880)照抄 ExecutionContext,实测填出 { organizationId: null, tenantId: "<活动组织>" } —— 框架的 ExecutionContextLike { userId, tenantId, timezone } 本来就以 tenantId 承载活动组织,plugin-security 的 RLS 也是从 ExecutionContext.tenantId 取 current_user.organization_id;
  • consumer(cloud packages/security-enterprise/src/hierarchy/resolver.ts)只读 context.organizationId,拿到 null 就把自己文档里写明的 "belt-and-braces 租户隔离" 整条跳过。

两边各自符合这份契约,合起来是一个实测可达的跨组织越权(#5852 有 201/403 对照实测)。含糊的是契约本身,不是任何一侧的实现。

完成范围(本单)

  1. 在 HierarchyScopeContext 上明确单一权威字段并写进 doc 注释 —— 依据是运行时事实:框架里真实承载活动组织的是 tenantId;
  2. 另一个字段保留为 deprecated 别名并在 doc 注释里写明「resolver 不得单独依赖它」。⛔ 不在本单删除 organizationId —— 它在 api-surface.json:3597 的公开面上,删除走 ADR-0049 enforce-or-remove / ADR-0087 退役单独立单裁决,不做 rider;
  3. IHierarchyScopeResolver.resolveOwnerIds 的 doc 补一句实现方义务:权威字段为空时必须 fail-closed,⛔ 不得静默按「无租户约束」构建 owner set —— 这正是本次越权的形状;
  4. 按仓内惯例更新生成物 / api-surface 基线。

为什么修在契约而不是在 consumer 加 ?? tenantId

#5852 已论证:consumer 兜底是宽容消费者模式 —— 契约仍然含糊,下一个 resolver 实现还会踩同一个坑,而这一类失效是静默的(隔离不生效不报错,只是多返回了别的组织的 owner id)。

解锁关系

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:specDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loop

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions