Convex Verify

作者 get-convex2cfe645c87f9無授權條款63 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫6 天前更新

Prove a Convex feature works — seed, drive as multiple mocked users via convex-test, assert behavior including the negative authz cases (wrong user refused, data-scope enforced).

AI 產生的概覽

透過植入資料、以多個模擬使用者身分驅動功能,並斷言正向與反向授權行為,來證明某個 Convex 功能確實可用。

功能
引導代理針對特定的 Convex 查詢、變更或動作執行「植入—驅動—斷言」循環,並使用 convex-test 在行程內執行,不需要部署。它會為呼叫者與第二位使用者植入擬真資料,分別以擁有者、其他已驗證使用者與未驗證呼叫者的身分驅動該函式,並同時斷言預期結果與拒絕行為。它會回報哪些斷言通過、哪些失敗,並將失敗的反向斷言視為真正的授權缺陷。產出包括測試檔案、vitest 設定,以及針對失敗斷言的發現記錄。
適用情境
適用於建置或修改某個具體 Convex 功能之後,需要證據顯示授權與資料範圍限制確實生效,而不只是程式碼能通過型別檢查時。它適合驗證非擁有者會被拒絕,以及查詢只會回傳呼叫者自己的資料列。通用測試框架的建置屬於另一項工作。
執行需求
需要一個 Convex 專案,並將 convex-test、vitest 與 @edge-runtime/vm 作為開發相依套件,同時需要一份使用 edge-runtime 環境並內嵌 convex-test 的 vitest.config.ts。測試在行程內執行,因此不需要部署或網路存取。此技能不附帶指令碼,僅為說明性指示。
<!-- 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 convex-test 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.

Workflow

  1. 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.
  2. SET UP convex-test: ensure convex-test + vitest are dev deps AND a vitest.config.ts sets test.environment: "edge-runtime" with server.deps.inline: ["convex-test"] — WITHOUT that config, convexTest(schema) fails at runtime with import.meta.glob is not a function (verified). Also install @edge-runtime/vm. Then convexTest(schema) gives a t handle. Reuse the project's existing test setup if present (compose with the test capability, don't fork it).
  3. 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 t.run(async (ctx) => ctx.db.insert(...)) 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.
  4. DRIVE the feature as DIFFERENT identities with t.withIdentity({ subject, tokenIdentifier, ... }): call the function as (a) the legitimate owner, (b) a different authenticated user, and (c) unauthenticated (t with no identity). Use the real identity shape the app's auth uses (subject/tokenIdentifier), matching how ownership is resolved.
  5. 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 — await expect(t.withIdentity(other).mutation(api.x.cancel, {id})).rejects.toThrow(/forbidden|not authorized|403/) — and an unauthenticated caller is refused where auth is required. A feature is not proven until the wrong caller is shown to be blocked.
    • data-scope: a list/query returns ONLY the caller's rows, never the second user's (assert the second user's row is absent).
  6. RUN the tests (npx vitest run) 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.
  7. 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.

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 test capability's setup rather than forking it.
  • 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 test capability.

來源與署名

來源:get-convex/agent-skills位於skills/convex-verify提交2cfe645

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架