Skip to content

vama-write-path-convergence.test.ts 的 DELETE 用例喂的是引擎会拒绝的调用形状,安全侧前像门在这一半从未被执行 #6277

Closed

Description

@baozhoutao

观察类发现(#5492 复现过程中量到,范围外,不在该单修)。

事实

packages/plugins/plugin-security/src/vama-write-path-convergence.test.ts 的测试替身把一次 by-id delete 构造成:

const opCtx: any = {
  object: 'crm_contract',
  operation: 'delete',
  options: { id: recordId },   // ← 引擎不接受这个形状
};

而真实引擎的 by-id delete 判定(metadata-core/src/engine-delete-dispatch.ts 的 scalarDeleteId / resolveEngineDeleteDispatch)只认 options.where.id:options.id 既不是 by-id 也不是 multi,落到 reject 分支。

后果是这一半的覆盖被悄悄掏空:SecurityPlugin 中间件的 extractSingleId(security-plugin.ts:2980)读的是 data.id 与 options.where.id,对 options.id 返回 null,于是 #1994 前像行级写门整段跳过;该用例里 write('delete', …) 实际只经过了 plugin-sharing 中间件的 canDelete 门。用例名声称的是「explain 与它所解释的那次写,答案一致」,而写的那一侧在 delete 上只跑了两个门中的一个。

实测(#5492 的复现装置里把同一形状换成 options: { where: { id } } 后):同一个 manager 的 delete 从 ok: true 变成 403 (row-level security) —— 前像门这才被执行到。UPDATE 一侧不受影响(data.id 是引擎与安全侧一致认可的 by-id 形状)。

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

生产路径没有这个形状(引擎会拒绝),所以今天没有用户会碰到;这是测试装置的保真度问题,不是运行时漏洞。但它属于「绿得不是因为逻辑对,而是因为什么都没执行」的那一类,值得在下一次动这个文件时一起修正。

建议修法

测试替身的 delete 分支改用引擎的规范形状 options: { where: { id } };更稳的做法是让替身像其他 fake engine 那样用 assertEngineDeleteDispatch(options) 把自己钉在生产者的拒绝面上(scripts/check-engine-double-contract.mjs 的既有纪律)。

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 7, 2026
  2. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    Collaborator

    Findings sweep (maintainer-authorized one-off, 2026-08-07 — registered on #6015): promoted to the queue. A security-gate test whose DELETE half feeds a shape the engine rejects is asserting nothing on that half — the #1994 pre-image row gate is skipped wholesale. Fix the fixture to options.where.id and let the gate actually execute. Constraint: same security surface as the #5491/#5492 batch ruled today — serialize with it, don't ride alongside. finding → pm:queue.


    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 8, 2026
  4. self-assigned this
    on Aug 8, 2026
  5. baozhoutao commented on Aug 8, 2026

    @baozhoutao
    ContributorAuthor

    认领(identity 车道 PM,session_01JwwiU9bjhwy2SWj13ho8uv,第 16 轮,2026-08-08 02:2xZ)


    Generated by Claude Code

  6. baozhoutao commented on Aug 8, 2026

    @baozhoutao
    ContributorAuthor

    ACCEPT(identity 车道 PM,第 16 轮)—— PR #6502 已过审、ready + auto-merge。

    交付:DELETE fixture 改规范 options.where.id 形状,#1994 前像门 delete 半边首次真正被行使(探针直测:extractSingleId null→id、computeRlsFilter 零调用→一次);双保险钉(显式前置断言 + 引擎终点断言,反向验证各自独立变红);check:engine-double-contract 两 slice 转 pinned。诚实边界:零重钉 —— fixture 三个 permission set 均无 authored RLS,门答「不适用」而非判决,dev 拒绝移植 #5492 装置的 403 期望,并把「配对 PR 需自带 RLS principal」的测量指引留档 #5492(comment 5224112673)。

    落地依赖:唯一 CI 红为全仓性 Validate Package Dependencies(nanoid GHSA-2v37-7h3g-55p8,main 同红,dev 已立 #6506 附修法与选择子形状提醒)—— auto-merge 已挂,该 OSV 修复落地后本 PR 自动入队。#5492/#5491 配对批次的串行前提(本单先落)由此满足。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

pm:dispatchedDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loop

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions