Skip to content

crypto.hash 能力声明了、构建期还会自动推断,但沙箱从没实现 —— 调用直接抛(declared ≠ enforced) #4391

Description

@os-zhuang

现象

crypto.hash 是一个声明了、推断了、类型也写了,但沙箱从没实现的能力。作者声明它、CLI 为它通过构建、然后调用在 VM 里直接抛。

defineHook({
  name: 'fingerprint_lead',
  object: 'crm_lead',
  events: ['beforeInsert'],
  body: {
    language: 'js',
    source: "ctx.input.fingerprint = await ctx.crypto.hash('sha256', ctx.input.email);",
    capabilities: ['crypto.hash'],   // 构建接受
  },
});

os build 通过,能力被授予,记录写入时 hook 抛错。

声明面(四层)

位置 状态
capability token packages/spec/src/data/hook-body.zod.ts:30'crypto.hash'HookBodyCapability 枚举里 ✅ 声明
文档 同文件 :19- `crypto.hash` — `ctx.crypto.hash(algo, data)` ✅ 声明
构建期推断 packages/cli/src/utils/extract-hook-body.ts:52{ rx: /ctx\.crypto\.hash\b/, cap: 'crypto.hash' },写了 ctx.crypto.hash 的 body 会自动拿到这个能力 ✅ 声明
运行时类型 packages/runtime/src/sandbox/script-runner.ts:117hash?: (algo, data) => Promise<string> ✅ 声明
沙箱实现 packages/runtime/src/sandbox/quickjs-runner.ts:607-618cryptoObj装了 randomUUID 没有

grep -n "crypto.hash" packages/runtime/src/sandbox/quickjs-runner.ts 无结果。

为什么值得单独记一笔

这是 Prime Directive #10 的正面违反,而且是比 declared ≠ enforced 更糟的一档:不只是"schema 说有、运行时不查",而是构建期主动帮作者把这个能力加上去(extractor 认 ctx.crypto.hash 这个模式),等于系统在鼓励作者走进一条死路。

唯一的记录是 content/docs/automation/hook-bodies.mdx 里一句 _(not yet wired)_ 的表格备注 —— 而 spec、extractor、类型三处都不带任何标记。搜遍 issue 库,这个缺口零跟踪

#4345 / #4271 / #4001 是同一族(声明的能力没有兑现),区别是这次连"静默"都算不上 —— 它会响亮地抛错,只是抛在运行时而不是作者时。

两条路,需要决策

A. 实现。installCtx 里装 ctx.crypto.hash,用 crypto.subtle.digest(WebCrypto,边缘运行时都有,符合"纯 JS、可跑边缘"的约束)。

  • ScriptContext.crypto.hash 的签名已经写好:(algo: string, data: string | Uint8Array) => Promise<string>
  • 需要走 installApiMethod 那套 deferred-promise 通道(它是 async)
  • 需要定 algo 白名单(sha-256 / sha-512?)和返回编码(hex?base64?)—— 签名说 Promise<string> 但没说哪种
  • 成本:中等,一个 host 函数 + 能力门 + 测试

B. 裁掉。HookBodyCapability 移除 'crypto.hash',删掉 extractor 那条模式和 ScriptContext.crypto.hash 类型。

  • 这是移除一个可授权的 spec key,要走 spec-property-retirement 那一整套(ADR-0049 enforce-or-remove):tombstone / UNKNOWN_KEY_GUIDANCE、带 FROM→TO 的 breaking changeset、生成物基线、liveness 台账处置
  • 已经声明它的 body 会在授权时被拒 —— 需要迁移话术

倾向 A:签名已定、边缘可用的实现就在 crypto.subtle 里,而且哈希对"指纹 / 幂等键 / 脱敏"这类 hook 是真实需求;B 要付的退役成本比实现还高。但这是产品决策,不是我该独断的。

附带

无论走哪条,hook-bodies.mdx 那句 _(not yet wired)_ 要一起改 —— 它现在是唯一诚实的地方,但也是唯一一处,作者不会先读文档表格再写 body。

参考

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions