实施 #6430(#6206 裁决 A 案契约半边,PR #6511)时在 packages/spec/src/contracts/ 内读到的越界观察,未在该 PR 修复(裁决只覆盖 share-link)。
事实(已核 origin/main ecff95108)
packages/spec/src/contracts/sharing-service.ts:105 的 SharingExecutionContext 声明六个字段:
userId? / tenantId? / positions? / permissions? / systemPermissions? / isSystem?
缺席的、恰是 #6206 裁决点名的那几个:accessible_org_ids、org_user_ids、posture、tabPermissions。
它不止服务一个接口 —— 三个契约共用它作为 context 参数类型,而这三个的方法都在裁定访问:
sharing-service.ts ISharingService:buildReadFilter(:136)、canEdit(:157)等;
approval-service.ts:decide(:537)、recall(:549)、getRequest(:530)等 11 处;
report-service.ts:run(:120)、runAdHoc(:123)、getReport(:135)等 10 处。
与 #6430 的关系,以及为什么形状值得记一笔
#6430 刚把 share-link 的同类窄类型从 enforcement 路径上摘掉,理由是裁决写的「治理默认收敛到完整信封,不留 per-site 子集」。按这条默认,SharingExecutionContext 是同族第四个窄契约类型,而且是覆盖面最大的一个(三个服务、20+ 个方法签名)。
一个具体的形状后果:packages/plugins/plugin-sharing/src/sharing-plugin.ts:796 是 service.buildReadFilter(ctx.object, exec ?? {}) —— 传进去的 exec 是引擎侧的执行上下文,值是全的,但形参类型是窄的,于是实现方不加 as any 就读不到 accessible_org_ids / posture。这是 #6206 正文「declared narrow ≠ consumed narrow」的镜像方向:那边是值被裁了,这边是值全而类型窄。
⚠️ 未测:我没有跑复现,也没有判级
- 我只读了契约面与
buildReadFilter 的一处调用点,没有逐个走 approval / report 的消费方,也没有跑 group 姿态复现;
- 方向上它看起来是休眠的(Layer 0 租户墙由
plugin-security 另行读 context?.accessible_org_ids 强制,sharing-service 自己那套 posture 是部署侧 tenancy posture,不是 ExecutionContext.posture),所以按「今天用户不撞得到」挂 finding、不挂 pm:queue;
- 但严重性在两个方向上都不可靠(cloud#1004 的「转义细节」是 P0),所以照实填、交分诊评级,不由我判。
去重
已搜开放 issue:SharingExecutionContext 零命中;accessible_org_ids + enforcement 命中 #6206(share-link 那处,已裁决)、#6216(dispatcher / REST / share-link 三处装配点收敛,匿名面待裁)、#6430(本次契约半边)。本条既不在 #6206 的完成范围内(它是 share-link 站点),也不是 #6216 的装配点问题(这是契约类型面),故独立立卡而非挂子卡。
相关:#6206(裁决)、#6430 / PR #6511(share-link 契约半边)、#6216、#5997、#6071。
Generated by Claude Code
实施 #6430(#6206 裁决 A 案契约半边,PR #6511)时在
packages/spec/src/contracts/内读到的越界观察,未在该 PR 修复(裁决只覆盖 share-link)。事实(已核 origin/main
ecff95108)packages/spec/src/contracts/sharing-service.ts:105的SharingExecutionContext声明六个字段:缺席的、恰是 #6206 裁决点名的那几个:
accessible_org_ids、org_user_ids、posture、tabPermissions。它不止服务一个接口 —— 三个契约共用它作为 context 参数类型,而这三个的方法都在裁定访问:
sharing-service.tsISharingService:buildReadFilter(:136)、canEdit(:157)等;approval-service.ts:decide(:537)、recall(:549)、getRequest(:530)等 11 处;report-service.ts:run(:120)、runAdHoc(:123)、getReport(:135)等 10 处。与 #6430 的关系,以及为什么形状值得记一笔
#6430 刚把 share-link 的同类窄类型从 enforcement 路径上摘掉,理由是裁决写的「治理默认收敛到完整信封,不留 per-site 子集」。按这条默认,
SharingExecutionContext是同族第四个窄契约类型,而且是覆盖面最大的一个(三个服务、20+ 个方法签名)。一个具体的形状后果:
packages/plugins/plugin-sharing/src/sharing-plugin.ts:796是service.buildReadFilter(ctx.object, exec ?? {})—— 传进去的exec是引擎侧的执行上下文,值是全的,但形参类型是窄的,于是实现方不加as any就读不到accessible_org_ids/posture。这是 #6206 正文「declared narrow ≠ consumed narrow」的镜像方向:那边是值被裁了,这边是值全而类型窄。buildReadFilter的一处调用点,没有逐个走 approval / report 的消费方,也没有跑group姿态复现;plugin-security另行读context?.accessible_org_ids强制,sharing-service自己那套posture是部署侧 tenancy posture,不是ExecutionContext.posture),所以按「今天用户不撞得到」挂finding、不挂pm:queue;去重
已搜开放 issue:
SharingExecutionContext零命中;accessible_org_ids+ enforcement 命中 #6206(share-link 那处,已裁决)、#6216(dispatcher / REST / share-link 三处装配点收敛,匿名面待裁)、#6430(本次契约半边)。本条既不在 #6206 的完成范围内(它是 share-link 站点),也不是 #6216 的装配点问题(这是契约类型面),故独立立卡而非挂子卡。相关:#6206(裁决)、#6430 / PR #6511(share-link 契约半边)、#6216、#5997、#6071。
Generated by Claude Code