Skip to content

沙箱两个写入方的 ?? …session?.user 兜底链是死支 —— 两种 session 形状都不声明也不生产 user 键(observation) #6316

Description

@qq9340100

Observation-class finding,来自 #5521 / PR #6295 的实施测量。今天没有用户会撞到,也不改变任何运行行为 —— 记录的是一处永远取不到值的兜底支(#4984 死肢家族),不是缺陷。

观察到的事实

packages/runtime/src/sandbox/body-runner.ts 的两个写入方各带一条两支的 ?? 链:

  • body-runner.ts:315 buildSandboxContext —— user: engineCtx?.user ?? engineCtx?.session?.user
  • body-runner.ts:340 buildActionSandboxContext —— user: actionCtx?.user ?? actionCtx?.session?.user

第二支在两处都不可达,因为这个接缝上出现的两种 session 形状都既不声明、也不生产 user 键:

session 类型 键集 唯一生产者 user
hook HookContext['session'] userId / actor / organizationId / accessToken / isSystem / skipTriggers / skipAutomations / positions / preserveAudit(+ roles 墓碑)—— packages/spec/src/data/hook.zod.ts:386-536 ObjectQLEngine.buildSession(),packages/objectql/src/engine.ts:1647-1690,逐字段构造
action ActionSession userId / organizationId / positions / roles(弃用别名)—— packages/spec/src/ui/action-params.zod.ts:237-336 buildActionSession(),packages/runtime/src/action-execution.ts:811-823,只写这四个键

两个写入方的形参都是 any,所以 tsc 从来没有、将来也不会对这条链说一句话。

为什么按 observation 归档而不是缺陷

  • 行为完全正确:第一支在两条真实路径上都取到值(hook 侧 HookContext['user'],action 侧 ActorUser),第二支只是永远返回 undefined 后被丢弃 —— 结果与没有它时一模一样;
  • 第三条调用路径 ScopedRepo.execute()(packages/objectql/src/engine.ts:7400-7407)传的 ctx 既无 user 也无 session,两支都取不到值,ctx.user 恒为 undefined —— 这也是正确的语义(该路径确实没有调用者身份);
  • 因此它是读起来像在兜底、实际上什么也没兜的代码。validateOrgAxisRedLines 读的 sharing-rule 键是 spec 拒收的:ADR-0105 D6 ① 在 criteria 路径上从不触发 #4984 记录的正是这种形状:一条 ?? 链只有最后一支可达,读者会误以为存在第二个数据来源。

#5521 的关系

#5521 / PR #6295ScriptContext.userunknown 收窄成 ScriptUser = ActorUser | HookContext['user'],过程中把这条链逐支测了一遍 —— 结论就是上表。那个 PR 刻意没有动它:本单授权是"给接缝钉类型",顺手删一个运行时表达式属于扩范围,且删除与保留是两种不同的判断,应当单独裁。测量结论已写进 ScriptUser 的 docblock,所以即使这条 finding 一直不处理,下一个读者也不会再被这条链误导。

可能的方向(未裁决)

  1. 删掉第二支,两处都只留 engineCtx?.user / actionCtx?.user —— 与 validateOrgAxisRedLines 读的 sharing-rule 键是 spec 拒收的:ADR-0105 D6 ① 在 criteria 路径上从不触发 #4984 的处置一致(死肢就是删);
  2. 保留但立即可证伪:若认为将来某个引擎可能在 session 上挂 user,那应当把它声明到相应的 session 契约里(HookContextSchema.session / ActionSessionSchema),而不是留一条没有契约支撑的消费者侧 ?? —— 后者正是 Prime Directive Add comprehensive test suite for Zod schema validation #12 点名的"消费者侧宽容"反模式;
  3. 维持现状,仅靠 ScriptUser docblock 里已写下的测量结论备案。

倾向 1:今天没有任何生产者写这个键,而"以防万一"的第二支恰恰是 #12 说的把错误约定固化成第二套事实上的契约。但这条链跨 hook / action 两个面,删除属于行为面判断,留给分诊裁。

⛔ 不认领,仅记录。会话:session_01Wbxm29qPKnLf44AbSxizqW

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions