// 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 resource schema registry. /// Resource schemas define the structure and validation rules for Azure Policy resources. /// public static unsafe class SchemaRegistry { /// /// Register a resource schema from JSON with a given name. /// /// Name to register the schema under /// JSON string representing the schema /// Thrown when schema registration fails public static void RegisterResource(string name, string schemaJson) { Utf8Marshaller.WithUtf8(name, namePtr => { Utf8Marshaller.WithUtf8(schemaJson, schemaPtr => { unsafe { CheckAndDropResult(Internal.API.regorus_resource_schema_register((byte*)namePtr, (byte*)schemaPtr)); } }); }); } /// /// Check if a resource schema with the given name exists. /// /// Name of the schema to check /// True if the schema exists, false otherwise /// Thrown when the operation fails public static bool ContainsResource(string name) { return Utf8Marshaller.WithUtf8(name, namePtr => { unsafe { var result = Internal.API.regorus_resource_schema_contains((byte*)namePtr); return GetBoolResult(result); } }); } /// /// Get the number of registered resource schemas. /// /// The number of registered resource schemas /// Thrown when the operation fails public static long ResourceCount { get { var result = Internal.API.regorus_resource_schema_len(); return GetIntResult(result); } } /// /// Check if the resource schema registry is empty. /// /// True if the registry is empty, false otherwise /// Thrown when the operation fails public static bool IsResourceRegistryEmpty { get { var result = Internal.API.regorus_resource_schema_is_empty(); return GetBoolResult(result); } } /// /// List all registered resource schema names. /// /// JSON array of schema names /// Thrown when the operation fails public static string ListResourceNames() { return CheckAndDropResult(Internal.API.regorus_resource_schema_list_names()) ?? "[]"; } /// /// Remove a resource schema by name. /// /// Name of the schema to remove /// True if the schema was removed, false if it wasn't found /// Thrown when the operation fails public static bool RemoveResource(string name) { return Utf8Marshaller.WithUtf8(name, namePtr => { unsafe { var result = Internal.API.regorus_resource_schema_remove((byte*)namePtr); return GetBoolResult(result); } }); } /// /// Clear all resource schemas from the registry. /// /// Thrown when the operation fails public static void ClearResources() { CheckAndDropResult(Internal.API.regorus_resource_schema_clear()); } /// /// Register an effect schema from JSON with a given name. /// /// Name to register the schema under /// JSON string representing the schema /// Thrown when schema registration fails public static void RegisterEffect(string name, string schemaJson) { Utf8Marshaller.WithUtf8(name, namePtr => { Utf8Marshaller.WithUtf8(schemaJson, schemaPtr => { unsafe { CheckAndDropResult(Internal.API.regorus_effect_schema_register((byte*)namePtr, (byte*)schemaPtr)); } }); }); } /// /// Check if an effect schema with the given name exists. /// /// Name of the schema to check /// True if the schema exists, false otherwise /// Thrown when the operation fails public static bool ContainsEffect(string name) { return Utf8Marshaller.WithUtf8(name, namePtr => { unsafe { var result = Internal.API.regorus_effect_schema_contains((byte*)namePtr); return GetBoolResult(result); } }); } /// /// Get the number of registered effect schemas. /// /// The number of registered effect schemas /// Thrown when the operation fails public static long EffectCount { get { var result = Internal.API.regorus_effect_schema_len(); return GetIntResult(result); } } /// /// Check if the effect schema registry is empty. /// /// True if the registry is empty, false otherwise /// Thrown when the operation fails public static bool IsEffectRegistryEmpty { get { var result = Internal.API.regorus_effect_schema_is_empty(); return GetBoolResult(result); } } /// /// List all registered effect schema names. /// /// JSON array of schema names /// Thrown when the operation fails public static string ListEffectNames() { return CheckAndDropResult(Internal.API.regorus_effect_schema_list_names()) ?? "[]"; } /// /// Remove an effect schema by name. /// /// Name of the schema to remove /// True if the schema was removed, false if it wasn't found /// Thrown when the operation fails public static bool RemoveEffect(string name) { return Utf8Marshaller.WithUtf8(name, namePtr => { unsafe { var result = Internal.API.regorus_effect_schema_remove((byte*)namePtr); return GetBoolResult(result); } }); } /// /// Clear all effect schemas from the registry. /// /// Thrown when the operation fails public static void ClearEffects() { CheckAndDropResult(Internal.API.regorus_effect_schema_clear()); } 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); } } } }