mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
fix(ffi): eliminate aliasing UB + add Azure Policy JSON compilation FFI (#727)
* fix(ffi): eliminate aliasing UB via to_shared_ref migration Add to_shared_ref() helper that creates &T (shared reference) from raw pointers instead of &mut T. This eliminates undefined behavior caused by violating Rust's aliasing invariant when C# SafeHandle permits concurrent FFI calls on the same handle. With &mut T, the compiler may assume exclusive (noalias) access and reorder or elide reads/writes — a miscompilation risk when another thread holds a reference to the same object. Switching to &T removes that assumption; actual mutation is mediated by the interior RwLock inside Handle<T>, which is the sole synchronization mechanism. Migrated sites: - rvm.rs: 20 non-drop call sites - engine.rs: 30 non-drop call sites + with_unwind_guard for timer fns - compiled_policy.rs: 2 call sites - Fix null-data UB in regorus_program_deserialize_binary Drop paths retain to_ref() where exclusive access is guaranteed by the caller contract (preventing use-after-free). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(ffi): add Azure Policy JSON compilation FFI and C# bindings - AliasRegistry builder pattern: RegorusAliasRegistryBuilder (mutable, single-threaded) + RegorusAliasRegistry (immutable, Arc-wrapped) - Azure Policy JSON compilation: regorus_compile_azure_policy_rule and regorus_compile_azure_policy_definition with alias registry support - regorus_rvm_set_context for host-supplied ambient data - C# AliasRegistryBuilder and AliasRegistry classes with convenience factories (FromJson, FromManifest, Empty) - C# AzurePolicyCompiler static class for policy rule/definition compilation - Compile functions take *const RegorusAliasRegistry (read-only via to_shared_ref for concurrent compilation safety) - Fix pre-existing clippy warnings across multiple crates Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
5467cd9e69
commit
86b4a279fa
@@ -150,3 +150,76 @@ const string ContextJson = """
|
||||
var allowed = RbacEngine.EvaluateCondition(Condition, ContextJson);
|
||||
Console.WriteLine($"RBAC condition allowed: {allowed}");
|
||||
```
|
||||
|
||||
## Azure Policy JSON Evaluation
|
||||
|
||||
Compile and evaluate Azure Policy JSON `policyRule` definitions directly — no Rego translation required.
|
||||
The `AzurePolicyCompiler` compiles JSON policy rules into RVM programs that can be executed with the `Rvm` engine.
|
||||
|
||||
```csharp
|
||||
using Regorus;
|
||||
|
||||
// 1. Load alias definitions for the resource provider
|
||||
const string AliasesJson = """
|
||||
[{
|
||||
"namespace": "Microsoft.Storage",
|
||||
"resourceTypes": [{
|
||||
"resourceType": "storageAccounts",
|
||||
"aliases": [{
|
||||
"name": "Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly",
|
||||
"defaultPath": "properties.supportsHttpsTrafficOnly",
|
||||
"paths": []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
""";
|
||||
|
||||
using var registry = AliasRegistry.FromJson(AliasesJson);
|
||||
|
||||
// 2. Compile a JSON policy rule (the native Azure Policy language)
|
||||
const string PolicyRule = """
|
||||
{
|
||||
"if": {
|
||||
"allOf": [
|
||||
{ "field": "type", "equals": "Microsoft.Storage/storageAccounts" },
|
||||
{ "field": "Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly", "equals": false }
|
||||
]
|
||||
},
|
||||
"then": { "effect": "deny" }
|
||||
}
|
||||
""";
|
||||
|
||||
using var program = AzurePolicyCompiler.CompilePolicyRule(registry, PolicyRule);
|
||||
|
||||
// 3. Normalize an ARM resource and evaluate
|
||||
var armResource = """
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts",
|
||||
"name": "mystorage",
|
||||
"properties": { "supportsHttpsTrafficOnly": false }
|
||||
}
|
||||
""";
|
||||
var envelope = registry.NormalizeAndWrap(armResource);
|
||||
|
||||
using var vm = new Rvm();
|
||||
vm.LoadProgram(program);
|
||||
vm.SetInputJson(envelope!);
|
||||
|
||||
var result = vm.ExecuteEntryPoint("main");
|
||||
// result: {"effect": "deny"} for non-compliant, "<undefined>" for compliant
|
||||
Console.WriteLine($"Policy result: {result}");
|
||||
```
|
||||
|
||||
**Context-dependent policies:** If your policy uses context functions like
|
||||
`subscription()`, `resourceGroup()`, or `requestContext()`, you must also set
|
||||
the VM context separately:
|
||||
|
||||
```csharp
|
||||
// The context JSON from NormalizeAndWrap is in the input envelope,
|
||||
// but must also be provided to the VM's ambient context:
|
||||
vm.SetContextJson(contextJson);
|
||||
```
|
||||
|
||||
You can also compile full policy definitions (with parameters) using
|
||||
`AzurePolicyCompiler.CompilePolicyDefinition()`. See
|
||||
`bindings/csharp/Regorus.Tests/AzurePolicyCompilerTests.cs` for comprehensive examples.
|
||||
|
||||
Reference in New Issue
Block a user