* perf(rvm): fix O(n²) comprehension yield by mutating in-place
Instead of cloning the entire accumulator collection on every yield
iteration, use take_register + Rc::make_mut to get exclusive ownership
and mutate in-place. This reduces comprehension yield from O(n²) to O(n)
for both run-to-completion and suspendable execution modes.
- Add RegoVM::take_register() helper that swaps register with Undefined
- Comprehension yield now takes the accumulator, mutates via Rc::make_mut,
and writes back — avoiding deep clones when refcount == 1
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* perf(rvm): use take_register for ObjectSet, ArrayPush, SetAdd
These instructions were cloning the container register (bumping Rc to 2),
then calling as_object_mut/as_array_mut/as_set_mut which invokes
Rc::make_mut — deep-cloning the entire collection since refcount > 1.
Use take_register instead so the Rc refcount stays at 1, making
Rc::make_mut a no-op and allowing in-place mutation.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* perf(rvm): remove unnecessary clones in rule caching
- execute_call_rule_common: move final_value into cache instead of
cloning, since it is not used afterwards
- finalize_rule_frame_data: add comment clarifying the clone is needed
because the value is both cached and returned
- Remove unnecessary .clone() on result_from_rule when setting register
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* rvm: avoid RuleInfo clone per rule call
Replace RuleInfo.clone() (which heap-allocates name, destructuring_blocks, and
potentially function_info) with a cheap Arc<Program> clone (atomic refcount
bump) followed by borrowing &RuleInfo from the local Arc. This eliminates
per-rule-call heap allocations.
Sites changed:
- execute_call_rule_common: Arc clone + borrow
- execute_call_rule_suspendable: Arc clone + borrow
- finalize_rule_frame_data: Arc clone + borrow
- handle_rule_break_event: inline Arc clone + borrow (was get_rule_info)
- handle_rule_error_event: inline Arc clone + borrow (was get_rule_info)
- Removed now-unused get_rule_info method
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* rvm: replace bincode with postcard for serialization
Remove unlinked bincode dependency. Use postcard (already a dep for rvm feature)
for all binary serialization/deserialization in program serialization and tests.
Also adds rvm_benchmark benchmark.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* perf(rvm): cache dummy Span/Expr for builtin calls
Every builtin call was allocating a Source (via from_contents), a Span, and
N Ref<Expr> wrappers just to satisfy the builtin function signature. These
dummy values are only used for error reporting context.
Cache the dummy Span and Vec<Ref<Expr>> on the RegoVM struct. The Source and
Span are created once on first builtin call; dummy Expr entries grow as
needed and are reused across calls via mem::take/put-back pattern.
This eliminates per-builtin-call heap allocations for Source (Rc + String +
Vec<lines>), Span clones, and Rc<Expr> wrappers.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* perf(rvm): round 2 allocation reduction in builtins, entry points, virtual data
- Cache builtin args Vec on RegoVM (mem::take/clear/put-back pattern)
- Restructure builtins_cache as two-level map for clone-free lookup
- Use IndexMap::get_index() in execute_entry_point_by_index
- Use mutable Vec path stack in traverse_rule_tree_subobject (push/pop)
- Walk data tree and rule-result paths by reference, clone only leaf
- Use mem::replace in resume() instead of cloning ExecutionState
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* fix(rvm): address PR review feedback
- Restore cached_builtin_args on all error/early-return paths in
execute_builtin_call to preserve allocation reuse
- Use 1-based line/col and \"<builtin>\" filename in dummy span for
clearer diagnostics
- Restore result register before returning errors in comprehension
mode-mismatch branches (both run-to-completion and suspendable)
- Avoid clone in resume() invalid-state error path by formatting
debug string before moving state back
---------
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Move RVM binary encoding from bincode to postcard and bump the format version. Update test helpers, docs, changelog, and refresh lockfiles after the swap.
Closes#575
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
- add Azure RBAC condition interpreter and builtin evaluation in core (expressions, parser updates, evaluator, and test harness)
- introduce comprehensive RBAC YAML test suites and coverage for i
- action/suboperation
- strings
- numbers
- bools
- IP
- GUID
- dates
- times
- lists
- quantifiers (ForAnyOfAnyValues, ForAllOfAllValues)
- expose RBAC evaluation through FFI with an `rbac` feature flag enabled by default
- add C# `RbacEngine` wrapper + P/Invoke entrypoint and document usage in C# README
- expand C# tests to execute all RBAC YAML cases with per-case logging
- wire test assets into C# test output and centralize YAML dependency versions
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
- Prefix regorus- to mimalloc crates and add MIT licenses
- alias dependencies to avoid code changes
- add versions and release-plz publish entries
- update Cargo.lock files for new crate names
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Bump up the versions to 0.9.0 to match the C# binding version.
Also use central version management for C# projects
Also fix clippy lint errors
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
- Introduce ExecutionTimer/ExecutionTimerConfig to allow limiting evaluating time.
- To amortize time checking costs, checking interval can be configured via the notion of work units
- A global fallback time limit can be set to universally limit all evaluation in addition to engine level limit setting.
- Implement limnits in interpreter and RVM. In RVM, also handle suspend/resume so that time during pause is not counted.
- Add engine-level APIs to set/clear per-engine timer configuration and apply global fallback defaults.
- Surface execution-time limits through FFI and C# bindings
- Add C# tests and example usage to validate engine overrides, global fallback behavior, and compiled policy enforcement.
- Expand docs for execution-time limit
- Add interpreter YAML cases and VM unit tests for time-limit behavior and deterministic time sources.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Policy evaluation at scale needs to be able to set memory limits
so that a bad policy does not hog memory or to ensure that
policy evaluation itself does not use too much memory which could
cause other components to suffer.
This PR introduces capability to set and enforce global memory limits.
It also lays the groundwork for enabling per evaluation limits in future.
Once a global memory limit is set, Regorus maintains per thread counters
to track memory activity (allocation, deallocation) of a thread.
These counters are periodically flushed to global memory counters.
Per thread counters avoid the contention that updating global counters
on each alloc/free would cause.
Policy evaluation periodically checks these counters and raises errors
if allocated memory has exceeded the configured limit.
Currently memory limit capability is exposed only to FFI and C#.
Also update mimalloc to v2.2.6
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Change the SPDX license expression from `MIT` to
`MIT AND Apache-2.0 AND BSD-3-Clause` to reflect all of the licenses
that apply to the crate’s sources.
Add license text for `Apache-2.0` and the `BSD-3-Clause` license from
Go’s `time` module to `LICENSE`. Like `MIT`, both of these licenses
require the license text to be distributed with source and/or binaries.
- Supply chain: Use the popular num-bigint crate for handling large integers
- Optimization: Handle f64, i64, u64 directly. These will be the most common instances of a number.
OPA number semantics isn't clear.
https://github.com/open-policy-agent/opa/issues/6281
As part of this change, we update the following failing tests:
- A local test that relies on what 15.3/3 evaluates to.
With our current change, we round in a different direction than what OPA does, but consistent
with Rust. We produce 5.1000000000000005 where as the OPA test expects 5.1.
There is no clear definition in Rego of what the right answer is. Moreover, policies should not
rely on exact floating point value comparison. Therefore this deviations is justified.
The test is patched to pass.
- Another local vm test that exercised 1.1 + 2.2
- Another local vm test that exercises 5.5 - 2.2
- An OPA test that expects that a large integer number say 10e308 is printed in exponent notation.
num-bigint does not print using scientific notation and instead prints all the digits.
The benefit of preserving this compatibility is not clear. We skip this test.
- Doc tests that exercised handling floating point numbers with more than 15 (what f64 supports)
digits of precision. There is no usecase for this scenario. The tests are updated to reflect
the behavior.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* feat: Add Azure RBAC condition parser
- declare an `azure-rbac` feature and expose the Azure RBAC module with parser, AST, and YAML-driven tests
- extend the shared lexer with RBAC-specific tokens, single-quoted strings, and corrected raw-string spans
- verify the parser via comprehensive test cases covering every operator and complex chaining
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
---------
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* feat!: add Rego Virtual Machine (RVM) implementation
This commit introduces a register-based virtual machine for executing Rego
policies with bytecode-style instructions. Unlike the existing tree-walking
interpreter, the RVM compiles policies into instruction sequences that operate
on virtual registers, offering better performance and optimization potential.
Core Components:
Instruction Set Architecture:
- Define instruction types for data operations, control flow, and builtins
- Implement instruction parameter encoding and display formatting
- Add instruction parser with comprehensive test coverage
Virtual Machine Engine:
- Register-based execution model with program counter management
- Loop execution supporting iterators, comprehensions, and quantifiers
- Function call handling with argument evaluation and context management
- Rule evaluation with default value resolution and virtual data support
- Arithmetic and comparison operation implementations
Program Representation:
- Program listing builder with instruction sequencing
- Rule tree construction for organizing policy rules
- Binary and JSON serialization for compiled programs
- Recompilation support for program modification
Testing Infrastructure:
- Extensive YAML test suites covering all VM features
- Rust unit tests for VM execution and instruction parsing
- Test suites for loops, comprehensions, builtins, and control flow
BREAKING CHANGE: Introduces new VM execution path alongside interpreter
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* docs: add detailed RVM architecture references
Introduce architecture.md explaining program artifacts, serialization, and runtime subsystems.
Document the full opcode catalog in instruction-set.md, including operands, parameter tables, and outcomes.
Walk through execution flow, stacks, and operational guidance in vm-runtime.md, tying the runtime to the new architecture docs.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
---------
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* build: Add xtask automation for binding version management
Introduces a dedicated xtask crate that keeps language binding versions
in sync with the core regorus crate, following the workflow pattern used
by rust-analyzer, gitoxide, and ripgrep.
Key features:
- Git-based change detection: compares binding source files against a
base ref (merge-base with origin/main by default) plus unstaged/
untracked files to identify which bindings have been modified
- SemVer-aware bumping: binding edits trigger a minor version increment
(e.g. 0.5.1 → 0.6.0) under pre-1.0 semantics, signaling potential
breaking changes; clean bindings simply align to the root version
- Multi-language support: updates Cargo manifests (Rust FFI, Java,
Python, WASM, Ruby), Maven pom.xml (Java), Ruby version constants,
and C# project files in a single pass
- CI integration: --check mode fails fast when manifests are out of
sync, ensuring pre-commit and release-plz workflows catch stale
versions before merge
Integration points:
- release-plz.toml: runs cargo xtask bindings --base-ref origin/main
after bumping the root crate, so binding versions are updated
atomically during the release process
- scripts/pre-commit: invokes cargo xtask bindings --check to block
commits that would leave bindings out of sync
- .cargo/config.toml: defines cargo xtask alias for convenience
Documentation includes inline examples showing how version bumps behave
when bindings are ahead/behind the root, and notes that the minor
field acts as the major version under SemVer 0.y.z initial development
phase.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
* build: refresh xtask tooling, workflows, and locks
- cargo xtask bindings: keep the binding version-sync pipeline intact
- cargo xtask update-deps: new helper to regenerate workspace/binding Cargo.lock files
- workflows: auto-detect the Java jar version in CI and temporarily disable the Ruby workflow
- lock files: refresh root + binding snapshots after the dependency sweep
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
---------
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Major changes:
- Implement the `net.cidr_contains` builtin
- Enable the v0 and v1 test for `net.cidr_contains`
- Add the `netip` crate to standardize CIDR searching and other
operations
Key Concept:
- Allow users to leverage the `net.cidr_contains` builtin to check
whether an IPv4 or IPv6 CIDR contains a specified IP address or
subnet.
Testing:
- All tests passing.
Signed-off-by: tjons <tylerschade99@gmail.com>
This commit introduces a complete multi-threaded evaluation benchmark suite for both Rust and C# implementations of Regorus.
- Implemented engine evaluation benchmark with input and engine cloning strategies
- Implemented compiled policy evaluation benchmark with input cloning and shared compiled policy strategies.
- Created EngineEvaluationBenchmark.cs and CompiledPolicyEvaluationBenchmark.cs with time-based execution (3s warmup + 3s evaluation)
- Implemented configuration options matching Rust implementation (useClonedEngines, useSharedPolicies parameters)
- Created markdown analysis documentation with cross-platform performance analysis
- C# seems to achieve 58-89% of Rust performance on test machine.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Since Regorus is MIT-licensed, it would be better to specify `license = "MIT"` rather than using `licene-file` to point to the MIT license file.
Some tools do not support parsing of `license-file`, for example crates.io classifies Regorus' license as "non-standard":
$ curl -s https://crates.io/api/v1/crates/regorus/0.4.0 | jq .version.license
"non-standard"
Using `license` would provide better compatability with various tools.
Signed-off-by: Burak Varlı <burakvar@amazon.co.uk>
Details:
- Implement complete Type enum with 12 variants: Any, Integer, Number, Boolean,
Null, String, Array, Set, Object, Enum, Const, AnyOf
- Add Schema wrapper struct with reference counting for efficient sharing
- Support JSON Schema-compatible deserialization with serde
- Implement discriminated subobjects for polymorphic type definitions
- Add comprehensive test suite covering all type variants
- Include Azure resource schema examples (Storage, VM, Key Vault, App Service)
- Create meta-schema validation system with lazy static validator
- Add extensive edge case and corner case test coverage
- Implement custom deserializers for complex schema patterns
This establishes the foundation for type checking and validation of Rego
policies, particularly useful for cloud resource schemas and policy validation.
Regorus's type system is a first of many features intended to
enable type checking and various other constraints on Rego policies.
The type system is inspired from:
- JSON schema
- Bicep
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Also update binding versions and lock files.
Note:
- Ruby binding is not updated
- C# binding is v0.7.0. We will make it match Regorus version later.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
- Documentation
- Regorus Engine is intended to be used from a single thread
- Clone the engine after adding policies and data to use from another thread
- Builtin errors strictness:
- default to less strict for OPA compatibility
- Provide API to change strictness
- Expose GetAstAsJson to C#,
This can allow writing policy validations in C#.
- Use spectre mitigated msvc crt libs (binskim compliance)
- Update dependencies
fixes#404
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Cryptographic builtins are removed due to various reasons like FIPS
compliance. Users needing crypto builtins are encouraged to use
extensions.
Deprecated functions are also removed.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Remove dependency on jsonwebtoken which brings in the ring crate.
Ring crate triggers governance violations.
Support for JWT will be implemented in future using a more governance
compliant crate.
BREAKING CHANGE
Prior to this PR, support for jwt builtins was minimially implemented.
Only io.jwt.decode and io.jwt.decode_verify was implemented.
With this PR, those builtins will no longer be available. They are
planned to be implemented in the future. In the meantime, they can be
brought back in via Engine::add_extension.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Removed cryptographically insecure sha1. This existed only for OPA
compatibility.
Also exclude bindings from main workspace
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
Specify `js` feature for `uuid` when building wasm by
specifying it as a non-optional dependency in wasm binding's Cargo.toml.
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>