Table of Contents

Policy Compilation

To evaluate policy modules they need to be compiled into WASM.

You can compile them manually with opa build -t wasm ... command or ask OpaDotNet do that for you.

OpaDotNet provides two options for policy compilation:

Which one you should be using?

Use OpaDotNet.Compilation.Cli if you have opa CLI tool available or you need functionality besides compilation (running tests, syntax checking etc.). Suitable for web applications and/or applications running in Docker containers. See Cli Compiler for more details.

Use OpaDotNet.Compilation.Interop if you need compilation only and want to avoid having external dependencies. Suitable for libraries, console application etc. See SDK Interop Compiler for more details.

If you sign your bundles to protect against tampering, see Bundle Signature Validation for how to verify signatures when loading a bundle.

Building bundles with BundleWriter

Both compilers accept a bundle directory path or a bundle as a Stream (CompileBundleAsync). If your policy sources and data don't live on disk as a directory - e.g. they come from a database, embedded resources, or are generated at runtime - use BundleWriter to assemble a bundle Stream in memory instead of writing files to a temp folder first.


var policySource = """
    package example

    default hello = false

    hello {
        x := input.message
        x == data.world
    }
    """;

var dataSource = """{ "world": "world" }""";

using var bundleStream = new MemoryStream();

// Assemble policy source and data files into a bundle, entirely in memory.
await using (var writer = new BundleWriter(bundleStream))
{
    writer.WriteEntry(policySource, "policy.rego");
    writer.WriteEntry(dataSource, "data.json");
}

bundleStream.Seek(0, SeekOrigin.Begin);

// The bundle still needs to be compiled to wasm before it can be evaluated.
var compiler = new RegoCliCompiler();

var policy = await compiler.CompileBundleAsync(
    bundleStream,
    new()
    {
        Entrypoints = ["example/hello"],
    },
    cancellationToken
    );

using var engine = OpaBundleEvaluatorFactory.Create(policy);

Other things BundleWriter can do:

  • WriteFile - add the contents of an existing file on disk as a bundle entry.
  • WriteManifest / the manifest constructor parameter - add bundle manifest (.manifest: roots, revision, metadata) into the bundle.
  • WriteBundle - merge the entries of another bundle with sources into this one, useful for combining several policies into a single bundle.
  • FromDirectory - create a BundleWriter pre-populated from a source directory, optionally excluding files matching glob patterns.
  • MergeCapabilities - a static helper that merges two capabilities.json files (e.g. built-in capabilities plus your own custom builtins) into one.
Note

BundleWriter strips a UTF-8 byte-order-mark from entries content if present - opa build fails to parse .rego files that have one.

BundleWriter writes a bundle of sources (.rego/.json/.yaml), not compiled wasm - you still need to run it through RegoCliCompiler or RegoInteropCompiler to get an evaluable policy.wasm bundle.