// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using Regorus.Internal; #nullable enable namespace Regorus { /// /// Provides static methods for compiling Azure Policy JSON definitions /// into RVM programs that can be executed by . /// /// /// /// This class bridges the gap between Azure Policy JSON (the native /// Azure policy language with policyRule, field, /// equals, etc.) and Regorus's RVM execution engine. /// /// /// /// Typical workflow: /// /// /// Load alias definitions with and freeze them into an . /// Normalize the ARM resource via . /// Compile the JSON policyRule with or the /// full definition with . /// Execute the resulting in an /// instance with the normalized input. /// /// /// /// Context-dependent policies: Policies that use context functions /// such as subscription(), resourceGroup(), or /// requestContext() require the VM context to be set separately via /// before execution. The context JSON /// returned by is passed as /// input.context but is not automatically wired into the VM's /// ambient context — the caller must do both: /// vm.SetInputJson(envelope) and vm.SetContextJson(contextJson). /// /// public static unsafe class AzurePolicyCompiler { /// /// Compile an Azure Policy JSON policy rule into an RVM . /// /// /// Alias registry for resolving fully-qualified alias names in field /// references. Pass null if no alias resolution is needed. /// /// Warning: When null, alias field references compile as raw /// property paths and will silently produce incorrect evaluation results for /// policies that use aliases. Modify/Append effect policies will also skip /// the compile-time modifiability validation. Only pass null when the /// policy is known to contain no alias references (e.g. simple type/location /// checks or unit-test scenarios). /// /// /// /// JSON string containing the policyRule object, e.g. /// { "if": { "field": "type", "equals": "..." }, "then": { "effect": "deny" } } /// /// /// A compiled ready to be loaded into an /// instance. /// /// /// Thrown when is null. /// /// /// Thrown when parsing or compilation fails. /// public static Program CompilePolicyRule(AliasRegistry? aliasRegistry, string policyRuleJson) { if (policyRuleJson is null) { throw new ArgumentNullException(nameof(policyRuleJson)); } return Utf8Marshaller.WithUtf8(policyRuleJson, rulePtr => { if (aliasRegistry is null) { var result = API.regorus_compile_azure_policy_rule( null, (byte*)rulePtr); return GetProgramResult(result); } else { return aliasRegistry.UseHandleForInterop(regPtr => { var result = API.regorus_compile_azure_policy_rule( (RegorusAliasRegistry*)regPtr, (byte*)rulePtr); return GetProgramResult(result); }); } }); } /// /// Compile a full Azure Policy definition JSON into an RVM . /// /// /// Alias registry for resolving fully-qualified alias names in field /// references. Pass null if no alias resolution is needed. /// /// Warning: When null, alias field references compile as raw /// property paths and will silently produce incorrect evaluation results for /// policies that use aliases. Modify/Append effect policies will also skip /// the compile-time modifiability validation. Only pass null when the /// policy is known to contain no alias references (e.g. simple type/location /// checks or unit-test scenarios). /// /// /// /// JSON string containing the full policy definition, which includes /// policyRule, parameters, displayName, etc. /// Accepted in both wrapped and unwrapped forms. /// /// /// A compiled ready to be loaded into an /// instance. /// /// /// Thrown when is null. /// /// /// Thrown when parsing or compilation fails. /// public static Program CompilePolicyDefinition(AliasRegistry? aliasRegistry, string policyDefinitionJson) { if (policyDefinitionJson is null) { throw new ArgumentNullException(nameof(policyDefinitionJson)); } return Utf8Marshaller.WithUtf8(policyDefinitionJson, defnPtr => { if (aliasRegistry is null) { var result = API.regorus_compile_azure_policy_definition( null, (byte*)defnPtr); return GetProgramResult(result); } else { return aliasRegistry.UseHandleForInterop(regPtr => { var result = API.regorus_compile_azure_policy_definition( (RegorusAliasRegistry*)regPtr, (byte*)defnPtr); return GetProgramResult(result); }); } }); } private static Program GetProgramResult(RegorusResult result) { try { if (result.status != RegorusStatus.Ok) { var message = Utf8Marshaller.FromUtf8(result.error_message); throw result.status.CreateException(message); } if (result.data_type != RegorusDataType.Pointer || result.pointer_value == null) { throw new Exception("Expected program pointer but got different data type"); } var handle = RegorusProgramHandle.FromPointer((IntPtr)result.pointer_value); return new Program(handle); } finally { API.regorus_result_drop(result); } } } }