認可をテストする
認可を確かめるには、種類の異なる証拠が必要です。人間によるレビュー、関所、生成される validation、verify、アプリケーションのテスト、移行時の比較は、それぞれ別の問いに答えます。どれか一つで、ほかを代用することはできません。
| 証拠 | 分かること | 分からないこと |
|---|---|---|
| 手形のレビュー | 認可仕様が、プロダクトの意図した要件を表しているか | アプリケーションが正しいデータを渡し、判定を正しく適用しているか |
| 関所 | Ninka が機械的に検出できるスキーマ上・意味上の検査に通っているか | 要件そのものが正しいか、人間が承認したか |
| 生成される validation | 現在の手形から導いた具体例と、コンパイル済みポリシーの判定が一致するか | 手形が業務要件や以前の実装と一致するか |
ninka-authz verify | 解決された成果物・Consumer Projection の状態が現在のソースに対応し、Ninka の再現性・検証条件を満たすか | Git がそのファイルを追跡しているか、人間が承認したか、以前と同じ挙動か |
| アプリケーション境界のテスト | アプリケーションが意図した入力を作り、意図したポリシーを呼び、結果を正しく適用しているか | ポリシーそのものが正しい業務ルールか |
| 移行時の比較 | 比較したケースについて、新旧の認可システムが同じ判定を返すか | どちらかがすべての入力について正しいか |
1. 現在のポリシーは、生成される validation で確かめる
WASM を生成するコンパイルでは、Ninka は 現在の手形から validation vector を導出します。期待される判定は、生成された Rego とは独立した reference evaluator が決め、生成された WASM がその判定と一致することを確認します。
対象には、各 allow ルールが実際に許可を与える例、条件などを一つ変えた場合、allow と deny が重なる場合などが含まれます。ここで検査しているのは、現在の仕様が実行成果物へ正しく変換されたかです。過去のポリシーに対する回帰テストではありません。ルールを意図的に変更すれば、次の validation は新しい手形から導かれます。
具体例は Authorization Reference で確認できます。vector の形式や成果物のフィールドは 生成ファイル を参照してください。
2. verify は再現性を確かめるゲートとして使う
npx ninka-authz verify
verify は、現在のワークスペースと、解決された出力先にある生成ファイルを読みます。ソースから導かれる状態を再生成し、成果物どうしの結び付きとハッシュを検査します。さらに、必要な validation を実行 bundle に対して再評価し、Consumer Projection も生成し直してバイト単位で比較します。
verify は Git を参照しません。 生成ファイルを Git で追跡するかどうかは、リポジトリ側の方針です。一方、そのファイルがディスク上に存在し、現在のソースと toolchain から再現できる状態と一致するかどうかは verify が検査する事実です。たとえば raw WASM を意図的に Git 管理から外しているリポジトリでも、bundle がディスク上に存在すれば verify は通り得ます。
したがって green になることが意味するのは、検査対象の状態を現在の Ninka と toolchain の契約のもとで再現できることです。次の意味ではありません。
- 人間が手形を承認した
- 変更前と同じ認可結果を保っている
- Git が特定の生成ファイル一式を追跡している
正確な検査項目、フラグ、スキップ条件、失敗条件は CLI リファレンス を参照してください。
3. アプリケーションとの境界をテストする
ハンドラが正しいドメインデータを読み、意図した認可入力を組み立て、意図したポリシーを呼び、deny を実際に適用しているかどうかは Ninka だけでは証明できません。ここはアプリケーション側でテストします。
少なくとも、境界の両側を確認してください。
- 意図した subject・action・具体的な resource を
check()に渡していること check()が返した boolean を、deny の場合も含めて正しく扱っていること
const check = vi.fn();
vi.mocked(createNinka).mockResolvedValue({ check } as never);
check.mockReturnValue(false);
const response = await POST(request);
expect(check).toHaveBeenCalledWith(policies.documentAccess, expectedInput);
expect(response.status).toBe(403);
check() 自体は同期処理です。await が必要なのはインスタンスの生成です。
アプリケーション側で Ninka を独自の composition root に包んでいるなら、この例をそのまま写すのではなく、その境界をテストまたはモックしてください。
4. 移行時は、置き換える認可システムと比較する
生成される validation だけでは、OPA、手書きの認可、その他の旧実装との parity は確認できません。期待値が現在の手形の意味論から導かれているためです。
移行中は、代表的なケースを新旧両方の認可経路へ通して判定を比較します。allow、deny、境界値、入力欠損、複数 role の組み合わせ、旧実装固有の入力表現など、移行対象のポリシーで意味のあるケースを含めてください。
この比較結果は Ninka の生成 validation とは別の証拠です。不一致がゼロでも、期待したポリシーとケースが実際に比較されていなければ意味はありません。詳しくは OPA から移行する を参照してください。
5. 人間によるレビューは別の層に残る
機械的な検査もアプリケーションのテストもすべて通っているのに、手形が業務要件の誤った解釈を忠実に実装している、ということはあり得ます。
認可の変更を受け入れる前に、仕様そのものをレビューしてください。認可をレビューする を参照してください。