Adds the YAML test runner that exercises the companion test data PRs, plus several compiler fixes surfaced during testing: - Removed parameter register caching that produced wrong results inside short-circuiting allOf/anyOf blocks; added literal-index caching for parameter defaults to avoid repeated O(n) literal-table scans - Simplified cross-resource effect details to only emit roleDefinitionIds and type (deployment templates are not evaluated for compliance) - Replaced guid/uniqueString builtins with clear "unsupported" errors - Normalized datetime output to ISO 8601 with Z suffix - Added azure_policy parser MAX_COL constant (8192) for long template expressions, keeping the global DEFAULT_MAX_COL at 1024 - Added rvm to azure_policy feature dependencies since the compiler targets RVM bytecode Also restructures the example binary into examples/regorus/ with new azure-policy-eval and azure-policy-aliases subcommands, adds C# alias normalization tests, and documents Azure Policy support in the README. Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Regorus CSharp
Regorus is
- Rego-Rus(t) - A fast, light-weight Rego interpreter written in Rust.
- Rigorous - A rigorous enforcer of well-defined Rego semantics.
See main Regorus page for more details about the project.
Building
Github Actions
The simplest way to build a Nuget for Regorus' C# bindings is to use Github Actions. The action to do so is named bindings/csharp and is defined in .github/workflows/test-csharp.yml.
There are two ways to trigger a Nuget build.
- Runs are triggered automatically whenever a push or pull request is made to the
mainbranch. - A run can be triggered manually by navigating to the action in the Github UI and clicking
Run workflow. This option allows you to generate a Nuget for any branch, which is useful when testing the integration of in-progress changes to Regorus with other projects. Nuget files that are generated via this flow will have amanualtriggersuffix appended to their version number, making it easy to distinguish them from Nugets generated using themainbranch.
Once the workflow run completes, the generated Nuget can be downloaded by following these steps:
- Open the run.
- Click on
Build Regorus nugeton the left. - Expand the
Upload Regorus nugetstep. - Click the
Artifact download URLlink at the bottom. - Save and extract the downloaded zip file to find the
.nupkgfile.
Local
The cargo xtask runner provides helpers for local builds:
cargo xtask ffibuilds thebindings/fficrate for the host platform in debug mode. Add--target <triple>(repeatable) to cross-compile, or--releaseto produce optimised artefacts. Results land underbindings/ffi/target/<triple>/<profile>.cargo xtask nugetreuses those artefacts to pack the C# library. It defaults to debug builds for the host but accepts--target,--release,--artifacts-dir <path>to reuse existing binaries, and--enforce-artifactsto require every officially supported platform.cargo xtask test-csharpensures a NuGet is available (rebuilding when required or when--force-nugetis passed) and then runsRegorus.Tests,TestApp, andTargetExampleAppagainst it. The command accepts the same build flags ascargo xtask nuget.
Memory Usage Safeguards
The C# bindings expose allocator-backed memory tracking utilities via the static Regorus.MemoryLimits helper. Typical usage:
// Restrict total allocations to 128 MiB for the process
Regorus.MemoryLimits.SetGlobalMemoryLimit(128 * 1024 * 1024);
// Optional: tune how frequently each thread flushes its allocation counters
Regorus.MemoryLimits.SetThreadFlushThresholdOverride(256 * 1024);
// Engine operations throw InvalidOperationException with the allocator message if the budget is exceeded
using var engine = new Regorus.Engine();
var veryLargeJson = new string('x', 128 * 1024);
try
{
engine.SetInputJson(veryLargeJson);
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Allocator reported: {ex.Message}");
}
// Restore defaults once done
Regorus.MemoryLimits.SetGlobalMemoryLimit(null);
Regorus.MemoryLimits.SetThreadFlushThresholdOverride(null);
See bindings/csharp/Regorus.Tests/RegorusTests.cs for scenario coverage and bindings/csharp/TargetExampleApp/Program.cs for end-to-end usage.
RVM Usage Example
The RVM API lets you compile a program from modules/entrypoints and execute it in a VM:
using Regorus;
const string Policy = """
package demo
default allow = false
allow if {
input.user == "alice"
some role in data.roles[input.user]
role == "admin"
}
""";
const string Data = """
{ "roles": { "alice": ["admin"] } }
""";
const string Input = """
{ "user": "alice" }
""";
var modules = new[] { new PolicyModule("demo.rego", Policy) };
var entryPoints = new[] { "data.demo.allow" };
using var program = Program.CompileFromModules(Data, modules, entryPoints);
var listing = program.GenerateListing();
using var vm = new Rvm();
vm.LoadProgram(program);
vm.SetDataJson(Data);
vm.SetInputJson(Input);
var result = vm.Execute();
Console.WriteLine($"allow: {result}");
Azure RBAC Condition Evaluation
Evaluate Azure RBAC condition expressions directly with a JSON evaluation context:
using Regorus;
const string Condition = "@Resource[owner] StringEquals 'alice'";
const string ContextJson = """
{
"principal": {
"id": "user-1",
"principal_type": "User",
"custom_security_attributes": {}
},
"resource": {
"id": "/subscriptions/s1",
"resource_type": "Microsoft.Storage/storageAccounts",
"scope": "/subscriptions/s1",
"attributes": {
"owner": "alice",
"confidential": true
}
},
"request": {
"action": "Microsoft.Storage/storageAccounts/read",
"data_action": null,
"attributes": {
"clientIP": "10.0.0.1"
}
},
"environment": {
"is_private_link": null,
"private_endpoint": null,
"subnet": null,
"utc_now": "2023-05-01T12:00:00Z"
},
"action": "Microsoft.Storage/storageAccounts/read",
"suboperation": null
}
""";
var allowed = RbacEngine.EvaluateCondition(Condition, ContextJson);
Console.WriteLine($"RBAC condition allowed: {allowed}");