生成ファイル
Ninka が生成する出力は、大きく二つに分かれます。
ninka/out/以下に置かれる canonical artifact- アプリケーションのソースツリーに生成される Consumer Projection
同じ「生成ファイル」でも、読む側と役割が違います。
| 出力 | 主な場所 | 主な利用者 |
|---|---|---|
| canonical artifact | ninka/out/ | verify、Authorization Reference、artifact を扱うツール、必要に応じたディレクトリ読み込み型 runtime |
| TypeScript Consumer Projection | <source root>/generated/ninka.ts または --out | TypeScript アプリケーションと ninka-authz/runtime |
| C# Consumer Projection | --out-csharp で指定したパス | .NET アプリケーションと Ninka.Authz |
ninka/out/ の構成
ninka/out/
├── policies/
│ ├── <id>.rego
│ ├── <id>.manifest.json
│ └── <id>.validation.json
├── bundles/
│ ├── <bundle-id>.wasm
│ └── <bundle-id>.build.json
└── input-contract.json
policies/ 以下のファイルは、一つのポリシーについて Rego、identity・lineage、validation を表します。bundles/ 以下は実行単位です。一つの bundle には一つの WASM module があり、その bundle に属する各ポリシーがそれぞれ entrypoint を持ちます。
artifact contract 上は複数 bundle を扱えますが、現在の toolchain はワークスペースに対して一つの bundle を生成します。bundle の分割単位は、利用者が認可設計として設定するものではありません。
artifact と Git 管理は別
Ninka の canonical artifact だからといって、すべてのリポジトリがそのファイルを Git で追跡する必要があるわけではありません。
リポジトリの役割によって、追跡する生成物は変わります。
| リポジトリの役割 | 主に追跡するもの | raw WASM | module identity の根拠 |
|---|---|---|---|
| Projection-only application | 手形 + Consumer Projection | 不要 | projection に埋め込まれた module と build record |
Reviewable-artifacts application (init の既定) | 手形 + raw WASM を除く ninka/out/ + projection | 不要 | build.json.wasm_sha256 |
| Artifact / conformance corpus | artifact 一式 | 追跡する | module 自体のバイト列 |
ninka-authz init は /ninka/out/bundles/*.wasm を .gitignore に追加します。通常の scaffold では、上の二つ目の構成になります。
どの構成でも verify を使えます。verify は Git を参照しないからです。必要なファイルが解決されたパス上に存在するか、現在の認可入力と toolchain から再現した状態と一致するかを filesystem 上で検査します。
普遍的なルールは「すべての artifact を commit する」ではありません。リポジトリが追跡すると決めた生成状態は、そのリポジトリが追跡する認可入力と、固定された toolchain の条件から再現できる必要があります。規範は TOOLCHAIN_SPEC §10.4 にあります。
ファイル一覧
| ファイル | 生成される時点 | 役割 |
|---|---|---|
policies/<id>.rego | ソース検査の成功後 | 一つの手形から決定論的に生成された Rego |
policies/<id>.manifest.json | ソース検査の成功後 | policy identity、Rego lineage、entrypoint、入力要件、Decision Log の開示情報 |
input-contract.json | ソース検査の成功後 | プロジェクト全体で統合した入力契約 |
bundles/<bundle-id>.wasm | OPA build 成功後 | 実行用 WASM module |
bundles/<bundle-id>.build.json | bundle とともに生成し、validation 後に validation 情報を確定 | module identity と policy-to-module binding |
policies/<id>.validation.json | 生成された validation が新しい WASM に対して成功した後 | 現在の手形から導いた validation table |
Consumer Projection は ninka/out/ の外に生成され、埋め込む bundle がある場合だけ書き出されます。
OPA を解決できない場合、通常の compile は Rego・manifest・input contract など WASM を必要としない成果物までは生成できます。完全な実行 bundle が必須なら build を使います。
Consumer Projection
TypeScript
TypeScript の Consumer Projection は、アプリケーションが使う次のような API を export します。
import { createNinka, policies } from "@/src/generated/ninka";
const authz = await createNinka({
onDecision: (event) => logger.info(event),
});
const allowed = authz.check(policies.invoiceAccess, input);
| export | 意味 |
|---|---|
createNinka(options?) | 埋め込まれた bundle から Ninka instance を作る。現在の生成 API では onDecision で Decision Log entry を受け取れる |
policies | 各policyのpolicy idから導出した名前(ハイフンを取り除いたcamelCase)をキーにした table。各 entry が変換前の正確な id・tegataHash と生成された入力型を結び付ける |
生成されたファイルには、意図的な runtime dependency が一つあります。ninka-authz/runtime を import します。一方、実行時に ninka/out/ のファイルを import したり読み込んだりはしません。build record / manifest の内容と WASM を base64 としてファイル内に保持し、runtime がそれを検証・instantiate できる形にしています。
Consumer Projection 自体が、認可ルールをアプリケーションの条件分岐として再実装するわけではありません。WASM の decode、artifact identity の検証、instantiate、Decision Log の masking、check() の評価は runtime が担います。
C#
C# の Consumer Projection は --out-csharp <file> を指定した場合だけ生成されます。Ninka.Authz から利用できるように、同等の bundle 情報と、生成された policy reference / input contract を保持します。
構文は TypeScript と異なりますが、目的は同じです。アプリケーション側で artifact binding を組み立て直すのではなく、生成されたソースをアプリケーションとの境界にします。
projection を最新に保つ
ファイルの先頭は、どのリリースとどの bundle から生成したかを記録します。ただし、そのヘッダーだけで「現在の手形に対して最新か」を判定するわけではありません。
ninka-authz verify は、解決した出力先、または --out / --out-csharp で指定したパスに Consumer Projection を再生成し、ディスク上のファイルとバイト単位で比較します。verify は projection を書き換えず、Git で追跡されているかどうかも確認しません。
実行時には、生成された policy reference が tegataHash も持っています。古い projection を別の仕様版の bundle と組み合わせた場合、check() は hash mismatch を整合性エラーとして拒否し、誤った契約で評価を続けません。
設計上の役割は Consumer Projection、API の詳細は runtime reference を参照してください。
policies/<id>.rego
一つのポリシーについて、Ninka コンパイラが決定論的に生成した Rego です。
認可判定のロジックは含みますが、policy.description や audit のようなレビュー専用情報、build timestamp などは含みません。OPA build より前に生成されます。
TypeScript / .NET の runtime は .rego を直接評価せず、コンパイル済みの WASM を実行します。
verify は現在の手形から Rego を再生成し、ディスク上の .rego とバイト単位で一致することを確認します。
policies/<id>.manifest.json
manifest は、一つのポリシーについて 手形 → Rego の対応と runtime contract を持ちます。
| フィールド | 意味 |
|---|---|
policy_id | 手形に書かれた正確な policy id |
tegata_version | Tegata の language/schema version。現在は "0.1" |
artifact_format_version | artifact contract の version。現在は 2 |
generated_by | manifest を生成した Ninka package/release。仕様 identity ではなく provenance |
tegata_hash | canonical な手形の認可内容を識別する hash |
rego_sha256 | 生成された Rego バイト列の SHA-256 |
entrypoint | compiler が導出し、このポリシー用として宣言する WASM entrypoint |
covered_resource_types | ポリシーが対象とする resource type |
input_requirements | compiler が導出した入力 key / type / requiredness / origin |
decision_log.unmasked | Decision Log でマスクせず記録してよい属性 |
tegata_hash、rego_sha256、generated_by は別の役割を持ちます。仕様の hash は生成コードの hash ではなく、生成したリリース番号は仕様 identity ではありません。
runtime は、対応している artifact_format_version を要求します。version が無ければ安全に推測できないため拒否します。対応外の古い / 新しい artifact format も、再コンパイルまたは runtime upgrade が必要なことを示して拒否します。
bundles/<bundle-id>.build.json
build record は、一つの実行 bundle について Rego → entrypoint → WASM の対応を持ちます。
| フィールド | 意味 |
|---|---|
bundle_id | bundle id。build/module のファイル名と対応する |
artifact_format_version | artifact contract version |
generated_by | bundle を build した Ninka リリース |
opa_version | OPA build の provenance。通常は設定された固定 OPA version |
wasm_sha256 | 生成された WASM バイト列の SHA-256 |
policies[] | bundle に含まれる各ポリシーの binding |
各 binding には次が入ります。
| フィールド | 意味 |
|---|---|
policy_id | この binding が表すポリシー |
entrypoint | module 内でそのポリシーを評価する entrypoint |
rego_sha256 | Rego lineage。対応する manifest と一致する必要がある |
validation | validation 成功時の vector 件数、digest、status |
build record は tegata_hash を重複して持ちません。手形から Rego までを manifest が持ち、Rego から実行 module までを build record が持ちます。両者は rego_sha256 でつながります。
runtime は load 時に次を確認します。
- module のハッシュ
- artifact format
- binding の policy id
- Rego の系譜
- manifest と binding の entrypoint が一致すること
- 宣言した entrypoint が実際の module に存在すること
bundle は一つの実行成果物です。bundle 内のどれか一つの必須 binding を検証できなければ、「確認できたポリシーだけ」を使うのではなく bundle 全体を拒否します。
policies/<id>.validation.json
validation table は 現在の手形から生成され、新しく build した WASM が必要な期待判定と一致した後に書き出されます。
ファイルには policy id、tegata_hash、validation format version、生成された vector が含まれます。
現在の evidence family は主に次の三つです。
| vector id の prefix | 目的 |
|---|---|
allow:<rule-id> | policy 全体の条件下で allow rule が実際に許可を与える positive witness |
what-if:<rule-id>:... | 生成した witness の一要素を変えた場合の判定 |
deny:<allow-rule-id>:<deny-rule-id> | allow と deny が重なり、deny-overrides が働くケース |
positive witness を作れない場合、validation は UNSAT と UNKNOWN を区別します。UNSAT は制約上成立しないことを証明できた場合、UNKNOWN は bounded search で witness を確定できなかった場合です。どちらも positive coverage の成功としては扱いません。
期待される判定は、生成された compiler output 自身から作るのではなく、Tegata semantics を独立に評価する reference evaluator が決めます。生成された Rego に「自分の正解」を答えさせて、その答えで同じ出力を検証する構造ではありません。
verify は table を現在の手形から再導出してディスク上のファイルと比較し、bundle build record に記録された vector count / digest も照合します。toolchain 条件が揃っている場合は、必要な vector を WASM に対して再実行します。
bundles/<bundle-id>.wasm
OPA が build した実行用 WASM module です。bundle に属する各ポリシーが、それぞれ別の entrypoint を持ちます。
実ファイルの SHA-256 は build.json.wasm_sha256 と一致する必要があります。WASM のバイト列は Rego だけでなく OPA build toolchain にも依存するため、opa_version を provenance として記録し、通常の CLI では OPA version を固定しています。
NINKA_OPA_PATH を使うと、既定の binary を明示的に上書きできます。ただし caller-supplied binary は、Ninka が pinned distribution として checksum 検証する対象ではありません。その override で再現性をどう管理するかは指定した側の責任です。
input-contract.json
コンパイル対象のポリシーを横断して統合した入力契約です。
{
"generated_by": { "package": "ninka-authz", "version": "0.7.0" },
"keys": [
{
"key": "subject.user_id",
"type": "string",
"required_by": ["invoice-access"],
"policies": ["invoice-access"]
}
]
}
各 key の型、どの policy が利用するか、どの policy が required としているかを記録します。policy manifest の input requirement と各言語の生成入力型は、同じ compiler-derived contract 情報から作られます。
言語別の型 projection を ninka/out/ に置くことはありません。
verify は現在の手形から contract を再導出し、ディスク上のファイルのうち再計算可能な内容と比較します。generated_by は contract identity ではなく provenance として別に扱います。
ディレクトリ読み込みと埋め込み読み込み
runtime が ディレクトリから成果物を読み込む場合、実行 bundle と、その bundle に含まれる各ポリシーの manifest が必要です。
bundles/<bundle-id>.wasm
bundles/<bundle-id>.build.json
policies/<id>.manifest.json
TypeScript の Ninka.load(dir) と .NET の Authz.Load(dir) がこの方式です。
通常の生成アプリケーション経路では、実行時に artifact directory は必要ありません。Consumer Projection が同等の bundle / module / manifest の情報を生成ソース内に持っているためです。runtime はそれをメモリ上の artifact の形へ戻し、ディレクトリ読み込みと同じ検証規則を適用します。
Rego、validation table、input-contract.json は、runtime が 1 回の判定を下すために必ずしも要りません。ただし、compile と verification のためのより広い artifact set には含まれます。
Authorization Reference の export は ninka/out/ とは別物
ninka-authz docs -o <dir> は静的な Authorization Reference snapshot を生成します。browser asset、data/reference.json、内容 digest を名前に含めた execution bundle module のコピーなどが入ります。
ninka/out/ とは形式も利用者も異なります。
ninka/out/ | docs -o snapshot | |
|---|---|---|
| 生成 | compile / build | docs -o。コンパイルはしない |
| 利用 | verification / tooling、必要に応じて directory runtime | browser |
| Git 管理 | repository role による | 通常は export 物として公開・保存・破棄を選ぶ |
| identity | Tegata / Rego / WASM それぞれの artifact identity | 取り込んだ認可状態の snapshot_hash |
書き出した時刻は exported_at として別に記録され、snapshot_hash には含まれません。どちらも人間による承認状態を表すフィールドではありません。
LIVE / SNAPSHOT の使い方と公開時の注意点は Authorization Reference を参照してください。