// 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);
}
}
}
}