// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using Regorus.Internal; #nullable enable namespace Regorus { /// /// Represents a policy module with an ID and content. /// public struct PolicyModule { /// /// Gets or sets the unique identifier for this policy module. /// public string Id { get; set; } /// /// Gets or sets the Rego policy content. /// public string Content { get; set; } /// /// Initializes a new instance of the PolicyModule struct. /// /// The unique identifier for this policy module /// The Rego policy content public PolicyModule(string id, string content) { Id = id; Content = content; } } /// /// Provides static methods for compiling policies into efficient compiled representations. /// These are convenience methods that create an engine internally and perform compilation. /// public static unsafe class Compiler { /// /// Compiles a policy from data and modules with a specific entry point rule. /// This is a convenience function that sets up an Engine internally and calls the appropriate compilation method. /// /// JSON string containing static data for policy evaluation /// List of policy modules to compile /// The specific rule path to evaluate (e.g., "data.policy.allow") /// A compiled policy that can be evaluated efficiently /// Thrown when compilation fails public static CompiledPolicy CompilePolicyWithEntrypoint(string dataJson, IEnumerable modules, string entryPointRule) { var modulesArray = modules.ToArray(); var nativeModules = new Internal.RegorusPolicyModule[modulesArray.Length]; var pinnedStrings = new List(modulesArray.Length * 2); try { for (int i = 0; i < modulesArray.Length; i++) { var idPinned = Utf8Marshaller.Pin(modulesArray[i].Id); var contentPinned = Utf8Marshaller.Pin(modulesArray[i].Content); pinnedStrings.Add(idPinned); pinnedStrings.Add(contentPinned); nativeModules[i] = new Internal.RegorusPolicyModule { id = idPinned.Pointer, content = contentPinned.Pointer }; } return Utf8Marshaller.WithUtf8(dataJson, dataPtr => Utf8Marshaller.WithUtf8(entryPointRule, entryPointPtr => { unsafe { fixed (Internal.RegorusPolicyModule* modulesPtr = nativeModules) { var result = Internal.API.regorus_compile_policy_with_entrypoint( (byte*)dataPtr, modulesPtr, (UIntPtr)modulesArray.Length, (byte*)entryPointPtr); var policy = GetCompiledPolicyResult(result); return policy; } } })); } finally { foreach (var pinned in pinnedStrings) { pinned.Dispose(); } } } /// /// Compiles a target-aware policy from data and modules. /// This is a convenience function that sets up an Engine internally and calls target-aware compilation. /// At least one module must contain a `__target__` declaration. /// /// JSON string containing static data for policy evaluation /// List of policy modules to compile /// A compiled policy that can be evaluated efficiently /// Thrown when compilation fails public static CompiledPolicy CompilePolicyForTarget(string dataJson, IEnumerable modules) { var modulesArray = modules.ToArray(); var nativeModules = new Internal.RegorusPolicyModule[modulesArray.Length]; var pinnedStrings = new List(modulesArray.Length * 2); try { for (int i = 0; i < modulesArray.Length; i++) { var idPinned = Utf8Marshaller.Pin(modulesArray[i].Id); var contentPinned = Utf8Marshaller.Pin(modulesArray[i].Content); pinnedStrings.Add(idPinned); pinnedStrings.Add(contentPinned); nativeModules[i] = new Internal.RegorusPolicyModule { id = idPinned.Pointer, content = contentPinned.Pointer }; } return Utf8Marshaller.WithUtf8(dataJson, dataPtr => { unsafe { fixed (Internal.RegorusPolicyModule* modulesPtr = nativeModules) { var result = Internal.API.regorus_compile_policy_for_target( (byte*)dataPtr, modulesPtr, (UIntPtr)modulesArray.Length); var policy = GetCompiledPolicyResult(result); return policy; } } }); } finally { foreach (var pinned in pinnedStrings) { pinned.Dispose(); } } } private static string? StringFromUTF8(IntPtr ptr) { #if NETSTANDARD2_1 return System.Runtime.InteropServices.Marshal.PtrToStringUTF8(ptr); #else int len = 0; while (System.Runtime.InteropServices.Marshal.ReadByte(ptr, len) != 0) { ++len; } byte[] buffer = new byte[len]; System.Runtime.InteropServices.Marshal.Copy(ptr, buffer, 0, buffer.Length); return Encoding.UTF8.GetString(buffer); #endif } private static CompiledPolicy GetCompiledPolicyResult(Internal.RegorusResult result) { try { if (result.status != Internal.RegorusStatus.Ok) { var message = StringFromUTF8((IntPtr)result.error_message); throw result.status.CreateException(message); } if (result.data_type != Internal.RegorusDataType.Pointer || result.pointer_value == null) { throw new Exception("Expected compiled policy pointer but got different data type"); } var handle = RegorusCompiledPolicyHandle.FromPointer((IntPtr)result.pointer_value); return new CompiledPolicy(handle); } finally { Internal.API.regorus_result_drop(result); } } } }