convex-verify
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese<!-- GENERATED from convex-agents content/capabilities/convex-verify.json — do not edit by hand. -->
<!-- GENERATED from convex-agents content/capabilities/convex-verify.json — do not edit by hand. -->
Prove a feature works — seed, drive, assert
验证功能是否正常工作——初始化、操作、断言
A green typecheck proves the code parses; it does not prove a non-owner is actually denied, that a query returns the right rows, or that a mutation has the effect it claims. This capability closes that gap with the loop the whole field is missing: seed → drive → assert, run in-process with so it needs no deployment. Its highest-value assertions are the NEGATIVE ones — the caller who should be refused — because those are exactly the authz defects the 30-app corpus shows are the #1 real bug and the ones a happy-path demo never catches.
convex-test通过类型检查可以证明代码能正常解析,但无法证明非所有者确实被拒绝访问、查询返回正确的行,或者变更操作达到了预期效果。该功能通过业内缺失的完整流程填补了这一空白:初始化(seed)→ 操作(drive)→ 断言(assert),使用在进程内运行,无需部署。其中价值最高的断言是负面断言——即验证应被拒绝的调用者——因为根据30个应用的案例分析,这类权限验证缺陷是排名第一的实际bug,而常规的正向演示永远无法发现它们。
convex-testWorkflow
工作流程
- IDENTIFY the feature to prove: the specific exported query/mutation/action (or a small set) the user just built/changed, and its intended behavior — who should be allowed, what data should come back, what a mutation should change. If the intent is unstated, ask one focused question rather than guessing the contract.
- SET UP : ensure
convex-test+convex-testare dev deps AND avitestsetsvitest.config.tswithtest.environment: "edge-runtime"— WITHOUT that config,server.deps.inline: ["convex-test"]fails at runtime withconvexTest(schema)(verified). Also installimport.meta.glob is not a function. Then@edge-runtime/vmgives aconvexTest(schema)handle. Reuse the project's existing test setup if present (compose with thetcapability, don't fork it).test - SEED realistic data through the app's OWN functions where possible (so the seed exercises the same validators/mutations a real user would), falling back to for fixtures the public API can't create. Seed at least: the caller's own rows AND a second user's rows, so cross-user access is testable.
t.run(async (ctx) => ctx.db.insert(...)) - DRIVE the feature as DIFFERENT identities with : call the function as (a) the legitimate owner, (b) a different authenticated user, and (c) unauthenticated (
t.withIdentity({ subject, tokenIdentifier, ... })with no identity). Use the real identity shape the app's auth uses (subject/tokenIdentifier), matching how ownership is resolved.t - ASSERT behavior — POSITIVE and NEGATIVE:
- positive: the owner gets the expected rows / the mutation made the expected change ().
expect(await t.withIdentity(owner).query(api.x.y, args)).toEqual(...) - NEGATIVE (the load-bearing half): a different user calling the same function is REFUSED — — and an unauthenticated caller is refused where auth is required. A feature is not proven until the wrong caller is shown to be blocked.
await expect(t.withIdentity(other).mutation(api.x.cancel, {id})).rejects.toThrow(/forbidden|not authorized|403/) - data-scope: a list/query returns ONLY the caller's rows, never the second user's (assert the second user's row is absent).
- positive: the owner gets the expected rows / the mutation made the expected change (
- RUN the tests () and report: what was proven (each positive + negative assertion that passed), and — critically — any assertion that FAILED, because a failed negative assertion is a real authz hole found before ship. Emit findings on the bus (specs/finding.schema.json, class authz/correctness, evidence kind probe-result with the exact failing call) for anything that didn't behave.
npx vitest run - Do NOT weaken a test to make it pass: if the owner-only query returns another user's row, the FIX is in the function (hand to convex-authz), not in the assertion. A test changed until it's green proves nothing.
- 确定待验证的功能:明确用户刚开发/修改的特定导出查询/变更/操作(或一小组),以及其预期行为——允许哪些用户访问、应返回哪些数据、变更操作应产生什么效果。如果预期行为未明确说明,应提出一个针对性问题,而非猜测约定。
- 配置:确保
convex-test和convex-test已作为开发依赖安装,且vitest中设置vitest.config.ts并配置test.environment: "edge-runtime"——如果没有此配置,server.deps.inline: ["convex-test"]在运行时会报错convexTest(schema)(已验证)。同时安装import.meta.glob is not a function。之后@edge-runtime/vm会返回一个convexTest(schema)句柄。如果项目已有测试配置,请复用(与t功能组合,不要单独搭建)。test - 初始化真实数据:尽可能通过应用自身的函数初始化数据(这样初始化过程会像真实用户一样触发相同的验证器/变更操作),如果公共API无法创建某些测试数据,则使用作为备选。至少初始化:调用者自己的数据行,以及另一个用户的数据行,以便测试跨用户访问。
t.run(async (ctx) => ctx.db.insert(...)) - 以不同身份操作功能:使用以不同身份调用功能:(a) 合法所有者,(b) 另一个已认证用户,(c) 未认证用户(不带身份的
t.withIdentity({ subject, tokenIdentifier, ... }))。使用应用认证系统实际使用的身份格式(subject/tokenIdentifier),与权限解析方式保持一致。t - 验证行为——正向与负向:
- 正向验证:所有者能获取预期的数据行 / 变更操作产生了预期效果()。
expect(await t.withIdentity(owner).query(api.x.y, args)).toEqual(...) - 负向验证(核心部分):其他用户调用同一功能时被拒绝————且在需要认证的场景下,未认证调用者被拒绝。只有当错误调用者被阻止时,才能证明功能正常。
await expect(t.withIdentity(other).mutation(api.x.cancel, {id})).rejects.toThrow(/forbidden|not authorized|403/) - 数据范围验证:列表/查询仅返回调用者自己的数据行,绝不会返回第二个用户的数据行(断言第二个用户的数据行不存在)。
- 正向验证:所有者能获取预期的数据行 / 变更操作产生了预期效果(
- 运行测试()并报告:已验证的内容(每个通过的正向和负向断言),以及——关键是——任何失败的断言,因为失败的负向断言意味着在发布前发现了真实的权限漏洞。对于不符合预期的行为,在总线(specs/finding.schema.json)上发布发现结果,分类为authz/correctness,证据类型为probe-result,并附上具体的失败调用。
npx vitest run - 不要为了让测试通过而弱化测试:如果仅限所有者访问的查询返回了其他用户的数据行,修复应在函数中进行(转交convex-authz处理),而非修改断言。修改到通过的测试无法证明任何内容。
Rules
规则
- Prove behavior, not compilation: every verification includes at least one NEGATIVE assertion (a caller who should be refused is refused) — the happy path alone is not proof.
- Drive the feature as multiple identities with t.withIdentity (owner, other user, unauthenticated) using the app's real subject/tokenIdentifier shape.
- Seed both the caller's rows AND a second user's rows so cross-user access and data-scope are actually testable.
- A vitest.config.ts with environment 'edge-runtime' + convex-test inlined is REQUIRED for convex-test to run (import.meta.glob needs it); author it, don't just author the test file.
- Run in-process with convex-test — no deployment needed; compose with the capability's setup rather than forking it.
test - Never weaken an assertion to make it pass: a failing negative test is a real defect → hand the fix to convex-authz/convex-expert, don't edit the test until it's green.
- Emit a bus finding for any assertion that failed (authz/correctness, evidence: the failing probe call) so a composite pass or self-heal can pick it up.
- This drives a SPECIFIC built feature; a request to set up a test framework generally is the capability.
test
- 验证行为而非编译结果:每次验证至少包含一个负向断言(应被拒绝的调用者确实被拒绝)——仅正向路径不足以证明功能正常。
- 使用以多个身份(所有者、其他用户、未认证用户)操作功能,身份格式需与应用的真实subject/tokenIdentifier一致。
t.withIdentity - 同时初始化调用者和另一个用户的数据行,以便实际测试跨用户访问和数据范围限制。
- 必须配置,设置环境为'edge-runtime'并内联convex-test,否则convex-test无法运行(需要import.meta.glob);需编写该配置文件,而非仅编写测试文件。
vitest.config.ts - 使用convex-test在进程内运行——无需部署;与功能的配置组合使用,不要单独搭建。
test - 绝不要为了让测试通过而弱化断言:失败的负向测试意味着真实缺陷→将修复工作转交convex-authz/convex-expert,不要修改测试直到问题解决。
- 对于任何失败的断言,在总线发布发现结果(authz/correctness,证据:失败的探测调用),以便组合验证或自我修复流程能处理。
- 该功能针对特定已开发的功能;如果是请求搭建测试框架,属于功能的范畴。
test