Repository navigation
Description
来源:#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 只留两个字段,然后被交给三个裁决方法:
:205svc.createLink(..., callerCtx):228svc.listLinks(..., callerCtx):244svc.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 组装本身是完整的,是在消费点又裁了一刀,属于第四类站点。
方向(实读消费方,本单未跑复现)
裁掉的字段中至少两类有已知消费者:
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 面裁得更狠,方向应当相同。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 席分诊。
Activity
os-zhuang commentedon Aug 8, 2026
Triage:
pm:queue+domain:cli+target:v17.packages/runtime/src/domains/share-links.ts(stop rebuildingcallerCtx; pass the full resolved envelope at the three call sites), andruntimebelongs todomain:cliin the domain table — the hook 的condition求不出值时:全局 fail loud —— 抛错并中断该次操作(方案 B 已拍板;Blocked-by #4770) #4775 shape. The identity lane's 同族第三处组装:share-link 路由把授权信封裁成 4 个字段后直接当 enforcement context 喂给 engine.find ——group租户姿态下 Layer 0 墙恒判否 #6206 half stays where it is; this card does not touch plugin-sharing.origin/main@f549a0d:share-links.ts:78builds the two-fieldcallerCtx; consumed at:217/:237/:244; the 401 check readscallerCtx.userIdat:199. (Body cites :205/:228 — line drift, same code.) The ruled upstream contract is feat(spec): share-link enforcement 路径改收完整 ExecutionContext,窄类型只服务路由 401 (#6430) #6511's "MUST NOT rebuild a subset", and the spec contract test's final "legal but unwanted" case pins exactly this shape, as the body states.group租户姿态下 Layer 0 墙恒判否 #6206's whole-envelope transplant) ⇒ queue. Note for the dev: thepositions/permissionslimb is unreproduced per the body — reproduce before claiming that half's severity; theaccessible_org_idslimb is proven in-family.group租户姿态下 Layer 0 墙恒判否 #6206 (plugin-sharing route half, dispatched, different file — no collision), finding: ExecutionContext 在 dispatcher / REST / share-link 三处独立组装 —— 收敛为单一共享装配函数前,先裁决匿名面分歧 #6216 (three assembly sites), finding:SharingExecutionContext是同族第四个窄 enforcement 契约类型(sharing / approval / report 三个服务共用),#6206 裁决的「不留 per-site 子集」默认尚未覆盖它 #6523 (narrow contract type) — none covers this consumption-site truncation.target:v17grounds ①: same mechanism 同族第三处组装:share-link 路由把授权信封裁成 4 个字段后直接当 enforcement context 喂给 engine.find ——group租户姿态下 Layer 0 墙恒判否 #6206 already reproduced (missingaccessible_org_ids⇒ Layer 0 tenant wall fails closed ⇒ 403 on readable records undergroupposture), on the dispatcher face that is the design-primary share-link surface for cloud per-environment kernels. Maintainer may strike.本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-project-manager commentedon Aug 8, 2026
认领:dev agent session
session_017uFVNMmTxLpmfQYiuKM1Yx,分支claude/issue-6551-sharelinks-full-envelope。实施面仅
packages/runtime/src/domains/share-links.ts(dispatcher 面整体透传ec),复现按 #6206 的 tenant-wall 形状打 dispatcher 入口;positions/permissions半边先尝试复现、如实上报。Generated by Claude Code
os-project-manager commentedon Aug 8, 2026
续接:同一 session(
session_017uFVNMmTxLpmfQYiuKM1Yx)的重派发续跑 —— 前一个 dev 实例在实施前因 API 限额中断,未写任何代码。分支不变:claude/issue-6551-sharelinks-full-envelope,现在开始实施。Generated by Claude Code
feat(spec): export SEED_WRITE_EXECUTION_CONTEXT and bind all three se…
docs(service-messaging): re-anchor the dead tracker citations to the …
docs(core): re-anchor the dead tracker citations to the commits and A…