Skip to content

dispatcher 面的 /share-links 把已解析完整的 ExecutionContext 重新裁成两个字段再喂给 enforcement —— 与 #6206 同一条 enforcement 路径的另一张脸 #6551

Description

@baozhoutao

来源:#6206 消费半边(PR 见下)实施时,遍历 IShareLinkService 调用方做消费半径核对时的越界发现。未评级 —— 交分诊,下面只给实读到的事实。

事实(已核 origin/main 3510e4a25)

packages/runtime/src/domains/share-links.ts:77-78:

const ec: any = context.executionContext;
const callerCtx = { userId: ec?.userId as string | undefined, tenantId: ec?.tenantId as string | undefined };

ec 是 dispatcher 已经解析好的完整信封(packages/runtime/src/security/resolve-execution-context.ts 组装,含 positions / permissions / systemPermissions / org_user_ids / accessible_org_ids / posture / tabPermissions)。callerCtx 只留两个字段,然后被交给三个裁决方法:

  • :205 svc.createLink(..., callerCtx)
  • :228 svc.listLinks(..., callerCtx)
  • :244 svc.revokeLink(..., callerCtx)

#6511(d7e0b4212)落地的契约,这三个方法的 context 形参已经是完整 ExecutionContext,并在 TSDoc 里写明「调用方 MUST NOT rebuild a subset of it」。结构化子类型让这个两字段对象照样编译通过(契约测试 packages/spec/src/contracts/share-link-service.test.ts 的最后一例已把「合法但不想要」这一点如实钉住),所以 tsc 不会报。

#6206 的关系:同一条 enforcement 路径,另一张脸

#6206 修的是 plugin-sharing 自己挂的 HTTP 路由(registerShareLinkRoutes)。本单是同一个 service 的另一个入口 —— dispatcher domain,cloud 每环境 kernel 的设计主面(registerShareLinkRoutes: false 时它是唯一的面,见 share-link-routes.ts 模块头)。两处互不覆盖:#6206 的 PR 只动 plugin-sharing。

也不同于 #6216:那单说的是「ExecutionContext 有三处组装」;这里的 dispatcher 组装本身是完整的,是在消费点又裁了一刀,属于第四类站点。

方向(实读消费方,本单未跑复现)

裁掉的字段中至少两类有已知消费者:

  1. accessible_org_ids —— group 姿态下就是 Layer 0 墙(plugin-security/src/tenant-layer.ts,缺席即 fail closed)。这正是 同族第三处组装:share-link 路由把授权信封裁成 4 个字段后直接当 enforcement context 喂给 engine.find —— group 租户姿态下 Layer 0 墙恒判否 #6206实测复现的那条:group 姿态下建链对可读记录返回 403(该 PR 的 packages/plugins/plugin-security/src/share-link-tenant-wall.test.ts 在恢复裁剪后复现 403 → 修后 201)。dispatcher 面裁得更狠,方向应当相同。
  2. positions / permissions —— 连这两个都没了,所以 Layer 1(business RLS / sharing)在这个面上是按「无任何 position、无任何 permission」评估的。也就是说即便 single 姿态,一条只能靠 position 绑定的 permission set 或 position 范围的共享才看得见的记录,在 dispatcher 面建链/列链时也可能判否 —— 这一点未复现,需要接手的人先跑复现再决定评级。

建议改法(与 #6206 同形)

callerCtx 不再重建,直接把 ec 整体传下去;路由自己的 401 判定读 ec?.userId 即可(第 199 行那句)。#6206 的 PR 在 plugin-sharing 侧用的就是这个形状({ ...authz, isSystem: false } 整体透传),可直接照搬。

查重

  • 全文检索 open issues:#6216(三处组装的收敛 finding)、#6206(plugin-sharing 面,已修)、#6523(SharingExecutionContext 窄契约类型)均不覆盖本处消费点裁剪,不是重复。

未指派、未标域 —— 由 triage 席分诊。

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions