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