convex-verify について
convex-verifyは、Convex関数の動作をプロセス内テストで確かめるスキルです。認可やデータ範囲を検証する開発者向けで、権限のない呼び出しが拒否されることも重視します。
主な機能
- 01複数ユーザーのテストデータ準備
- 02異なるIDで関数を呼び出し
- 03成功と拒否の動作を検証
- 04convex-testとVitestでテスト実行
- 05失敗した検証を所見として報告
活用シーン
- 01所有者が期待するデータにアクセスできるか確認
- 02他ユーザーの変更関数呼び出しが拒否されるか確認
- 03クエリが他ユーザーの行を除外するか検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ convex/ agent-skills --skill convex-verifyインストール後、Claude Code で/convex-verifyを入力して読み込まれたか確認します。
詳細
機能が動作することを証明する — シード、実行、アサート
型チェックが成功しても、コードが解析できることしか証明されません。所有者以外のユーザーが実際に拒否されること、クエリが正しい行を返すこと、ミューテーションが期待どおりの効果をもたらすことは証明されません。この機能は、フィールド全体で欠けているループ、つまりシード → 実行 → アサートによって、その隔たりを埋めます。convex-test を使ってプロセス内で実行するため、デプロイは不要です。最も価値の高いアサーションは NEGATIVE(拒否されるべき呼び出し元)です。30 アプリのコーパスが示すとおり、これらは実際に最も多いバグである認可の欠陥そのものであり、ハッピーパスのデモでは決して見つかりません。
ワークフロー
- 証明する機能を特定します。ユーザーが作成または変更した、具体的なエクスポート済みクエリ/ミューテーション/アクション(または少数のセット)と、その意図された動作(誰に許可されるべきか、どのデータが返されるべきか、ミューテーションで何が変更されるべきか)です。意図が示されていない場合は、契約を推測するのではなく、要点を絞って質問を 1 つしてください。
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(...))を使用します。少なくとも、呼び出し元自身の行と別のユーザーの行をシードし、ユーザー間のアクセスをテストできるようにします。 t.withIdentity({ subject, tokenIdentifier, ... })を使い、異なる ID として機能を実行します。関数を(a)正当な所有者、(b)別の認証済みユーザー、(c)未認証ユーザー(ID なしのt)として呼び出します。所有権の解決方法に合わせ、アプリの認証で使用されている実際の ID 形式(subject/tokenIdentifier)を使います。- 動作を POSITIVE と NEGATIVE の両方でアサートします。
- positive:所有者が期待される行を取得する、またはミューテーションが期待される変更を行うこと(
expect(await t.withIdentity(owner).query(api.x.y, args)).toEqual(...))。 - NEGATIVE(最も重要な部分):別のユーザーが同じ関数を呼び出すと拒否されること —
await expect(t.withIdentity(other).mutation(api.x.cancel, {id})).rejects.toThrow(/forbidden|not authorized|403/)— また、認証が必要な箇所では未認証の呼び出し元も拒否されること。誤った呼び出し元がブロックされることを確認するまで、機能を証明したことにはなりません。 - データ範囲:リスト/クエリが呼び出し元自身の行だけを返し、別のユーザーの行を決して返さないこと(別のユーザーの行が含まれないことをアサートします)。
- positive:所有者が期待される行を取得する、またはミューテーションが期待される変更を行うこと(
- テスト(
npx vitest run)を実行し、証明できた内容(成功した各 positive/negative アサーション)と、重要な点として、失敗したアサーションがあれば報告します。失敗した negative アサーションは、リリース前に見つかった実際の認可の穴です。期待どおりに動作しなかったものについては、バスに指摘を送信します(specs/finding.schema.json、class authz/correctness、evidence kind probe-result。失敗した呼び出しを正確に記載)。 - テストを通すために弱めてはいけません。所有者のみが使えるクエリが別のユーザーの行を返す場合、修正すべきなのはアサーションではなく関数です(convex-authz に引き継ぎます)。テストを変更してグリーンにしても、何の証明にもなりません。
ルール
- コンパイルではなく動作を検証してください。すべての検証に、少なくとも1つの否定的アサーションを含めてください(拒否されるべき呼び出しが拒否されること)。成功パスだけでは証明になりません。
- アプリが実際に使用する subject/tokenIdentifier の形式を使い、t.withIdentity で複数のユーザー(所有者、別のユーザー、未認証)として機能を実行してください。
- 呼び出し元の行と、別ユーザーの行の両方をシードしてください。これにより、ユーザー間アクセスとデータスコープを実際に検証できます。
- convex-test の実行には、環境が 'edge-runtime' で convex-test がインライン化された vitest.config.ts が必須です(import.meta.glob が必要とするため)。テストファイルだけでなく、設定ファイルも作成してください。
- デプロイは不要です。convex-test を使ってプロセス内で実行してください。
test機能のセットアップと組み合わせ、独自に分岐させないでください。 - アサーションを弱めて合格させないでください。否定的テストの失敗は実際の不具合です。修正を convex-authz/convex-expert に引き継ぎ、テストは合格するまで編集しないでください。
- アサーションが失敗した場合は、失敗したプローブ呼び出しを証拠として、バスに検出結果(authz/correctness)を送信してください。これにより、複合パスまたはセルフヒーリングで検出結果を利用できます。
- これは特定の構築済み機能を動作させるためのものです。一般的なテストフレームワークのセットアップ依頼は、通常
test機能の対象です。
コメント
Markdown 対応