// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using System.Text; using Regorus.Internal; #nullable enable namespace Regorus { /// /// Provides static methods for managing the global target registry. /// Targets define resource types and their associated schemas for Azure Policy evaluation. /// public static unsafe class TargetRegistry { /// /// Register a target from JSON definition. /// The target JSON should follow the target schema format. /// Once registered, the target can be referenced in Rego policies using `__target__` rules. /// /// JSON encoded target definition /// Thrown when target registration fails public static void RegisterFromJson(string targetJson) { Utf8Marshaller.WithUtf8(targetJson, targetPtr => { unsafe { CheckAndDropResult(Internal.API.regorus_register_target_from_json((byte*)targetPtr)); } }); } /// /// Check if a target is registered. /// /// Name of the target to check /// True if the target is registered, false otherwise /// Thrown when the operation fails public static bool Contains(string name) { return Utf8Marshaller.WithUtf8(name, namePtr => { unsafe { var result = Internal.API.regorus_target_registry_contains((byte*)namePtr); return GetBoolResult(result); } }); } /// /// Get a list of all registered target names. /// /// JSON array of target names /// Thrown when the operation fails public static string ListNames() { return CheckAndDropResult(Internal.API.regorus_target_registry_list_names()) ?? "[]"; } /// /// Remove a target from the registry by name. /// /// The target name to remove /// True if the target was removed, false if it wasn't found /// Thrown when the operation fails public static bool Remove(string name) { return Utf8Marshaller.WithUtf8(name, namePtr => { unsafe { var result = Internal.API.regorus_target_registry_remove((byte*)namePtr); return GetBoolResult(result); } }); } /// /// Clear all targets from the registry. /// /// Thrown when the operation fails public static void Clear() { CheckAndDropResult(Internal.API.regorus_target_registry_clear()); } /// /// Get the number of registered targets. /// /// The number of registered targets /// Thrown when the operation fails public static long Count { get { var result = Internal.API.regorus_target_registry_len(); return GetIntResult(result); } } /// /// Check if the target registry is empty. /// /// True if the registry is empty, false otherwise /// Thrown when the operation fails public static bool IsEmpty { get { var result = Internal.API.regorus_target_registry_is_empty(); return GetBoolResult(result); } } 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 string? CheckAndDropResult(Internal.RegorusResult result) { try { if (result.status != Internal.RegorusStatus.Ok) { var message = StringFromUTF8((IntPtr)result.error_message); throw new Exception(message ?? "Unknown error occurred"); } return result.data_type switch { Internal.RegorusDataType.String => StringFromUTF8((IntPtr)result.output), Internal.RegorusDataType.Boolean => result.bool_value.ToString().ToLowerInvariant(), Internal.RegorusDataType.Integer => result.int_value.ToString(), Internal.RegorusDataType.None => null, _ => StringFromUTF8((IntPtr)result.output) }; } finally { Internal.API.regorus_result_drop(result); } } private static bool GetBoolResult(Internal.RegorusResult result) { try { if (result.status != Internal.RegorusStatus.Ok) { var message = StringFromUTF8((IntPtr)result.error_message); throw new Exception(message ?? "Unknown error occurred"); } return result.data_type == Internal.RegorusDataType.Boolean ? result.bool_value : false; } finally { Internal.API.regorus_result_drop(result); } } private static long GetIntResult(Internal.RegorusResult result) { try { if (result.status != Internal.RegorusStatus.Ok) { var message = StringFromUTF8((IntPtr)result.error_message); throw new Exception(message ?? "Unknown error occurred"); } return result.data_type == Internal.RegorusDataType.Integer ? result.int_value : 0; } finally { Internal.API.regorus_result_drop(result); } } } }