Skip to main content

Generated Files

Ninka writes two different kinds of generated output:

  1. canonical artifacts under ninka/out/;
  2. Consumer Projections in the application's source tree.

They serve different readers and are not one directory contract.

OutputTypical locationPrimary readers
Canonical artifactsninka/out/verify, Authorization Reference, artifact tooling, and optional directory-based runtime loading
TypeScript Consumer Projection<source root>/generated/ninka.ts or --outTypeScript application code and ninka-authz/runtime
C# Consumer Projectionpath passed to --out-csharp.NET application code and Ninka.Authz

Artifact layout

ninka/out/
├── policies/
│ ├── <id>.rego
│ ├── <id>.manifest.json
│ └── <id>.validation.json
├── bundles/
│ ├── <bundle-id>.wasm
│ └── <bundle-id>.build.json
└── input-contract.json

Policy files describe one policy's compiled source, identity, lineage, and validation. Bundle files describe an execution unit. A bundle contains one WASM module with one entrypoint per policy bound to that bundle.

The artifact contract permits one or more bundles. The current toolchain emits one bundle for the workspace; bundle partitioning is not a user-configurable authorization concept.

Git tracking is a separate repository decision

Being a canonical Ninka artifact does not mean every repository must track that file in Git.

Ninka supports different repository roles:

Repository roleTypically trackedRaw WASMAnchor for module identity
Projection-only applicationTegata + Consumer Projectionnot requiredmodule and build record embedded in the projection
Reviewable-artifacts application (init default)Tegata + ninka/out/ except raw WASM + projectionnot requiredbuild.json.wasm_sha256
Artifact / conformance corpuscomplete artifact settrackedmodule bytes themselves

ninka-authz init adds /ninka/out/bundles/*.wasm to .gitignore, so the second row is the normal scaffolded application configuration.

All of these roles can use verify because verify does not read Git. It checks whether the required files are present at the resolved filesystem paths and whether they match the state reproduced from the current authorization inputs and toolchain contract.

The universal rule is not “commit every artifact.” It is: generated state a repository chooses to track must remain reproducible from the authorization inputs and pinned toolchain assumptions that repository tracks. The normative repository-role contract is in TOOLCHAIN_SPEC §10.4.

Files at a glance

FileProducedPurpose
policies/<id>.regoafter source checksdeterministic Rego produced from one Tegata
policies/<id>.manifest.jsonafter source checkspolicy identity, Rego lineage, entrypoint, input requirements, Decision Log disclosure metadata
input-contract.jsonafter source checksmerged project-wide input contract
bundles/<bundle-id>.wasmafter successful OPA buildexecutable WASM module
bundles/<bundle-id>.build.jsonwith the bundle; validation fields finalized after validationmodule identity and policy-to-module bindings
policies/<id>.validation.jsonafter generated validation succeeds against the built WASMvalidation table derived from the current Tegata

Consumer Projections are outside ninka/out/ and are written only when Ninka has a bundle to embed.

If OPA cannot be resolved, plain compile can still write the source-derived Rego, manifests, and input contract. build is the hard-fail command when producing a complete execution bundle is mandatory.


Consumer Projections

TypeScript

The generated TypeScript module exports the application-facing surface:

import { createNinka, policies } from "@/src/generated/ninka";

const authz = await createNinka({
onDecision: (event) => logger.info(event),
});

const allowed = authz.check(policies.invoiceAccess, input);

Its public exports are:

ExportMeaning
createNinka(options?)Creates a Ninka instance from the embedded bundle. The generated option surface currently exposes onDecision for observing Decision Log entries.
policiesTable keyed by a name derived from each policy's Tegata id (hyphens removed, camelCase). Each entry binds the exact, untransformed id and its tegataHash to the generated input type.

The generated file has one deliberate runtime dependency: it imports ninka-authz/runtime. It does not import files from ninka/out/ at runtime. Instead, it carries the parsed build/manifest data and the WASM as base64 so the runtime can verify and instantiate the bundle without an artifact directory.

The projection does not reimplement authorization rules as application control flow. Decoding the module, checking artifact identities, instantiating WASM, Decision Log masking, and evaluating check() remain runtime responsibilities.

C#

The C# Consumer Projection is written only when --out-csharp <file> is supplied. It carries the equivalent compiled bundle information and generated input/policy references for Ninka.Authz.

The exact generated syntax differs from TypeScript, but the boundary is the same: the application imports generated source instead of reconstructing artifact bindings itself.

Keeping a projection current

The header records what generated the projection, but the header is not a freshness oracle.

ninka-authz verify regenerates the projection at the path it resolves (or the --out / --out-csharp path supplied to the command) and requires byte identity with the file on disk. verify does not rewrite the projection and does not care whether Git tracks it.

At runtime, a policy reference also carries tegataHash. If a stale projection is paired with artifacts from another specification revision, check() refuses the mismatch instead of evaluating under the wrong generated contract.

See Consumer Projection for the architectural role and the runtime references for the API surface.


policies/<id>.rego

The deterministic Rego emitted for one policy.

It contains authorization decision logic, but not review-only text such as policy.description or audit, and not build timestamps. Ninka emits it before the OPA build step.

The application runtimes do not evaluate .rego directly; execution uses the compiled WASM.

verify regenerates this Rego from the current Tegata and requires byte identity with the file on disk.


policies/<id>.manifest.json

The manifest owns the Tegata → Rego part of the artifact chain and the runtime contract for one policy.

FieldMeaning
policy_idexact policy id
tegata_versionTegata language/schema version, currently "0.1"
artifact_format_versionartifact contract version, currently 2
generated_byNinka package/release that generated the manifest; provenance, not specification identity
tegata_hashidentity of the canonical Tegata authorization content
rego_sha256SHA-256 of the emitted Rego bytes
entrypointWASM entrypoint derived by the compiler and declared for this policy
covered_resource_typesresource types named by the policy
input_requirementscompiler-derived input keys/types/requiredness/origins for the policy
decision_log.unmaskedattributes permitted to appear unmasked in Decision Log entries

tegata_hash, rego_sha256, and generated_by have different jobs. A specification hash is not a generated-code hash, and the generating release is provenance rather than another identity for the specification.

The runtime requires a supported artifact_format_version. A missing version cannot be guessed safely. Unsupported older/newer formats are refused with remediation pointing toward recompilation or runtime upgrade as appropriate.


bundles/<bundle-id>.build.json

The build record owns the Rego → entrypoint → WASM part of the artifact chain for one execution bundle.

FieldMeaning
bundle_idbundle id; corresponds to the build/module file names
artifact_format_versionartifact contract version
generated_byNinka release that built the bundle
opa_versionOPA build provenance, normally the configured pinned version
wasm_sha256SHA-256 identity of the emitted WASM bytes
policies[]one policy binding per policy in the bundle

Each binding contains:

FieldMeaning
policy_idpolicy bound to the module
entrypointentrypoint for that policy in the module
rego_sha256Rego lineage; must agree with that policy's manifest
validationsuccessful validation metadata: vector count, vector digest, status

The build record intentionally does not duplicate tegata_hash. The manifest connects Tegata to Rego; the build record connects Rego to the executable module. They meet at rego_sha256.

At load time the runtime checks the module hash, artifact formats, binding policy ids, Rego lineage, manifest/binding entrypoint agreement, and that the declared entrypoint actually exists in the module.

A bundle is one execution artifact. If a required link for any bound policy fails, the runtime refuses the whole bundle rather than serving a partially verified module.


policies/<id>.validation.json

The validation table is generated from the current Tegata and written only after the newly built WASM agrees with the required expected decisions.

A file contains the policy id, tegata_hash, validation format version, and the generated vectors.

Current evidence families include:

Vector id prefixPurpose
allow:<rule-id>positive witness that establishes coverage for an allow rule under the complete policy
what-if:<rule-id>:...decision after changing one generated witness facet
deny:<allow-rule-id>:<deny-rule-id>overlapping evidence where deny overrides allow

Validation derivation distinguishes a provably impossible positive witness (UNSAT) from a bounded search that cannot establish one (UNKNOWN). Neither counts as successful positive coverage.

Expected decisions are determined independently from the emitted compiler transformation; the validation file is not produced by asking the generated Rego what answer it expects from itself.

verify derives the table again, compares it with the file on disk, checks the corresponding digest/count recorded in the bundle build record, and replays the required vectors against WASM when the toolchain path allows that obligation to be checked.


bundles/<bundle-id>.wasm

The executable OPA WASM module. Each policy bound to the bundle has its own entrypoint in this module.

The file's actual SHA-256 must equal build.json.wasm_sha256. WASM identity depends on the Rego bytes and the OPA build toolchain, which is why opa_version is recorded as build provenance and the default CLI path pins OPA.

NINKA_OPA_PATH can explicitly override the default binary. A caller-supplied override is not checksum-verified by Ninka as though it were the pinned distribution, so reproducibility responsibility for that override belongs to the caller.


input-contract.json

The merged project-wide input contract derived from the compiled policies.

{
"generated_by": { "package": "ninka-authz", "version": "0.7.0" },
"keys": [
{
"key": "subject.user_id",
"type": "string",
"required_by": ["invoice-access"],
"policies": ["invoice-access"]
}
]
}

It records the merged key/type contract, which policies use a key, and which policies require it. Per-policy manifest requirements and generated language input types come from the same compiler-derived contract information.

Language-specific type projections do not live under ninka/out/.

verify re-derives the contract and compares the recomputable content with the file on disk. generated_by is handled as provenance rather than part of the contract identity comparison.


Directory loading versus embedded loading

A runtime that loads artifacts from a directory needs the execution bundle and the manifest for every policy bound to it:

bundles/<bundle-id>.wasm
bundles/<bundle-id>.build.json
policies/<id>.manifest.json

That is the acquisition model used by Ninka.load(dir) in TypeScript and Authz.Load(dir) in .NET.

The normal generated application path does not require an artifact directory at runtime. Consumer Projections carry the equivalent bundle/module/manifest information in generated source and use the same verification rules after the runtime reconstructs the in-memory artifact shape.

Rego, validation tables, and input-contract.json are part of the wider compile/verification artifact set even though the runtime does not need all of them to execute a decision.


Exported Authorization Reference is not ninka/out/

ninka-authz docs -o <dir> creates a static Authorization Reference snapshot. It contains browser assets, data/reference.json, and content-digest-named copies of the exported execution bundle modules.

This is a different format with a different consumer:

ninka/out/docs -o snapshot
Produced bycompile / builddocs -o (does not compile)
Consumed byverification/tooling and optional directory runtimebrowser
Repository trackingdepends on repository rolenormally publish, retain, or discard as an exported snapshot
IdentityTegata/Rego/WASM artifact identitiessnapshot_hash for the captured authorization state

Export time is stored separately as exported_at and is not part of snapshot_hash. Neither field represents human approval.

See Authorization Reference for LIVE/SNAPSHOT behavior and hosting considerations.

See also