mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
feat: Complete target system with C# bindings and resource inference (#458)
* feat: Add Schema Registry and Validation Framework This commit introduces a comprehensive schema registry and validation framework, providing schema-based validation of resources and policy effects. - Thread-safe, in-memory registry for schema storage and management - Global registry patterns for effects and resources - Concurrent access with proper error handling - Unicode schema names support - JSON Schema-compliant validation for all primitive types - Advanced constraint validation (patterns, ranges, length limits) - Discriminated union support with anyOf schemas - Detailed error reporting with nested validation paths - Discriminated subobject validation for polymorphic schemas - **Registry Tests**: All registry operations - **Effect Tests**: Policy effect validation - **Resource Tests**: Resource validation - **Validation Tests**: Core validation engine - Thread-safety, error handling, integration scenarios, edge cases - **Dependencies**: dashmap, once_cell, regex - **Thread Safety**: Minimal locking with Rc<Schema> sharing - **Error Types**: TypeMismatch, OutOfRange, PatternMismatch, etc. - Complete schema registry and validation subsystem - Comprehensive test coverage - Foundation for policy validation in Regorus Benchmarks: - Criterion benchmarks for basic types, effects and Azure resources - Performance range: 3.22ns (string) to 34.74µs (Azure VM resource schema validation) - String withs patterns validation: 30.2µs. Need to explore whether regex caching helps bring this down. - Azure policy effects: 188ns-1.4µs Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com> * feat: Complete target system with C# bindings and resource inference - Add comprehensive target system with TargetRegistry and target-aware compilation - Implement resource type inference from policy equality expressions - Create modular C# bindings with separate wrapper classes for each concept - Add thread-safe CompiledPolicy with reference counting for safe disposal - Enhance FFI with detailed error propagation and target functionality - Create TargetExampleApp demonstrating Azure Policy integration - Add CI/CD pipeline testing for all C# applications - Support target definitions with schema validation and resource selectors - Implement PolicyModule struct and target-aware compilation methods - Add comprehensive test coverage for target functionality Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com> --------- Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
3c33d31d08
commit
cc917ea75d
@@ -43,27 +43,27 @@ int main() {
|
||||
|
||||
// Turn on rego v0 since policy uses v0.
|
||||
r = regorus_engine_set_rego_v0(engine, true);
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
|
||||
// Load policies.
|
||||
r = regorus_engine_add_policy(engine, "framework.rego", (buffer = file_to_string("../../../tests/aci/framework.rego")));
|
||||
free(buffer);
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
printf("Loaded package %s\n", r.output);
|
||||
regorus_result_drop(r);
|
||||
|
||||
r = regorus_engine_add_policy(engine, "api.rego", (buffer = file_to_string("../../../tests/aci/api.rego")));
|
||||
free(buffer);
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
printf("Loaded package %s\n", r.output);
|
||||
regorus_result_drop(r);
|
||||
|
||||
r = regorus_engine_add_policy(engine, "policy.rego", (buffer = file_to_string("../../../tests/aci/policy.rego")));
|
||||
free(buffer);
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
printf("Loaded package %s\n", r.output);
|
||||
regorus_result_drop(r);
|
||||
@@ -71,20 +71,20 @@ int main() {
|
||||
// Add data
|
||||
r = regorus_engine_add_data_json(engine, (buffer = file_to_string("../../../tests/aci/data.json")));
|
||||
free(buffer);
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
regorus_result_drop(r);
|
||||
|
||||
// Set input
|
||||
r = regorus_engine_set_input_json(engine, (buffer = file_to_string("../../../tests/aci/input.json")));
|
||||
free(buffer);
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
regorus_result_drop(r);
|
||||
|
||||
// Eval rule.
|
||||
r = regorus_engine_eval_rule(engine, "data.framework.mount_overlay");
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
|
||||
// Print output
|
||||
|
||||
+10
-10
@@ -8,43 +8,43 @@ int main() {
|
||||
|
||||
// Turn on rego v0 since policy uses v0.
|
||||
r = regorus_engine_set_rego_v0(engine, true);
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
|
||||
// Load policies.
|
||||
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/framework.rego");
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
printf("Loaded package %s\n", r.output);
|
||||
regorus_result_drop(r);
|
||||
|
||||
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/api.rego");
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
printf("Loaded package %s\n", r.output);
|
||||
regorus_result_drop(r);
|
||||
|
||||
r = regorus_engine_add_policy_from_file(engine, "../../../tests/aci/policy.rego");
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
printf("Loaded package %s\n", r.output);
|
||||
regorus_result_drop(r);
|
||||
|
||||
// Add data
|
||||
r = regorus_engine_add_data_from_json_file(engine, "../../../tests/aci/data.json");
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
regorus_result_drop(r);
|
||||
|
||||
// Set input
|
||||
r = regorus_engine_set_input_from_json_file(engine, "../../../tests/aci/input.json");
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
regorus_result_drop(r);
|
||||
|
||||
// Eval rule.
|
||||
r = regorus_engine_eval_query(engine, "data.framework.mount_overlay");
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
|
||||
// Print output
|
||||
@@ -66,14 +66,14 @@ int main() {
|
||||
);
|
||||
|
||||
// Evaluate rule.
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
|
||||
r = regorus_engine_set_enable_coverage(engine, true);
|
||||
regorus_result_drop(r);
|
||||
|
||||
r = regorus_engine_eval_query(engine, "data.test.message");
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
|
||||
// Print output
|
||||
@@ -82,7 +82,7 @@ int main() {
|
||||
|
||||
// Print pretty coverage report.
|
||||
r = regorus_engine_get_coverage_report_pretty(engine);
|
||||
if (r.status != RegorusStatusOk)
|
||||
if (r.status != Ok)
|
||||
goto error;
|
||||
|
||||
printf("%s\n", r.output);
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace regorus {
|
||||
class Result {
|
||||
public:
|
||||
|
||||
operator bool() const { return result.status == RegorusStatus::RegorusStatusOk; }
|
||||
bool operator !() const { return result.status != RegorusStatus::RegorusStatusOk; }
|
||||
operator bool() const { return result.status == RegorusStatus::Ok; }
|
||||
bool operator !() const { return result.status != RegorusStatus::Ok; }
|
||||
|
||||
const char* output() const {
|
||||
if (*this && result.output) {
|
||||
|
||||
@@ -0,0 +1,421 @@
|
||||
# Regorus C# API Documentation
|
||||
|
||||
This document describes the C# API for Regorus, focusing on the compiled policy approach for high-performance policy evaluation.
|
||||
|
||||
## Overview
|
||||
|
||||
The Regorus C# bindings provide a modern, thread-safe API for compiling and evaluating Open Policy Agent (OPA) Rego policies. The API is designed around pre-compiled policies that can be evaluated efficiently multiple times with different inputs.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ CompiledPolicy Workflow │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
||||
│ Policy Modules │ │ Target/Schema │ │ Static Data │
|
||||
│ (.rego files) │ │ Registries │ │ (JSON) │
|
||||
└─────────┬───────┘ └────────┬─────────┘ └─────────┬───────┘
|
||||
│ │ │
|
||||
└─────────────────────┼────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────┐
|
||||
│ Compile │
|
||||
│ ┌─────────────────────┐│
|
||||
│ │ Parse & Analyze ││
|
||||
│ │ Infer Resource Types││
|
||||
│ │ Build AST & Rules ││
|
||||
│ │ Target Integration ││
|
||||
│ └─────────────────────┘│
|
||||
└─────────────┬───────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────┐
|
||||
│ CompiledPolicy │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ AST & Rules │ │
|
||||
│ │ Target Info │ │
|
||||
│ │ Resource Types │ │
|
||||
│ │ Function Table │ │
|
||||
│ │ Compiled Modules │ │
|
||||
│ └─────────────────────┘ │
|
||||
└─────────────┬───────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ Service Cache │
|
||||
│ (Policy Framework, │
|
||||
│ MS Graph, etc.) │
|
||||
│ ┌─────────────────┐ │
|
||||
│ │ CompiledPolicy │ │ ◄─── Same LOCK-FREE policy
|
||||
│ │ (cached) │ │ instance shared across
|
||||
│ └─────────────────┘ │ all threads
|
||||
└─────────┬───────────┘
|
||||
│
|
||||
┌───────┼───────┬───────┐
|
||||
│ │ │ │
|
||||
▼ ▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Thread 1 │ │ Thread 2 │ │ Thread N │
|
||||
│ │ │ │ │ │
|
||||
│ input1 ────▶│ │ input2 ────▶│ │ inputN ────▶│
|
||||
│ ◄─── result │ │ ◄─── result │ │ ◄─── result │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Key Benefits │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ ✓ Compile Once, Evaluate Many ✓ Lock-Free Concurrent Eval │
|
||||
│ ✓ No Re-parsing Overhead ✓ Reference Counting Safety │
|
||||
│ ✓ Reduced GC Pressure ✓ Proper Resource Management │
|
||||
│ ✓ Cache-Friendly Design ✓ Target System Integration │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Pre-compiled Policies**: Compile once, evaluate many times for optimal performance
|
||||
- **Target System Support**: Built-in support for Azure Policy targets with resource type inference
|
||||
- **Thread Safety**: All operations are thread-safe without external synchronization
|
||||
- **Registry Management**: Centralized management of targets and schemas
|
||||
- **Policy Introspection**: Rich metadata about compiled policies
|
||||
|
||||
## Core Classes
|
||||
|
||||
### CompiledPolicy
|
||||
|
||||
The `CompiledPolicy` class represents a pre-compiled Rego policy that can be evaluated efficiently.
|
||||
|
||||
```csharp
|
||||
public sealed class CompiledPolicy : IDisposable
|
||||
{
|
||||
// Evaluate the policy with input data
|
||||
public string? EvalWithInput(string inputJson);
|
||||
|
||||
// Get comprehensive policy metadata
|
||||
public PolicyInfo GetPolicyInfo();
|
||||
|
||||
// Dispose of unmanaged resources
|
||||
public void Dispose();
|
||||
}
|
||||
```
|
||||
|
||||
**Thread Safety**: All methods are thread-safe. Multiple threads can call `EvalWithInput()` concurrently, and `Dispose()` will safely wait for active evaluations to complete.
|
||||
|
||||
### Compiler
|
||||
|
||||
The `Compiler` class provides static methods for compiling policies.
|
||||
|
||||
```csharp
|
||||
public static class Compiler
|
||||
{
|
||||
// Compile a policy with a specific entrypoint rule
|
||||
public static CompiledPolicy CompilePolicyWithEntrypoint(
|
||||
string dataJson,
|
||||
IEnumerable<PolicyModule> modules,
|
||||
string entryPointRule);
|
||||
|
||||
// Compile a target-aware policy (requires azure_policy feature)
|
||||
public static CompiledPolicy CompilePolicyForTarget(
|
||||
string dataJson,
|
||||
IEnumerable<PolicyModule> modules);
|
||||
}
|
||||
```
|
||||
|
||||
### PolicyModule
|
||||
|
||||
Represents a single policy module to be compiled. Each PolicyModule corresponds to a Rego file (.rego), and each Rego file defines a Rego package using the `package` declaration at the top of the file.
|
||||
|
||||
```csharp
|
||||
public struct PolicyModule
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Content { get; set; }
|
||||
|
||||
public PolicyModule(string id, string content);
|
||||
}
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
- `Id`: A unique identifier for the module, typically the filename (e.g., "policy.rego", "rules/storage.rego")
|
||||
- `Content`: The complete Rego policy content, including the `package` declaration and all rules
|
||||
|
||||
**Example:**
|
||||
```csharp
|
||||
var module = new PolicyModule("storage-policy.rego", @"
|
||||
package azure.storage
|
||||
import rego.v1
|
||||
|
||||
default allow := false
|
||||
allow if input.type == ""Microsoft.Storage/storageAccounts""
|
||||
");
|
||||
```
|
||||
|
||||
### PolicyInfo
|
||||
|
||||
Provides comprehensive metadata about a compiled policy.
|
||||
|
||||
```csharp
|
||||
public class PolicyInfo
|
||||
{
|
||||
// List of module identifiers
|
||||
public List<string> ModuleIds { get; set; }
|
||||
|
||||
// Target name (for target-aware policies)
|
||||
public string? TargetName { get; set; }
|
||||
|
||||
// Resource types this policy can evaluate
|
||||
public List<string> ApplicableResourceTypes { get; set; }
|
||||
|
||||
// Primary rule/entrypoint
|
||||
public string EntrypointRule { get; set; }
|
||||
|
||||
// Effect rule (for target-aware policies)
|
||||
public string? EffectRule { get; set; }
|
||||
|
||||
// Policy parameters
|
||||
public List<PolicyParameters> Parameters { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
## Registry Classes
|
||||
|
||||
### TargetRegistry
|
||||
|
||||
Manages target definitions for Azure Policy-style evaluations.
|
||||
|
||||
```csharp
|
||||
public static class TargetRegistry
|
||||
{
|
||||
// Register a target from JSON
|
||||
public static void RegisterFromJson(string targetJson);
|
||||
|
||||
// Check if a target exists
|
||||
public static bool Contains(string name);
|
||||
|
||||
// List all registered targets
|
||||
public static string ListNames();
|
||||
|
||||
// Remove a target
|
||||
public static bool Remove(string name);
|
||||
|
||||
// Clear all targets
|
||||
public static void Clear();
|
||||
|
||||
// Get count of registered targets
|
||||
public static int Count { get; }
|
||||
|
||||
// Check if registry is empty
|
||||
public static bool IsEmpty { get; }
|
||||
}
|
||||
```
|
||||
|
||||
### SchemaRegistry
|
||||
|
||||
Manages schema definitions for validation.
|
||||
|
||||
```csharp
|
||||
public static class SchemaRegistry
|
||||
{
|
||||
// Register resource schemas
|
||||
public static void RegisterResourceSchema(string name, string schemaJson);
|
||||
public static bool ContainsResourceSchema(string name);
|
||||
public static string ListResourceSchemas();
|
||||
|
||||
// Register effect schemas
|
||||
public static void RegisterEffectSchema(string name, string schemaJson);
|
||||
public static bool ContainsEffectSchema(string name);
|
||||
public static string ListEffectSchemas();
|
||||
|
||||
// Clear methods
|
||||
public static void ClearResourceSchemas();
|
||||
public static void ClearEffectSchemas();
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Policy Compilation and Evaluation
|
||||
|
||||
```csharp
|
||||
// Define policy modules
|
||||
var modules = new List<PolicyModule>
|
||||
{
|
||||
new PolicyModule("policy.rego", @"
|
||||
package example
|
||||
import rego.v1
|
||||
|
||||
default allow := false
|
||||
allow if input.user == ""admin""
|
||||
")
|
||||
};
|
||||
|
||||
// Compile the policy
|
||||
using var policy = Compiler.CompilePolicyWithEntrypoint("{}", modules, "data.example.allow");
|
||||
|
||||
// Evaluate with different inputs
|
||||
var result1 = policy.EvalWithInput(@"{""user"": ""admin""}"); // true
|
||||
var result2 = policy.EvalWithInput(@"{""user"": ""guest""}"); // false
|
||||
```
|
||||
|
||||
### Target-Aware Policy (Azure Policy Style)
|
||||
|
||||
```csharp
|
||||
// Register target definition
|
||||
TargetRegistry.RegisterFromJson(@"{
|
||||
""name"": ""azure.storage"",
|
||||
""resource_schema_selector"": ""type"",
|
||||
""resource_types"": {
|
||||
""Microsoft.Storage/storageAccounts"": {
|
||||
""schema"": { /* JSON Schema */ }
|
||||
}
|
||||
}
|
||||
}");
|
||||
|
||||
// Define policy with target
|
||||
var modules = new List<PolicyModule>
|
||||
{
|
||||
new PolicyModule("policy.rego", @"
|
||||
package policy
|
||||
import rego.v1
|
||||
|
||||
__target__ := ""azure.storage""
|
||||
|
||||
default effect := ""deny""
|
||||
effect := ""allow"" if {
|
||||
input.type == ""Microsoft.Storage/storageAccounts""
|
||||
input.properties.supportsHttpsTrafficOnly == true
|
||||
}
|
||||
")
|
||||
};
|
||||
|
||||
// Compile for target
|
||||
using var policy = Compiler.CompilePolicyForTarget("{}", modules);
|
||||
|
||||
// Evaluate Azure resource
|
||||
var resource = @"{
|
||||
""type"": ""Microsoft.Storage/storageAccounts"",
|
||||
""properties"": {
|
||||
""supportsHttpsTrafficOnly"": true
|
||||
}
|
||||
}";
|
||||
|
||||
var result = policy.EvalWithInput(resource); // "allow"
|
||||
```
|
||||
|
||||
### Policy Introspection
|
||||
|
||||
```csharp
|
||||
// Get policy metadata
|
||||
var info = policy.GetPolicyInfo();
|
||||
|
||||
Console.WriteLine($"Target: {info.TargetName}");
|
||||
Console.WriteLine($"Effect Rule: {info.EffectRule}");
|
||||
Console.WriteLine($"Modules: {string.Join(", ", info.ModuleIds)}");
|
||||
Console.WriteLine($"Resource Types: {string.Join(", ", info.ApplicableResourceTypes)}");
|
||||
|
||||
// Access parameters
|
||||
if (info.Parameters != null && info.Parameters.Count > 0)
|
||||
{
|
||||
foreach (var parameterSet in info.Parameters)
|
||||
{
|
||||
Console.WriteLine($"Module: {parameterSet.SourceFile}");
|
||||
foreach (var param in parameterSet.Parameters)
|
||||
{
|
||||
Console.WriteLine($"Parameter: {param.Name} ({param.Type})");
|
||||
if (param.Default != null)
|
||||
Console.WriteLine($" Default: {param.Default}");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Concurrent Evaluation
|
||||
|
||||
```csharp
|
||||
// CompiledPolicy is thread-safe
|
||||
var tasks = Enumerable.Range(0, 100).Select(i =>
|
||||
Task.Run(() => policy.EvalWithInput($@"{{""id"": {i}}}"))
|
||||
).ToArray();
|
||||
|
||||
var results = await Task.WhenAll(tasks);
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Compilation Overhead
|
||||
|
||||
- Policy compilation has significant overhead due to parsing and analysis
|
||||
- **Best Practice**: Compile once, reuse many times
|
||||
- Consider caching compiled policies for repeated use
|
||||
|
||||
### Memory Management
|
||||
|
||||
- `CompiledPolicy` manages unmanaged resources
|
||||
- **Always** dispose of compiled policies using `using` statements or explicit `Dispose()`
|
||||
- Disposal is thread-safe and waits for active evaluations
|
||||
|
||||
### Thread Safety
|
||||
|
||||
- All classes are thread-safe for concurrent reads/evaluations
|
||||
- Registry modifications should be done during initialization
|
||||
- No external synchronization required
|
||||
|
||||
## Error Handling
|
||||
|
||||
All methods throw `Exception` on errors with descriptive messages:
|
||||
|
||||
```csharp
|
||||
try
|
||||
{
|
||||
var policy = Compiler.CompilePolicyWithEntrypoint(data, modules, rule);
|
||||
var result = policy.EvalWithInput(input);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
}
|
||||
```
|
||||
|
||||
## Feature Flags
|
||||
|
||||
Some functionality requires specific Rust feature flags:
|
||||
|
||||
- **azure_policy**: Required for target-aware compilation and policy parameters
|
||||
- Without this feature, target-related methods will not be available
|
||||
|
||||
## Version Compatibility
|
||||
|
||||
- Requires .NET Standard 2.0 or later
|
||||
- Compatible with .NET Framework 4.6.1+, .NET Core 2.0+, .NET 5+
|
||||
- Uses System.Text.Json for JSON serialization (added as dependency)
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Compile Once, Evaluate Many**: Pre-compile policies for repeated evaluation
|
||||
2. **Use Disposable Pattern**: Always dispose of CompiledPolicy instances
|
||||
3. **Thread-Safe Design**: Take advantage of built-in thread safety
|
||||
4. **Registry Setup**: Configure targets and schemas during application startup
|
||||
5. **Error Handling**: Wrap operations in try-catch blocks for robust error handling
|
||||
6. **Performance Monitoring**: Monitor evaluation times for performance optimization
|
||||
|
||||
## Migration from Engine-Based API
|
||||
|
||||
If migrating from an engine-based approach:
|
||||
|
||||
```csharp
|
||||
// Old approach (if it existed)
|
||||
// var engine = new Engine();
|
||||
// engine.AddPolicy("policy.rego", policyContent);
|
||||
// engine.SetInputJson(inputJson);
|
||||
// var result = engine.EvalRule("data.policy.allow");
|
||||
|
||||
// New compiled approach
|
||||
var modules = new[] { new PolicyModule("policy.rego", policyContent) };
|
||||
using var policy = Compiler.CompilePolicyWithEntrypoint("{}", modules, "data.policy.allow");
|
||||
var result = policy.EvalWithInput(inputJson);
|
||||
```
|
||||
|
||||
The compiled approach provides better performance for repeated evaluations and clearer resource management.
|
||||
@@ -0,0 +1,168 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
#nullable enable
|
||||
namespace Regorus
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a compiled Regorus policy that can be evaluated efficiently.
|
||||
/// This class wraps a pre-compiled policy that can be evaluated multiple times
|
||||
/// with different inputs without recompilation overhead.
|
||||
///
|
||||
/// This class manages unmanaged resources and should not be copied or cloned.
|
||||
/// Each instance represents a unique native policy object.
|
||||
///
|
||||
/// Thread Safety: This class is thread-safe for all operations. Multiple threads
|
||||
/// can safely call EvalWithInput() concurrently, and Dispose() will safely wait
|
||||
/// for all active evaluations to complete before freeing resources. No external
|
||||
/// synchronization is required.
|
||||
/// </summary>
|
||||
public unsafe sealed class CompiledPolicy : IDisposable
|
||||
{
|
||||
private Internal.RegorusCompiledPolicy* _policy;
|
||||
private int _isDisposed;
|
||||
private int _activeEvaluations;
|
||||
|
||||
internal CompiledPolicy(Internal.RegorusCompiledPolicy* policy)
|
||||
{
|
||||
_policy = policy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the compiled policy with the given input.
|
||||
/// For target policies, evaluates the target's effect rule.
|
||||
/// For regular policies, evaluates the originally compiled rule.
|
||||
/// </summary>
|
||||
/// <param name="inputJson">JSON encoded input data (resource) to validate against the policy</param>
|
||||
/// <returns>The evaluation result as JSON string</returns>
|
||||
/// <exception cref="Exception">Thrown when policy evaluation fails</exception>
|
||||
/// <exception cref="ObjectDisposedException">Thrown when the policy has been disposed</exception>
|
||||
public string? EvalWithInput(string inputJson)
|
||||
{
|
||||
// Increment active evaluations count
|
||||
System.Threading.Interlocked.Increment(ref _activeEvaluations);
|
||||
try
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
var inputBytes = Encoding.UTF8.GetBytes(inputJson + char.MinValue);
|
||||
fixed (byte* inputPtr = inputBytes)
|
||||
{
|
||||
return CheckAndDropResult(Internal.API.regorus_compiled_policy_eval_with_input(_policy, inputPtr));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Decrement active evaluations count
|
||||
System.Threading.Interlocked.Decrement(ref _activeEvaluations);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the compiled policy including metadata about modules,
|
||||
/// target configuration, and resource types.
|
||||
/// </summary>
|
||||
/// <returns>Policy information containing module IDs, target name, applicable resource types, entry point rule, and parameters</returns>
|
||||
/// <exception cref="Exception">Thrown when getting policy info fails</exception>
|
||||
/// <exception cref="ObjectDisposedException">Thrown when the policy has been disposed</exception>
|
||||
public PolicyInfo GetPolicyInfo()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
var jsonResult = CheckAndDropResult(Internal.API.regorus_compiled_policy_get_policy_info(_policy));
|
||||
|
||||
if (string.IsNullOrEmpty(jsonResult))
|
||||
{
|
||||
throw new Exception("Failed to get policy info: empty response");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
return JsonSerializer.Deserialize<PolicyInfo>(jsonResult!, options)
|
||||
?? throw new Exception("Failed to deserialize policy info");
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
throw new Exception($"Failed to parse policy info JSON: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (System.Threading.Interlocked.CompareExchange(ref _isDisposed, 1, 0) == 0)
|
||||
{
|
||||
if (_policy != null)
|
||||
{
|
||||
// Wait for all active evaluations to complete
|
||||
while (System.Threading.Volatile.Read(ref _activeEvaluations) > 0)
|
||||
{
|
||||
System.Threading.Thread.Yield();
|
||||
}
|
||||
|
||||
Internal.API.regorus_compiled_policy_drop(_policy);
|
||||
_policy = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~CompiledPolicy() => Dispose(disposing: false);
|
||||
|
||||
private void ThrowIfDisposed()
|
||||
{
|
||||
if (_isDisposed != 0)
|
||||
throw new ObjectDisposedException(nameof(CompiledPolicy));
|
||||
}
|
||||
|
||||
private 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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
#nullable enable
|
||||
namespace Regorus
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a policy module with an ID and content.
|
||||
/// </summary>
|
||||
public struct PolicyModule
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the unique identifier for this policy module.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Rego policy content.
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PolicyModule struct.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for this policy module</param>
|
||||
/// <param name="content">The Rego policy content</param>
|
||||
public PolicyModule(string id, string content)
|
||||
{
|
||||
Id = id;
|
||||
Content = content;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides static methods for compiling policies into efficient compiled representations.
|
||||
/// These are convenience methods that create an engine internally and perform compilation.
|
||||
/// </summary>
|
||||
public static unsafe class Compiler
|
||||
{
|
||||
/// <summary>
|
||||
/// Compiles a policy from data and modules with a specific entry point rule.
|
||||
/// This is a convenience function that sets up an Engine internally and calls the appropriate compilation method.
|
||||
/// </summary>
|
||||
/// <param name="dataJson">JSON string containing static data for policy evaluation</param>
|
||||
/// <param name="modules">List of policy modules to compile</param>
|
||||
/// <param name="entryPointRule">The specific rule path to evaluate (e.g., "data.policy.allow")</param>
|
||||
/// <returns>A compiled policy that can be evaluated efficiently</returns>
|
||||
/// <exception cref="Exception">Thrown when compilation fails</exception>
|
||||
public static CompiledPolicy CompilePolicyWithEntrypoint(string dataJson, IEnumerable<PolicyModule> modules, string entryPointRule)
|
||||
{
|
||||
var dataBytes = Encoding.UTF8.GetBytes(dataJson + char.MinValue);
|
||||
var entryPointBytes = Encoding.UTF8.GetBytes(entryPointRule + char.MinValue);
|
||||
var modulesArray = modules.ToArray();
|
||||
|
||||
// Convert C# modules to native structs
|
||||
var nativeModules = new Internal.RegorusPolicyModule[modulesArray.Length];
|
||||
var pinnedHandles = new List<GCHandle>();
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < modulesArray.Length; i++)
|
||||
{
|
||||
var idBytes = Encoding.UTF8.GetBytes(modulesArray[i].Id + char.MinValue);
|
||||
var contentBytes = Encoding.UTF8.GetBytes(modulesArray[i].Content + char.MinValue);
|
||||
|
||||
var idHandle = GCHandle.Alloc(idBytes, GCHandleType.Pinned);
|
||||
var contentHandle = GCHandle.Alloc(contentBytes, GCHandleType.Pinned);
|
||||
pinnedHandles.Add(idHandle);
|
||||
pinnedHandles.Add(contentHandle);
|
||||
|
||||
nativeModules[i] = new Internal.RegorusPolicyModule
|
||||
{
|
||||
id = (byte*)idHandle.AddrOfPinnedObject(),
|
||||
content = (byte*)contentHandle.AddrOfPinnedObject()
|
||||
};
|
||||
}
|
||||
|
||||
fixed (byte* dataPtr = dataBytes)
|
||||
fixed (byte* entryPointPtr = entryPointBytes)
|
||||
fixed (Internal.RegorusPolicyModule* modulesPtr = nativeModules)
|
||||
{
|
||||
var result = Internal.API.regorus_compile_policy_with_entrypoint(
|
||||
dataPtr, modulesPtr, (UIntPtr)modulesArray.Length, entryPointPtr);
|
||||
|
||||
var policy = GetCompiledPolicyResult(result);
|
||||
return policy;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var handle in pinnedHandles)
|
||||
{
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compiles a target-aware policy from data and modules.
|
||||
/// This is a convenience function that sets up an Engine internally and calls target-aware compilation.
|
||||
/// At least one module must contain a `__target__` declaration.
|
||||
/// </summary>
|
||||
/// <param name="dataJson">JSON string containing static data for policy evaluation</param>
|
||||
/// <param name="modules">List of policy modules to compile</param>
|
||||
/// <returns>A compiled policy that can be evaluated efficiently</returns>
|
||||
/// <exception cref="Exception">Thrown when compilation fails</exception>
|
||||
public static CompiledPolicy CompilePolicyForTarget(string dataJson, IEnumerable<PolicyModule> modules)
|
||||
{
|
||||
var dataBytes = Encoding.UTF8.GetBytes(dataJson + char.MinValue);
|
||||
var modulesArray = modules.ToArray();
|
||||
|
||||
// Convert C# modules to native structs
|
||||
var nativeModules = new Internal.RegorusPolicyModule[modulesArray.Length];
|
||||
var pinnedHandles = new List<GCHandle>();
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < modulesArray.Length; i++)
|
||||
{
|
||||
var idBytes = Encoding.UTF8.GetBytes(modulesArray[i].Id + char.MinValue);
|
||||
var contentBytes = Encoding.UTF8.GetBytes(modulesArray[i].Content + char.MinValue);
|
||||
|
||||
var idHandle = GCHandle.Alloc(idBytes, GCHandleType.Pinned);
|
||||
var contentHandle = GCHandle.Alloc(contentBytes, GCHandleType.Pinned);
|
||||
pinnedHandles.Add(idHandle);
|
||||
pinnedHandles.Add(contentHandle);
|
||||
|
||||
nativeModules[i] = new Internal.RegorusPolicyModule
|
||||
{
|
||||
id = (byte*)idHandle.AddrOfPinnedObject(),
|
||||
content = (byte*)contentHandle.AddrOfPinnedObject()
|
||||
};
|
||||
}
|
||||
|
||||
fixed (byte* dataPtr = dataBytes)
|
||||
fixed (Internal.RegorusPolicyModule* modulesPtr = nativeModules)
|
||||
{
|
||||
var result = Internal.API.regorus_compile_policy_for_target(
|
||||
dataPtr, modulesPtr, (UIntPtr)modulesArray.Length);
|
||||
|
||||
var policy = GetCompiledPolicyResult(result);
|
||||
return policy;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var handle in pinnedHandles)
|
||||
{
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 CompiledPolicy GetCompiledPolicyResult(Internal.RegorusResult result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (result.status != Internal.RegorusStatus.Ok)
|
||||
{
|
||||
var message = StringFromUTF8((IntPtr)result.error_message);
|
||||
throw new Exception(message ?? "Unknown compilation error occurred");
|
||||
}
|
||||
|
||||
if (result.data_type != Internal.RegorusDataType.Pointer || result.pointer_value == null)
|
||||
{
|
||||
throw new Exception("Expected compiled policy pointer but got different data type");
|
||||
}
|
||||
|
||||
return new CompiledPolicy((Internal.RegorusCompiledPolicy*)result.pointer_value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Internal.API.regorus_result_drop(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,7 +243,7 @@ namespace Regorus
|
||||
|
||||
string? CheckAndDropResult(Regorus.Internal.RegorusResult result)
|
||||
{
|
||||
if (result.status != Regorus.Internal.RegorusStatus.RegorusStatusOk)
|
||||
if (result.status != Regorus.Internal.RegorusStatus.Ok)
|
||||
{
|
||||
var message = StringFromUTF8((IntPtr)result.error_message);
|
||||
var ex = new Exception(message);
|
||||
@@ -0,0 +1,546 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable CS8500
|
||||
#pragma warning disable CS8981
|
||||
|
||||
namespace Regorus.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Native FFI method declarations for Regorus.
|
||||
/// This file contains all P/Invoke declarations for the Regorus native library.
|
||||
/// </summary>
|
||||
internal static unsafe partial class API
|
||||
{
|
||||
private const string LibraryName = "regorus_ffi";
|
||||
|
||||
#region Common Methods
|
||||
|
||||
/// <summary>
|
||||
/// Drop a RegorusResult.
|
||||
/// output and error_message strings are not valid after drop.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_result_drop", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern void regorus_result_drop(RegorusResult result);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Engine Methods
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new Engine.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusEngine* regorus_engine_new();
|
||||
|
||||
/// <summary>
|
||||
/// Clone a RegorusEngine.
|
||||
/// To avoid having to parse same policy again, the engine can be cloned
|
||||
/// after policies and data have been added.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusEngine* regorus_engine_clone(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Drop a RegorusEngine.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_drop", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern void regorus_engine_drop(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Add a policy.
|
||||
/// The policy is parsed into AST.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_policy
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_add_policy", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_add_policy(RegorusEngine* engine, byte* path, byte* rego);
|
||||
|
||||
/// <summary>
|
||||
/// Add a policy from file.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_add_policy_from_file", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_add_policy_from_file(RegorusEngine* engine, byte* path);
|
||||
|
||||
/// <summary>
|
||||
/// Add policy data.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_data
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_add_data_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_add_data_json(RegorusEngine* engine, byte* data);
|
||||
|
||||
/// <summary>
|
||||
/// Get list of loaded Rego packages as JSON.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_packages
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_get_packages", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_packages(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Get list of policies as JSON.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_get_policies", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_policies(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Add data from JSON file.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_add_data_from_json_file", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_add_data_from_json_file(RegorusEngine* engine, byte* path);
|
||||
|
||||
/// <summary>
|
||||
/// Clear policy data.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_data
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_clear_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_clear_data(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Set input.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_input
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_set_input_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_input_json(RegorusEngine* engine, byte* input);
|
||||
|
||||
/// <summary>
|
||||
/// Set input from JSON file.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_set_input_from_json_file", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_input_from_json_file(RegorusEngine* engine, byte* path);
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate query.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_query
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_eval_query", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_eval_query(RegorusEngine* engine, byte* query);
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate specified rule.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_rule
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_eval_rule", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_eval_rule(RegorusEngine* engine, byte* rule);
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable coverage.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_set_enable_coverage", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_enable_coverage(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool enable);
|
||||
|
||||
/// <summary>
|
||||
/// Get coverage report.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_get_coverage_report", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_coverage_report(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable strict builtin errors.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_strict_builtin_errors
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_set_strict_builtin_errors", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_strict_builtin_errors(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool strict);
|
||||
|
||||
/// <summary>
|
||||
/// Get pretty printed coverage report.
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Report.html#method.to_string_pretty
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_get_coverage_report_pretty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_coverage_report_pretty(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Clear coverage data.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_coverage_data
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_clear_coverage_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_clear_coverage_data(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Whether to gather output of print statements.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_gather_prints
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_set_gather_prints", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_gather_prints(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool enable);
|
||||
|
||||
/// <summary>
|
||||
/// Take all the gathered print statements.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.take_prints
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_take_prints", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_take_prints(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Get AST of policies.
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_ast_as_json
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_get_ast_as_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_ast_as_json(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the package names defined in each policy added to the engine.
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_policy_package_names
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_get_policy_package_names", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_policy_package_names(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameters defined in each policy added to the engine.
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_policy_parameters
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_get_policy_parameters", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_policy_parameters(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable rego v1.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_rego_v0
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_set_rego_v0", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_rego_v0(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool enable);
|
||||
|
||||
/// <summary>
|
||||
/// Compile a target-aware policy from the current engine state.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.compile_for_target
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_compile_for_target", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_compile_for_target(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Compile a policy with a specific entry point rule.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.compile_with_entrypoint
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_engine_compile_with_entrypoint", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_compile_with_entrypoint(RegorusEngine* engine, byte* rule);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Compilation Methods
|
||||
|
||||
/// <summary>
|
||||
/// Compiles a policy from data and modules with a specific entry point rule.
|
||||
/// This is a convenience function that wraps regorus::compile_policy_with_entrypoint.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_compile_policy_with_entrypoint", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_compile_policy_with_entrypoint(byte* data_json, RegorusPolicyModule* modules, UIntPtr modules_len, byte* entry_point_rule);
|
||||
|
||||
/// <summary>
|
||||
/// Compiles a target-aware policy from data and modules.
|
||||
/// This is a convenience function that wraps regorus::compile_policy_for_target.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_compile_policy_for_target", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_compile_policy_for_target(byte* data_json, RegorusPolicyModule* modules, UIntPtr modules_len);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Compiled Policy Methods
|
||||
|
||||
/// <summary>
|
||||
/// Drop a RegorusCompiledPolicy.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_compiled_policy_drop", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern void regorus_compiled_policy_drop(RegorusCompiledPolicy* compiled_policy);
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate the compiled policy with the given input.
|
||||
/// For target policies, evaluates the target's effect rule.
|
||||
/// For regular policies, evaluates the originally compiled rule.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_compiled_policy_eval_with_input", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_compiled_policy_eval_with_input(RegorusCompiledPolicy* compiled_policy, byte* input);
|
||||
|
||||
/// <summary>
|
||||
/// Get information about the compiled policy including metadata about modules,
|
||||
/// target configuration, and resource types.
|
||||
/// Returns a JSON-encoded PolicyInfo struct containing comprehensive
|
||||
/// information about the compiled policy such as module IDs, target name,
|
||||
/// applicable resource types, entry point rule, and parameters.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_compiled_policy_get_policy_info", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_compiled_policy_get_policy_info(RegorusCompiledPolicy* compiled_policy);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Target Registry Methods
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_register_target_from_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_register_target_from_json(byte* target_json);
|
||||
|
||||
/// <summary>
|
||||
/// Check if a target is registered.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_target_registry_contains", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_target_registry_contains(byte* name);
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all registered target names as JSON array.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_target_registry_list_names", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_target_registry_list_names();
|
||||
|
||||
/// <summary>
|
||||
/// Remove a target from the registry by name.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_target_registry_remove", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_target_registry_remove(byte* name);
|
||||
|
||||
/// <summary>
|
||||
/// Clear all targets from the registry.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_target_registry_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_target_registry_clear();
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of registered targets.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_target_registry_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_target_registry_len();
|
||||
|
||||
/// <summary>
|
||||
/// Check if the target registry is empty.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_target_registry_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_target_registry_is_empty();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Resource Schema Registry Methods
|
||||
|
||||
/// <summary>
|
||||
/// Register a resource schema from JSON with a given name.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_resource_schema_register", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_resource_schema_register(byte* name, byte* schema_json);
|
||||
|
||||
/// <summary>
|
||||
/// Check if a resource schema with the given name exists.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_resource_schema_contains", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_resource_schema_contains(byte* name);
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of registered resource schemas.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_resource_schema_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_resource_schema_len();
|
||||
|
||||
/// <summary>
|
||||
/// Check if the resource schema registry is empty.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_resource_schema_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_resource_schema_is_empty();
|
||||
|
||||
/// <summary>
|
||||
/// List all registered resource schema names as a JSON array.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_resource_schema_list_names", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_resource_schema_list_names();
|
||||
|
||||
/// <summary>
|
||||
/// Remove a resource schema by name.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_resource_schema_remove", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_resource_schema_remove(byte* name);
|
||||
|
||||
/// <summary>
|
||||
/// Clear all resource schemas from the registry.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_resource_schema_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_resource_schema_clear();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Effect Schema Registry Methods
|
||||
|
||||
/// <summary>
|
||||
/// Register an effect schema from JSON with a given name.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_effect_schema_register", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_effect_schema_register(byte* name, byte* schema_json);
|
||||
|
||||
/// <summary>
|
||||
/// Check if an effect schema with the given name exists.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_effect_schema_contains", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_effect_schema_contains(byte* name);
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of registered effect schemas.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_effect_schema_len", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_effect_schema_len();
|
||||
|
||||
/// <summary>
|
||||
/// Check if the effect schema registry is empty.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_effect_schema_is_empty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_effect_schema_is_empty();
|
||||
|
||||
/// <summary>
|
||||
/// List all registered effect schema names as a JSON array.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_effect_schema_list_names", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_effect_schema_list_names();
|
||||
|
||||
/// <summary>
|
||||
/// Remove an effect schema by name.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_effect_schema_remove", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_effect_schema_remove(byte* name);
|
||||
|
||||
/// <summary>
|
||||
/// Clear all effect schemas from the registry.
|
||||
/// </summary>
|
||||
[DllImport(LibraryName, EntryPoint = "regorus_effect_schema_clear", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_effect_schema_clear();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region Native Structures
|
||||
|
||||
/// <summary>
|
||||
/// Type of data contained in RegorusResult.
|
||||
/// </summary>
|
||||
internal enum RegorusDataType : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// No data / void.
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// String data (output field is valid).
|
||||
/// </summary>
|
||||
String,
|
||||
/// <summary>
|
||||
/// Boolean data (bool_value field is valid).
|
||||
/// </summary>
|
||||
Boolean,
|
||||
/// <summary>
|
||||
/// Integer data (int_value field is valid).
|
||||
/// </summary>
|
||||
Integer,
|
||||
/// <summary>
|
||||
/// Pointer data (pointer_value field is valid).
|
||||
/// </summary>
|
||||
Pointer,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Status of a call on RegorusEngine.
|
||||
/// </summary>
|
||||
internal enum RegorusStatus : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// The operation was successful.
|
||||
/// </summary>
|
||||
Ok,
|
||||
/// <summary>
|
||||
/// The operation was unsuccessful.
|
||||
/// </summary>
|
||||
Error,
|
||||
/// <summary>
|
||||
/// Invalid data format provided.
|
||||
/// </summary>
|
||||
InvalidDataFormat,
|
||||
/// <summary>
|
||||
/// Invalid entrypoint rule specified.
|
||||
/// </summary>
|
||||
InvalidEntrypoint,
|
||||
/// <summary>
|
||||
/// Compilation failed.
|
||||
/// </summary>
|
||||
CompilationFailed,
|
||||
/// <summary>
|
||||
/// Invalid argument provided.
|
||||
/// </summary>
|
||||
InvalidArgument,
|
||||
/// <summary>
|
||||
/// Invalid module ID.
|
||||
/// </summary>
|
||||
InvalidModuleId,
|
||||
/// <summary>
|
||||
/// Invalid policy content.
|
||||
/// </summary>
|
||||
InvalidPolicy,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of a call on RegorusEngine.
|
||||
/// Must be freed using regorus_result_drop.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe partial struct RegorusResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Status.
|
||||
/// </summary>
|
||||
public RegorusStatus status;
|
||||
/// <summary>
|
||||
/// Type of data contained in this result.
|
||||
/// </summary>
|
||||
public RegorusDataType data_type;
|
||||
/// <summary>
|
||||
/// String output produced by the call.
|
||||
/// Valid when data_type is String. Owned by Rust.
|
||||
/// </summary>
|
||||
public byte* output;
|
||||
/// <summary>
|
||||
/// Boolean value.
|
||||
/// Valid when data_type is Boolean.
|
||||
/// </summary>
|
||||
public bool bool_value;
|
||||
/// <summary>
|
||||
/// Integer value.
|
||||
/// Valid when data_type is Integer.
|
||||
/// </summary>
|
||||
public long int_value;
|
||||
/// <summary>
|
||||
/// Pointer value.
|
||||
/// Valid when data_type is Pointer.
|
||||
/// </summary>
|
||||
public void* pointer_value;
|
||||
/// <summary>
|
||||
/// Errors produced by the call.
|
||||
/// Owned by Rust.
|
||||
/// </summary>
|
||||
public byte* error_message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for regorus::Engine.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe partial struct RegorusEngine
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for regorus::CompiledPolicy.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe partial struct RegorusCompiledPolicy
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FFI wrapper for PolicyModule struct.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe partial struct RegorusPolicyModule
|
||||
{
|
||||
public byte* id;
|
||||
public byte* content;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
#nullable enable
|
||||
namespace Regorus
|
||||
{
|
||||
/// <summary>
|
||||
/// Information about a compiled policy, including metadata about modules,
|
||||
/// target configuration, and resource types that the policy can evaluate.
|
||||
/// </summary>
|
||||
public class PolicyInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// List of module identifiers that were compiled into this policy.
|
||||
/// Each module ID represents a unique policy module that contributes
|
||||
/// rules, functions, or data to the compiled policy.
|
||||
/// </summary>
|
||||
[JsonPropertyName("module_ids")]
|
||||
public List<string> ModuleIds { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Name of the target configuration used during compilation, if any.
|
||||
/// This indicates which target schema and validation rules were applied.
|
||||
/// </summary>
|
||||
[JsonPropertyName("target_name")]
|
||||
public string? TargetName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of resource types that this policy can evaluate.
|
||||
/// For target-aware policies, this contains the inferred or configured
|
||||
/// resource types. For general policies, this may be empty.
|
||||
/// </summary>
|
||||
[JsonPropertyName("applicable_resource_types")]
|
||||
public List<string> ApplicableResourceTypes { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// The primary rule or entrypoint that this policy evaluates.
|
||||
/// This is the rule path that will be executed when the policy runs.
|
||||
/// </summary>
|
||||
[JsonPropertyName("entrypoint_rule")]
|
||||
public string EntrypointRule { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The effect rule name for target-aware policies, if applicable.
|
||||
/// This is the specific effect rule (e.g., "effect", "allow", "deny")
|
||||
/// that determines the policy decision for target evaluation.
|
||||
/// </summary>
|
||||
[JsonPropertyName("effect_rule")]
|
||||
public string? EffectRule { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parameters that can be configured for this policy.
|
||||
/// Contains parameter names and their expected types or default values.
|
||||
/// Used for parameterized policies that accept configuration at evaluation time.
|
||||
/// Each element represents parameters from a different module.
|
||||
/// </summary>
|
||||
[JsonPropertyName("parameters")]
|
||||
public List<PolicyParameters> Parameters { get; set; } = new List<PolicyParameters>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parameters that can be configured for a policy.
|
||||
/// </summary>
|
||||
public class PolicyParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Source file where the parameters are defined.
|
||||
/// </summary>
|
||||
[JsonPropertyName("source_file")]
|
||||
public string SourceFile { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// List of parameter definitions.
|
||||
/// </summary>
|
||||
[JsonPropertyName("parameters")]
|
||||
public List<PolicyParameter> Parameters { get; set; } = new List<PolicyParameter>();
|
||||
|
||||
/// <summary>
|
||||
/// List of parameter modifiers.
|
||||
/// </summary>
|
||||
[JsonPropertyName("modifiers")]
|
||||
public List<PolicyParameterModifier> Modifiers { get; set; } = new List<PolicyParameterModifier>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A single parameter definition.
|
||||
/// </summary>
|
||||
public class PolicyParameter
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the parameter.
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Type of the parameter.
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Default value of the parameter, if any.
|
||||
/// </summary>
|
||||
[JsonPropertyName("default")]
|
||||
public object? Default { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the parameter.
|
||||
/// </summary>
|
||||
[JsonPropertyName("description")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allowed values for the parameter, if constrained.
|
||||
/// </summary>
|
||||
[JsonPropertyName("allowed_values")]
|
||||
public List<object>? AllowedValues { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A parameter modifier that affects parameter behavior.
|
||||
/// </summary>
|
||||
public class PolicyParameterModifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the modifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Value of the modifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("value")]
|
||||
public object? Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,10 @@
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
$(RegorusFFIArtifactsDir) is the location where regorus shared libraries have been
|
||||
built for various platforms and copied to. RegorusFFIArtifactsDir is passed in
|
||||
@@ -20,8 +24,10 @@
|
||||
|
||||
For each target triple, `Pack` expects the regorus ffi shared library
|
||||
to be found in $(RegorusFFIArtifactsDir)/<target-triple>/release.
|
||||
|
||||
If $(IgnoreMissingArtifacts) is not set, ensure that the binaries for officially supported platforms exists.
|
||||
-->
|
||||
<Target Name="ChecksRegorusFFIArtifactsDir" BeforeTargets="Pack">
|
||||
<Target Name="ChecksRegorusFFIArtifactsDir" BeforeTargets="Pack" Condition="'$(IgnoreMissingArtifacts)' == ''">
|
||||
<Error Text="RegorusFFIArtifactsDir must be supplied." Condition="$(RegorusFFIArtifactsDir) == ''" />
|
||||
|
||||
<!-- Ensure that the binaries for officially supported platforms exists. -->
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
// <auto-generated>
|
||||
// This code is generated by csbindgen.
|
||||
// DON'T CHANGE THIS DIRECTLY.
|
||||
// </auto-generated>
|
||||
#pragma warning disable CS8500
|
||||
#pragma warning disable CS8981
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
namespace Regorus.Internal
|
||||
{
|
||||
internal static unsafe partial class API
|
||||
{
|
||||
const string __DllName = "regorus_ffi";
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Drop a `RegorusResult`.
|
||||
///
|
||||
/// `output` and `error_message` strings are not valid after drop.
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_result_drop", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern void regorus_result_drop(RegorusResult r);
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new Engine
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusEngine* regorus_engine_new();
|
||||
|
||||
/// <summary>
|
||||
/// Clone a [`RegorusEngine`]
|
||||
///
|
||||
/// To avoid having to parse same policy again, the engine can be cloned
|
||||
/// after policies and data have been added.
|
||||
///
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_clone", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusEngine* regorus_engine_clone(RegorusEngine* engine);
|
||||
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_drop", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern void regorus_engine_drop(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Add a policy
|
||||
///
|
||||
/// The policy is parsed into AST.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_policy
|
||||
///
|
||||
/// * `path`: A filename to be associated with the policy.
|
||||
/// * `rego`: Rego policy.
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_add_policy", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_add_policy(RegorusEngine* engine, byte* path, byte* rego);
|
||||
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_add_policy_from_file", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_add_policy_from_file(RegorusEngine* engine, byte* path);
|
||||
|
||||
/// <summary>
|
||||
/// Add policy data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_data
|
||||
/// * `data`: JSON encoded value to be used as policy data.
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_add_data_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_add_data_json(RegorusEngine* engine, byte* data);
|
||||
|
||||
/// <summary>
|
||||
/// Get list of loaded Rego packages as JSON.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_packages
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_get_packages", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_packages(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Get list of policies as JSON.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_get_policies", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_policies(RegorusEngine* engine);
|
||||
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_add_data_from_json_file", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_add_data_from_json_file(RegorusEngine* engine, byte* path);
|
||||
|
||||
/// <summary>
|
||||
/// Clear policy data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_data
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_clear_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_clear_data(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Set input.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_input
|
||||
/// * `input`: JSON encoded value to be used as input to query.
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_set_input_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_input_json(RegorusEngine* engine, byte* input);
|
||||
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_set_input_from_json_file", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_input_from_json_file(RegorusEngine* engine, byte* path);
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate query.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_query
|
||||
/// * `query`: Rego expression to be evaluate.
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_eval_query", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_eval_query(RegorusEngine* engine, byte* query);
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate specified rule.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_rule
|
||||
/// * `rule`: Path to the rule.
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_eval_rule", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_eval_rule(RegorusEngine* engine, byte* rule);
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable coverage.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage
|
||||
/// * `enable`: Whether to enable or disable coverage.
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_set_enable_coverage", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_enable_coverage(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool enable);
|
||||
|
||||
/// <summary>
|
||||
/// Get coverage report.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_get_coverage_report", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_coverage_report(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable strict builtin errors.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_strict_builtin_errors
|
||||
/// * `strict`: Whether to raise errors or return undefined on certain scenarios.
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_set_strict_builtin_errors", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_strict_builtin_errors(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool strict);
|
||||
|
||||
/// <summary>
|
||||
/// Get pretty printed coverage report.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Report.html#method.to_string_pretty
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_get_coverage_report_pretty", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_coverage_report_pretty(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Clear coverage data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_coverage_data
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_clear_coverage_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_clear_coverage_data(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Whether to gather output of print statements.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_gather_prints
|
||||
/// * `enable`: Whether to enable or disable gathering print statements.
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_set_gather_prints", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_gather_prints(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool enable);
|
||||
|
||||
/// <summary>
|
||||
/// Take all the gathered print statements.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.take_prints
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_take_prints", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_take_prints(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Get AST of policies.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_ast_as_json
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_get_ast_as_json", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_ast_as_json(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the package names of policies added to the engine.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_policy_package_names
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_get_policy_package_names", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_policy_package_names(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameters defined in each policy added to the engine
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_policy_parameters
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_get_policy_parameters", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_get_policy_parameters(RegorusEngine* engine);
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable rego v1.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_rego_v0
|
||||
/// </summary>
|
||||
[DllImport(__DllName, EntryPoint = "regorus_engine_set_rego_v0", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
internal static extern RegorusResult regorus_engine_set_rego_v0(RegorusEngine* engine, [MarshalAs(UnmanagedType.U1)] bool enable);
|
||||
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe partial struct RegorusResult
|
||||
{
|
||||
public RegorusStatus status;
|
||||
public byte* output;
|
||||
public byte* error_message;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe partial struct RegorusEngine
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
internal enum RegorusStatus : uint
|
||||
{
|
||||
RegorusStatusOk,
|
||||
RegorusStatusError,
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
#nullable enable
|
||||
namespace Regorus
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides static methods for managing the global resource schema registry.
|
||||
/// Resource schemas define the structure and validation rules for Azure Policy resources.
|
||||
/// </summary>
|
||||
public static unsafe class SchemaRegistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Register a resource schema from JSON with a given name.
|
||||
/// </summary>
|
||||
/// <param name="name">Name to register the schema under</param>
|
||||
/// <param name="schemaJson">JSON string representing the schema</param>
|
||||
/// <exception cref="Exception">Thrown when schema registration fails</exception>
|
||||
public static void RegisterResource(string name, string schemaJson)
|
||||
{
|
||||
var nameBytes = Encoding.UTF8.GetBytes(name + char.MinValue);
|
||||
var schemaBytes = Encoding.UTF8.GetBytes(schemaJson + char.MinValue);
|
||||
|
||||
fixed (byte* namePtr = nameBytes)
|
||||
fixed (byte* schemaPtr = schemaBytes)
|
||||
{
|
||||
CheckAndDropResult(Internal.API.regorus_resource_schema_register(namePtr, schemaPtr));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a resource schema with the given name exists.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the schema to check</param>
|
||||
/// <returns>True if the schema exists, false otherwise</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static bool ContainsResource(string name)
|
||||
{
|
||||
var nameBytes = Encoding.UTF8.GetBytes(name + char.MinValue);
|
||||
fixed (byte* namePtr = nameBytes)
|
||||
{
|
||||
var result = Internal.API.regorus_resource_schema_contains(namePtr);
|
||||
return GetBoolResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of registered resource schemas.
|
||||
/// </summary>
|
||||
/// <returns>The number of registered resource schemas</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static long ResourceCount
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = Internal.API.regorus_resource_schema_len();
|
||||
return GetIntResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the resource schema registry is empty.
|
||||
/// </summary>
|
||||
/// <returns>True if the registry is empty, false otherwise</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static bool IsResourceRegistryEmpty
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = Internal.API.regorus_resource_schema_is_empty();
|
||||
return GetBoolResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all registered resource schema names.
|
||||
/// </summary>
|
||||
/// <returns>JSON array of schema names</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static string ListResourceNames()
|
||||
{
|
||||
return CheckAndDropResult(Internal.API.regorus_resource_schema_list_names()) ?? "[]";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a resource schema by name.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the schema to remove</param>
|
||||
/// <returns>True if the schema was removed, false if it wasn't found</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static bool RemoveResource(string name)
|
||||
{
|
||||
var nameBytes = Encoding.UTF8.GetBytes(name + char.MinValue);
|
||||
fixed (byte* namePtr = nameBytes)
|
||||
{
|
||||
var result = Internal.API.regorus_resource_schema_remove(namePtr);
|
||||
return GetBoolResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all resource schemas from the registry.
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static void ClearResources()
|
||||
{
|
||||
CheckAndDropResult(Internal.API.regorus_resource_schema_clear());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register an effect schema from JSON with a given name.
|
||||
/// </summary>
|
||||
/// <param name="name">Name to register the schema under</param>
|
||||
/// <param name="schemaJson">JSON string representing the schema</param>
|
||||
/// <exception cref="Exception">Thrown when schema registration fails</exception>
|
||||
public static void RegisterEffect(string name, string schemaJson)
|
||||
{
|
||||
var nameBytes = Encoding.UTF8.GetBytes(name + char.MinValue);
|
||||
var schemaBytes = Encoding.UTF8.GetBytes(schemaJson + char.MinValue);
|
||||
|
||||
fixed (byte* namePtr = nameBytes)
|
||||
fixed (byte* schemaPtr = schemaBytes)
|
||||
{
|
||||
CheckAndDropResult(Internal.API.regorus_effect_schema_register(namePtr, schemaPtr));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if an effect schema with the given name exists.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the schema to check</param>
|
||||
/// <returns>True if the schema exists, false otherwise</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static bool ContainsEffect(string name)
|
||||
{
|
||||
var nameBytes = Encoding.UTF8.GetBytes(name + char.MinValue);
|
||||
fixed (byte* namePtr = nameBytes)
|
||||
{
|
||||
var result = Internal.API.regorus_effect_schema_contains(namePtr);
|
||||
return GetBoolResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of registered effect schemas.
|
||||
/// </summary>
|
||||
/// <returns>The number of registered effect schemas</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static long EffectCount
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = Internal.API.regorus_effect_schema_len();
|
||||
return GetIntResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the effect schema registry is empty.
|
||||
/// </summary>
|
||||
/// <returns>True if the registry is empty, false otherwise</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static bool IsEffectRegistryEmpty
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = Internal.API.regorus_effect_schema_is_empty();
|
||||
return GetBoolResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all registered effect schema names.
|
||||
/// </summary>
|
||||
/// <returns>JSON array of schema names</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static string ListEffectNames()
|
||||
{
|
||||
return CheckAndDropResult(Internal.API.regorus_effect_schema_list_names()) ?? "[]";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove an effect schema by name.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the schema to remove</param>
|
||||
/// <returns>True if the schema was removed, false if it wasn't found</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static bool RemoveEffect(string name)
|
||||
{
|
||||
var nameBytes = Encoding.UTF8.GetBytes(name + char.MinValue);
|
||||
fixed (byte* namePtr = nameBytes)
|
||||
{
|
||||
var result = Internal.API.regorus_effect_schema_remove(namePtr);
|
||||
return GetBoolResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all effect schemas from the registry.
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
#nullable enable
|
||||
namespace Regorus
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides static methods for managing the global target registry.
|
||||
/// Targets define resource types and their associated schemas for Azure Policy evaluation.
|
||||
/// </summary>
|
||||
public static unsafe class TargetRegistry
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="targetJson">JSON encoded target definition</param>
|
||||
/// <exception cref="Exception">Thrown when target registration fails</exception>
|
||||
public static void RegisterFromJson(string targetJson)
|
||||
{
|
||||
var targetBytes = Encoding.UTF8.GetBytes(targetJson + char.MinValue);
|
||||
fixed (byte* targetPtr = targetBytes)
|
||||
{
|
||||
CheckAndDropResult(Internal.API.regorus_register_target_from_json(targetPtr));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a target is registered.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the target to check</param>
|
||||
/// <returns>True if the target is registered, false otherwise</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static bool Contains(string name)
|
||||
{
|
||||
var nameBytes = Encoding.UTF8.GetBytes(name + char.MinValue);
|
||||
fixed (byte* namePtr = nameBytes)
|
||||
{
|
||||
var result = Internal.API.regorus_target_registry_contains(namePtr);
|
||||
return GetBoolResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all registered target names.
|
||||
/// </summary>
|
||||
/// <returns>JSON array of target names</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static string ListNames()
|
||||
{
|
||||
return CheckAndDropResult(Internal.API.regorus_target_registry_list_names()) ?? "[]";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a target from the registry by name.
|
||||
/// </summary>
|
||||
/// <param name="name">The target name to remove</param>
|
||||
/// <returns>True if the target was removed, false if it wasn't found</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static bool Remove(string name)
|
||||
{
|
||||
var nameBytes = Encoding.UTF8.GetBytes(name + char.MinValue);
|
||||
fixed (byte* namePtr = nameBytes)
|
||||
{
|
||||
var result = Internal.API.regorus_target_registry_remove(namePtr);
|
||||
return GetBoolResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all targets from the registry.
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static void Clear()
|
||||
{
|
||||
CheckAndDropResult(Internal.API.regorus_target_registry_clear());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of registered targets.
|
||||
/// </summary>
|
||||
/// <returns>The number of registered targets</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
public static long Count
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = Internal.API.regorus_target_registry_len();
|
||||
return GetIntResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the target registry is empty.
|
||||
/// </summary>
|
||||
/// <returns>True if the registry is empty, false otherwise</returns>
|
||||
/// <exception cref="Exception">Thrown when the operation fails</exception>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Text.Json;
|
||||
|
||||
namespace TargetExampleApp;
|
||||
|
||||
class Program
|
||||
{
|
||||
// Policy definition constants
|
||||
private const string AZURE_STORAGE_POLICY_DEFINITION = @"
|
||||
package policy
|
||||
|
||||
import rego.v1
|
||||
|
||||
# Target declaration for Azure Policy
|
||||
__target__ := ""target.tests.azure_policy""
|
||||
|
||||
default parameters.requiredTLSVersion = """"
|
||||
default parameters.allowedPorts = []
|
||||
|
||||
# Policy rules for storage accounts
|
||||
default allow := false
|
||||
|
||||
# Allow storage accounts with HTTPS-only traffic and proper encryption
|
||||
allow if {
|
||||
input.type == ""Microsoft.Storage/storageAccounts""
|
||||
input.properties.supportsHttpsTrafficOnly == true
|
||||
input.properties.encryption.services.blob.enabled == true
|
||||
input.properties.minimumTlsVersion in [parameters.requiredTLSVersion]
|
||||
}
|
||||
|
||||
# Allow network security groups with proper inbound rules
|
||||
allow if {
|
||||
input.type == ""Microsoft.Network/networkSecurityGroups""
|
||||
count([rule |
|
||||
rule := input.properties.securityRules[_]
|
||||
rule.properties.direction == ""Inbound""
|
||||
rule.properties.access == ""Allow""
|
||||
rule.properties.sourceAddressPrefix == ""*""
|
||||
rule.properties.destinationPortRange in [parameters.allowedPorts]
|
||||
]) == 0
|
||||
}";
|
||||
|
||||
private const string AZURE_STORAGE_POLICY_ASSIGNMENT = @"
|
||||
package policy
|
||||
|
||||
import rego.v1
|
||||
|
||||
parameters.requiredTLSVersion = ""TLS1_2""
|
||||
parameters.allowedPorts = [""22"", ""3389""]";
|
||||
|
||||
// Test data constants
|
||||
private const string COMPLIANT_STORAGE_ACCOUNT = @"{
|
||||
""type"": ""Microsoft.Storage/storageAccounts"",
|
||||
""name"": ""compliantstorageacct"",
|
||||
""location"": ""eastus"",
|
||||
""kind"": ""StorageV2"",
|
||||
""properties"": {
|
||||
""supportsHttpsTrafficOnly"": true,
|
||||
""minimumTlsVersion"": ""TLS1_2"",
|
||||
""allowBlobPublicAccess"": false,
|
||||
""encryption"": {
|
||||
""services"": {
|
||||
""blob"": { ""enabled"": true },
|
||||
""file"": { ""enabled"": true }
|
||||
}
|
||||
}
|
||||
},
|
||||
""tags"": {
|
||||
""environment"": ""production""
|
||||
}
|
||||
}";
|
||||
|
||||
private const string NON_COMPLIANT_STORAGE_ACCOUNT = @"{
|
||||
""type"": ""Microsoft.Storage/storageAccounts"",
|
||||
""name"": ""insecurestorageacct"",
|
||||
""location"": ""westus"",
|
||||
""kind"": ""Storage"",
|
||||
""properties"": {
|
||||
""supportsHttpsTrafficOnly"": false,
|
||||
""minimumTlsVersion"": ""TLS1_0"",
|
||||
""allowBlobPublicAccess"": true,
|
||||
""encryption"": {
|
||||
""services"": {
|
||||
""blob"": { ""enabled"": false },
|
||||
""file"": { ""enabled"": false }
|
||||
}
|
||||
}
|
||||
}
|
||||
}";
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("=== Regorus Target Example Application ===\n");
|
||||
|
||||
try
|
||||
{
|
||||
DemonstrateTargetFunctionality();
|
||||
Console.WriteLine("\n=== Target demonstration completed successfully! ===");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void DemonstrateTargetFunctionality()
|
||||
{
|
||||
Console.WriteLine("REGORUS TARGET FUNCTIONALITY DEMONSTRATION");
|
||||
Console.WriteLine("==========================================");
|
||||
|
||||
// 1. Register target using JSON from file
|
||||
var targetJsonPath = Path.Combine(AppContext.BaseDirectory, "azure_policy.target.json");
|
||||
var targetJson = File.ReadAllText(targetJsonPath);
|
||||
|
||||
Console.WriteLine("1. Registering target from JSON file:");
|
||||
Console.WriteLine(targetJson);
|
||||
|
||||
Regorus.TargetRegistry.RegisterFromJson(targetJson);
|
||||
Console.WriteLine($"Target registered. Registry contains {Regorus.TargetRegistry.Count} target(s)");
|
||||
Console.WriteLine($"Registered targets: {Regorus.TargetRegistry.ListNames()}");
|
||||
|
||||
// 2. Compile policy for target
|
||||
var policyModules = new List<Regorus.PolicyModule>
|
||||
{
|
||||
new Regorus.PolicyModule($"definition-{Guid.NewGuid():N}", AZURE_STORAGE_POLICY_DEFINITION),
|
||||
new Regorus.PolicyModule($"assignment-{Guid.NewGuid():N}", AZURE_STORAGE_POLICY_ASSIGNMENT)
|
||||
};
|
||||
|
||||
var policyDataJson = "{}";
|
||||
|
||||
Console.WriteLine("\n2. Compiling policy for target...");
|
||||
using var compiledPolicy = Regorus.Compiler.CompilePolicyForTarget(policyDataJson, policyModules);
|
||||
Console.WriteLine("Policy compiled successfully!");
|
||||
|
||||
// 2.5. Demonstrate policy information retrieval
|
||||
Console.WriteLine("\n2.5. Retrieving policy information:");
|
||||
DemonstratePolicyInfo(compiledPolicy);
|
||||
|
||||
// 3. Evaluate with different inputs
|
||||
Console.WriteLine("\n3. Testing policy evaluation:");
|
||||
Console.WriteLine("Compliant storage account:");
|
||||
Console.WriteLine(COMPLIANT_STORAGE_ACCOUNT);
|
||||
|
||||
var compliantResult = compiledPolicy.EvalWithInput(COMPLIANT_STORAGE_ACCOUNT);
|
||||
Console.WriteLine($"Result: {compliantResult}");
|
||||
|
||||
Console.WriteLine("\nNon-compliant storage account:");
|
||||
Console.WriteLine(NON_COMPLIANT_STORAGE_ACCOUNT);
|
||||
|
||||
var nonCompliantResult = compiledPolicy.EvalWithInput(NON_COMPLIANT_STORAGE_ACCOUNT);
|
||||
Console.WriteLine($"Result: {nonCompliantResult}");
|
||||
|
||||
// 4. Demonstrate thread-safe concurrent evaluation
|
||||
Console.WriteLine("\n4. Testing concurrent evaluation from multiple threads:");
|
||||
DemonstrateConcurrentEvaluation(compiledPolicy);
|
||||
}
|
||||
|
||||
static void DemonstrateConcurrentEvaluation(Regorus.CompiledPolicy compiledPolicy)
|
||||
{
|
||||
var testInputs = new[]
|
||||
{
|
||||
("Thread-1-Compliant", COMPLIANT_STORAGE_ACCOUNT),
|
||||
("Thread-2-NonCompliant", NON_COMPLIANT_STORAGE_ACCOUNT),
|
||||
("Thread-3-Compliant", COMPLIANT_STORAGE_ACCOUNT.Replace("compliantstorageacct", "thread3storage")),
|
||||
("Thread-4-NonCompliant", NON_COMPLIANT_STORAGE_ACCOUNT.Replace("insecurestorageacct", "thread4storage")),
|
||||
("Thread-5-Compliant", COMPLIANT_STORAGE_ACCOUNT.Replace("compliantstorageacct", "thread5storage"))
|
||||
};
|
||||
|
||||
Console.WriteLine($"Starting {testInputs.Length} concurrent evaluations...");
|
||||
|
||||
var tasks = testInputs.Select(input =>
|
||||
Task.Run(() => {
|
||||
var (threadName, json) = input;
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
|
||||
// Multiple evaluations per thread to stress test
|
||||
var results = new List<string>();
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
var result = compiledPolicy.EvalWithInput(json);
|
||||
results.Add(result);
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
var microseconds = stopwatch.ElapsedTicks * 1000000 / System.Diagnostics.Stopwatch.Frequency;
|
||||
|
||||
// Verify all results are identical (thread safety)
|
||||
var firstResult = results[0];
|
||||
var allIdentical = results.All(r => r == firstResult);
|
||||
|
||||
Console.WriteLine($"✓ {threadName}: {results.Count} evaluations in {microseconds}μs, " +
|
||||
$"Results consistent: {allIdentical}");
|
||||
|
||||
return (threadName, results.Count, microseconds, allIdentical);
|
||||
})
|
||||
).ToArray();
|
||||
|
||||
// Wait for all threads to complete
|
||||
var results = Task.WhenAll(tasks).Result;
|
||||
|
||||
Console.WriteLine("\nConcurrency test results:");
|
||||
var totalEvaluations = results.Sum(r => r.Item2);
|
||||
var maxTime = results.Max(r => r.Item3);
|
||||
var allConsistent = results.All(r => r.allIdentical);
|
||||
|
||||
Console.WriteLine($"✓ Total evaluations: {totalEvaluations}");
|
||||
Console.WriteLine($"✓ Max thread time: {maxTime}μs");
|
||||
Console.WriteLine($"✓ All threads consistent: {allConsistent}");
|
||||
Console.WriteLine($"✓ Approximate throughput: {totalEvaluations * 1000000.0 / maxTime:F0} evaluations/second");
|
||||
Console.WriteLine("✓ No locks required - CompiledPolicy is thread-safe!");
|
||||
}
|
||||
|
||||
static void DemonstratePolicyInfo(Regorus.CompiledPolicy compiledPolicy)
|
||||
{
|
||||
Console.WriteLine("Getting policy metadata using GetPolicyInfo()...");
|
||||
|
||||
try
|
||||
{
|
||||
var policyInfo = compiledPolicy.GetPolicyInfo();
|
||||
|
||||
Console.WriteLine($"✓ Policy Information Retrieved:");
|
||||
Console.WriteLine($" Target Name: {policyInfo.TargetName ?? "None"}");
|
||||
Console.WriteLine($" Effect Rule: {policyInfo.EffectRule ?? "None"}");
|
||||
Console.WriteLine($" Entrypoint Rule: {policyInfo.EntrypointRule}");
|
||||
|
||||
Console.WriteLine($" Module IDs ({policyInfo.ModuleIds.Count}):");
|
||||
foreach (var moduleId in policyInfo.ModuleIds)
|
||||
{
|
||||
Console.WriteLine($" - {moduleId}");
|
||||
}
|
||||
|
||||
Console.WriteLine($" Applicable Resource Types ({policyInfo.ApplicableResourceTypes.Count}):");
|
||||
foreach (var resourceType in policyInfo.ApplicableResourceTypes)
|
||||
{
|
||||
Console.WriteLine($" - {resourceType}");
|
||||
}
|
||||
|
||||
if (policyInfo.Parameters != null && policyInfo.Parameters.Count > 0)
|
||||
{
|
||||
Console.WriteLine($" Policy Parameters:");
|
||||
foreach (var parameterSet in policyInfo.Parameters)
|
||||
{
|
||||
Console.WriteLine($" From '{parameterSet.SourceFile}':");
|
||||
Console.WriteLine($" Parameters ({parameterSet.Parameters.Count}):");
|
||||
foreach (var param in parameterSet.Parameters)
|
||||
{
|
||||
Console.WriteLine($" - {param.Name} ({param.Type})");
|
||||
if (param.Default != null)
|
||||
{
|
||||
Console.WriteLine($" Default: {param.Default}");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(param.Description))
|
||||
{
|
||||
Console.WriteLine($" Description: {param.Description}");
|
||||
}
|
||||
}
|
||||
|
||||
if (parameterSet.Modifiers.Count > 0)
|
||||
{
|
||||
Console.WriteLine($" Modifiers ({parameterSet.Modifiers.Count}):");
|
||||
foreach (var modifier in parameterSet.Modifiers)
|
||||
{
|
||||
Console.WriteLine($" - {modifier.Name}: {modifier.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(" No parameter information available");
|
||||
}
|
||||
|
||||
// Demonstrate JSON serialization of policy info
|
||||
Console.WriteLine("\n✓ Policy Info as JSON:");
|
||||
var jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
var policyInfoJson = JsonSerializer.Serialize(policyInfo, jsonOptions);
|
||||
Console.WriteLine(policyInfoJson);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"✗ Failed to get policy info: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- If the environment variable is set (such as in a Github Action run), append the suffix to the version number -->
|
||||
<RegorusPackageVersionSuffix Condition="'$(VersionSuffix)' != ''">-$(VersionSuffix)</RegorusPackageVersionSuffix>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Regorus" Version="0.6.0$(RegorusPackageVersionSuffix)"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="azure_policy.target.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"name": "target.tests.azure_policy",
|
||||
"description": "Azure Policy target for comprehensive policy evaluation testing",
|
||||
"version": "1.0.0",
|
||||
"resource_schema_selector": "type",
|
||||
"resource_schemas": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "const": "Microsoft.Resources/subscriptions" },
|
||||
"subscriptionId": { "type": "string" },
|
||||
"tenantId": { "type": "string" },
|
||||
"displayName": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "subscriptionId"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "const": "Microsoft.Storage/storageAccounts" },
|
||||
"name": { "type": "string" },
|
||||
"location": { "type": "string" },
|
||||
"kind": { "enum": ["Storage", "StorageV2", "BlobStorage", "FileStorage", "BlockBlobStorage"] },
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"supportsHttpsTrafficOnly": { "type": "boolean" },
|
||||
"minimumTlsVersion": { "enum": ["TLS1_0", "TLS1_1", "TLS1_2"] },
|
||||
"allowBlobPublicAccess": { "type": "boolean" },
|
||||
"encryption": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"services": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"blob": { "type": "object", "properties": { "enabled": { "type": "boolean" } } },
|
||||
"file": { "type": "object", "properties": { "enabled": { "type": "boolean" } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": { "type": "object" }
|
||||
},
|
||||
"required": ["type", "name", "location"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "const": "Microsoft.Network/networkSecurityGroups" },
|
||||
"name": { "type": "string" },
|
||||
"location": { "type": "string" },
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"securityRules": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"direction": { "enum": ["Inbound", "Outbound"] },
|
||||
"access": { "enum": ["Allow", "Deny"] },
|
||||
"protocol": { "enum": ["Tcp", "Udp", "*"] },
|
||||
"sourcePortRange": { "type": "string" },
|
||||
"destinationPortRange": { "type": "string" },
|
||||
"sourceAddressPrefix": { "type": "string" },
|
||||
"destinationAddressPrefix": { "type": "string" },
|
||||
"priority": { "type": "integer", "minimum": 100, "maximum": 4096 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["type", "name", "location"]
|
||||
}
|
||||
],
|
||||
"effects": {
|
||||
"allow": { "type": "boolean" },
|
||||
"deny": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"audit": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"level": { "enum": ["info", "warning", "error"] },
|
||||
"message": { "type": "string" },
|
||||
"complianceState": { "enum": ["Compliant", "NonCompliant", "Unknown"] }
|
||||
}
|
||||
},
|
||||
"modify": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"operations": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"operation": { "enum": ["add", "replace", "remove"] },
|
||||
"field": { "type": "string" },
|
||||
"value": { "type": "any" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deployIfNotExists": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"template": { "type": "object" },
|
||||
"parameters": { "type": "object" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"sdk": {
|
||||
"allowPrerelease": false,
|
||||
"version": "8.0.412",
|
||||
"rollForward": "disable"
|
||||
"rollForward": "latestFeature"
|
||||
}
|
||||
}
|
||||
Generated
+37
-20
@@ -92,9 +92,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
@@ -217,18 +217,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.43"
|
||||
version = "4.5.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f"
|
||||
checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.43"
|
||||
version = "4.5.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65"
|
||||
checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -255,22 +255,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "csbindgen"
|
||||
version = "1.9.3"
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c26b9831049b947d154bba920e4124053def72447be6fb106a96f483874b482a"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"syn",
|
||||
]
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.5.3"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"hashbrown 0.14.5",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
@@ -816,9 +813,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.96"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0"
|
||||
checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -959,6 +956,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
@@ -969,7 +967,6 @@ version = "0.5.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cbindgen",
|
||||
"csbindgen",
|
||||
"regorus",
|
||||
"serde_json",
|
||||
]
|
||||
@@ -1117,9 +1114,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.104"
|
||||
version = "2.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
||||
checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1150,6 +1147,26 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.8.1"
|
||||
|
||||
@@ -32,4 +32,3 @@ custom_allocator = []
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "0.28.0"
|
||||
csbindgen = "=1.9.3"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
extern crate cbindgen;
|
||||
extern crate csbindgen;
|
||||
|
||||
use std::env;
|
||||
|
||||
@@ -21,12 +20,4 @@ fn main() {
|
||||
.generate()
|
||||
.expect("Unable to generate bindings")
|
||||
.write_to_file("regorus.ffi.hpp");
|
||||
|
||||
csbindgen::Builder::default()
|
||||
.input_extern_file("src/lib.rs")
|
||||
.csharp_dll_name("regorus_ffi")
|
||||
.csharp_class_name("API")
|
||||
.csharp_namespace("Regorus.Internal")
|
||||
.generate_csharp_file("./RegorusFFI.g.cs")
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#[cfg(feature = "custom_allocator")]
|
||||
extern "C" {
|
||||
fn regorus_aligned_alloc(alignment: usize, size: usize) -> *mut u8;
|
||||
fn regorus_free(ptr: *mut u8);
|
||||
}
|
||||
|
||||
#[cfg(feature = "custom_allocator")]
|
||||
mod allocator {
|
||||
use std::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
struct RegorusAllocator {}
|
||||
|
||||
unsafe impl GlobalAlloc for RegorusAllocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
let size = layout.size();
|
||||
let align = layout.align();
|
||||
|
||||
crate::allocator::regorus_aligned_alloc(align, size)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||
crate::allocator::regorus_free(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: RegorusAllocator = RegorusAllocator {};
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::{c_char, c_longlong};
|
||||
|
||||
/// Status of a call on `RegorusEngine`.
|
||||
#[repr(C)]
|
||||
pub enum RegorusStatus {
|
||||
/// The operation was successful.
|
||||
Ok,
|
||||
|
||||
/// The operation was unsuccessful.
|
||||
Error,
|
||||
|
||||
/// Invalid data format provided.
|
||||
InvalidDataFormat,
|
||||
|
||||
/// Invalid entrypoint rule specified.
|
||||
InvalidEntrypoint,
|
||||
|
||||
/// Compilation failed.
|
||||
CompilationFailed,
|
||||
|
||||
/// Invalid argument provided.
|
||||
InvalidArgument,
|
||||
|
||||
/// Invalid module ID.
|
||||
InvalidModuleId,
|
||||
|
||||
/// Invalid policy content.
|
||||
InvalidPolicy,
|
||||
}
|
||||
|
||||
/// Type of data contained in RegorusResult
|
||||
#[repr(C)]
|
||||
#[allow(unused)]
|
||||
pub enum RegorusDataType {
|
||||
/// No data / void
|
||||
None,
|
||||
/// String data (output field is valid)
|
||||
String,
|
||||
/// Boolean data (bool_value field is valid)
|
||||
Boolean,
|
||||
/// Integer data (int_value field is valid)
|
||||
Integer,
|
||||
/// Pointer data (pointer_value field is valid)
|
||||
Pointer,
|
||||
}
|
||||
|
||||
/// Result of a call on `RegorusEngine`.
|
||||
///
|
||||
/// Must be freed using `regorus_result_drop`.
|
||||
#[repr(C)]
|
||||
pub struct RegorusResult {
|
||||
/// Status
|
||||
pub(crate) status: RegorusStatus,
|
||||
|
||||
/// Type of data contained in this result
|
||||
pub(crate) data_type: RegorusDataType,
|
||||
|
||||
/// String output produced by the call.
|
||||
/// Valid when data_type is String. Owned by Rust.
|
||||
pub(crate) output: *mut c_char,
|
||||
|
||||
/// Boolean value.
|
||||
/// Valid when data_type is Boolean.
|
||||
pub(crate) bool_value: bool,
|
||||
|
||||
/// Integer value.
|
||||
/// Valid when data_type is Integer.
|
||||
pub(crate) int_value: c_longlong,
|
||||
|
||||
/// Pointer value.
|
||||
/// Valid when data_type is Pointer.
|
||||
pub(crate) pointer_value: *mut std::os::raw::c_void,
|
||||
|
||||
/// Errors produced by the call.
|
||||
/// Owned by Rust.
|
||||
pub(crate) error_message: *mut c_char,
|
||||
}
|
||||
|
||||
impl RegorusResult {
|
||||
/// Create a successful result with no data.
|
||||
pub(crate) fn ok_void() -> Self {
|
||||
Self {
|
||||
status: RegorusStatus::Ok,
|
||||
data_type: RegorusDataType::None,
|
||||
output: std::ptr::null_mut(),
|
||||
bool_value: false,
|
||||
int_value: 0,
|
||||
pointer_value: std::ptr::null_mut(),
|
||||
error_message: std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a successful result with string output.
|
||||
pub(crate) fn ok_string(output: String) -> Self {
|
||||
Self {
|
||||
status: RegorusStatus::Ok,
|
||||
data_type: RegorusDataType::String,
|
||||
output: to_c_str(output),
|
||||
bool_value: false,
|
||||
int_value: 0,
|
||||
pointer_value: std::ptr::null_mut(),
|
||||
error_message: std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a successful result with boolean value.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn ok_bool(value: bool) -> Self {
|
||||
Self {
|
||||
status: RegorusStatus::Ok,
|
||||
data_type: RegorusDataType::Boolean,
|
||||
output: std::ptr::null_mut(),
|
||||
bool_value: value,
|
||||
int_value: 0,
|
||||
pointer_value: std::ptr::null_mut(),
|
||||
error_message: std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a successful result with integer value.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn ok_int(value: i64) -> Self {
|
||||
Self {
|
||||
status: RegorusStatus::Ok,
|
||||
data_type: RegorusDataType::Integer,
|
||||
output: std::ptr::null_mut(),
|
||||
bool_value: false,
|
||||
int_value: value as c_longlong,
|
||||
pointer_value: std::ptr::null_mut(),
|
||||
error_message: std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a successful result with pointer value.
|
||||
pub(crate) fn ok_pointer(pointer: *mut std::os::raw::c_void) -> Self {
|
||||
Self {
|
||||
status: RegorusStatus::Ok,
|
||||
data_type: RegorusDataType::Pointer,
|
||||
output: std::ptr::null_mut(),
|
||||
bool_value: false,
|
||||
int_value: 0,
|
||||
pointer_value: pointer,
|
||||
error_message: std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an error result with specific status.
|
||||
pub(crate) fn err(status: RegorusStatus) -> Self {
|
||||
Self {
|
||||
status,
|
||||
data_type: RegorusDataType::None,
|
||||
output: std::ptr::null_mut(),
|
||||
bool_value: false,
|
||||
int_value: 0,
|
||||
pointer_value: std::ptr::null_mut(),
|
||||
error_message: std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an error result with status and message.
|
||||
pub(crate) fn err_with_message(status: RegorusStatus, message: String) -> Self {
|
||||
Self {
|
||||
status,
|
||||
data_type: RegorusDataType::None,
|
||||
output: std::ptr::null_mut(),
|
||||
bool_value: false,
|
||||
int_value: 0,
|
||||
pointer_value: std::ptr::null_mut(),
|
||||
error_message: to_c_str(message),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_c_str(s: String) -> *mut c_char {
|
||||
match CString::new(s) {
|
||||
Ok(cs) => cs.into_raw(),
|
||||
_ => to_c_str("binding error: failed to create c-style string".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_c_str(s: *const c_char) -> Result<String> {
|
||||
if s.is_null() {
|
||||
bail!("null pointer");
|
||||
}
|
||||
unsafe {
|
||||
CStr::from_ptr(s)
|
||||
.to_str()
|
||||
.map_err(|e| anyhow!("invalid utf8: {e}"))
|
||||
.map(|s| s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_ref<'a, T>(t: *mut T) -> Result<&'a mut T> {
|
||||
unsafe { t.as_mut().ok_or_else(|| anyhow!("null pointer")) }
|
||||
}
|
||||
|
||||
pub(crate) fn to_regorus_result(r: Result<()>) -> RegorusResult {
|
||||
match r {
|
||||
Ok(()) => RegorusResult::ok_void(),
|
||||
Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{e}")),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_regorus_string_result(r: Result<String>) -> RegorusResult {
|
||||
match r {
|
||||
Ok(s) => RegorusResult::ok_string(s),
|
||||
Err(e) => RegorusResult::err_with_message(RegorusStatus::Error, format!("{e}")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Drop a `RegorusResult`.
|
||||
///
|
||||
/// `output` and `error_message` strings are not valid after drop.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_result_drop(r: RegorusResult) {
|
||||
unsafe {
|
||||
if !r.error_message.is_null() {
|
||||
let _ = CString::from_raw(r.error_message);
|
||||
}
|
||||
if !r.output.is_null() {
|
||||
let _ = CString::from_raw(r.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
use crate::common::{from_c_str, RegorusResult, RegorusStatus};
|
||||
use crate::compiled_policy::RegorusCompiledPolicy;
|
||||
use regorus::{compile_policy_with_entrypoint, PolicyModule, Value};
|
||||
|
||||
#[cfg(feature = "azure_policy")]
|
||||
use regorus::compile_policy_for_target;
|
||||
|
||||
use std::os::raw::c_char;
|
||||
|
||||
/// FFI wrapper for PolicyModule struct.
|
||||
#[repr(C)]
|
||||
pub struct RegorusPolicyModule {
|
||||
pub id: *const c_char,
|
||||
pub content: *const c_char,
|
||||
}
|
||||
|
||||
/// Compiles a policy from data and modules with a specific entry point rule.
|
||||
///
|
||||
/// This is a convenience function that wraps [`regorus::compile_policy_with_entrypoint`].
|
||||
/// It sets up an Engine internally and calls the appropriate compilation method.
|
||||
///
|
||||
/// # Parameters
|
||||
/// * `data_json` - JSON string containing static data for policy evaluation
|
||||
/// * `modules` - Array of policy modules to compile
|
||||
/// * `modules_len` - Number of modules in the array
|
||||
/// * `entry_point_rule` - The specific rule path to evaluate (e.g., "data.policy.allow")
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult containing a RegorusCompiledPolicy handle on success.
|
||||
///
|
||||
/// # Safety
|
||||
/// All string parameters must be valid null-terminated UTF-8 strings.
|
||||
/// The modules array must contain exactly `modules_len` valid elements.
|
||||
/// The caller must eventually call regorus_compiled_policy_drop on the returned handle.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_compile_policy_with_entrypoint(
|
||||
data_json: *const c_char,
|
||||
modules: *const RegorusPolicyModule,
|
||||
modules_len: usize,
|
||||
entry_point_rule: *const c_char,
|
||||
) -> RegorusResult {
|
||||
let data_str = match from_c_str(data_json) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidDataFormat,
|
||||
format!("Invalid data JSON string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let entry_rule = match from_c_str(entry_point_rule) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidEntrypoint,
|
||||
format!("Invalid entry point rule string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Parse data JSON
|
||||
let data = match Value::from_json_str(&data_str) {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidDataFormat,
|
||||
format!("Failed to parse data JSON: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Convert C modules array to Rust Vec
|
||||
let policy_modules = match convert_c_modules_to_rust(modules, modules_len) {
|
||||
Ok(modules) => modules,
|
||||
Err(status) => return RegorusResult::err(status),
|
||||
};
|
||||
|
||||
// Call the convenience function
|
||||
match compile_policy_with_entrypoint(data, &policy_modules, entry_rule.into()) {
|
||||
Ok(compiled_policy) => {
|
||||
let wrapped_policy = RegorusCompiledPolicy { compiled_policy };
|
||||
let boxed_policy = Box::new(wrapped_policy);
|
||||
RegorusResult::ok_pointer(Box::into_raw(boxed_policy) as *mut std::os::raw::c_void)
|
||||
}
|
||||
Err(e) => RegorusResult::err_with_message(
|
||||
RegorusStatus::CompilationFailed,
|
||||
format!("Policy compilation failed: {e}"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compiles a target-aware policy from data and modules.
|
||||
///
|
||||
/// This is a convenience function that wraps [`regorus::compile_policy_for_target`].
|
||||
/// It sets up an Engine internally and calls target-aware compilation.
|
||||
///
|
||||
/// # Parameters
|
||||
/// * `data_json` - JSON string containing static data for policy evaluation
|
||||
/// * `modules` - Array of policy modules to compile
|
||||
/// * `modules_len` - Number of modules in the array
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult containing a RegorusCompiledPolicy handle on success.
|
||||
///
|
||||
/// # Note
|
||||
/// This function is only available when the `azure_policy` feature is enabled.
|
||||
/// At least one module must contain a `__target__` declaration.
|
||||
///
|
||||
/// # Safety
|
||||
/// All string parameters must be valid null-terminated UTF-8 strings.
|
||||
/// The modules array must contain exactly `modules_len` valid elements.
|
||||
/// The caller must eventually call regorus_compiled_policy_drop on the returned handle.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_compile_policy_for_target(
|
||||
data_json: *const c_char,
|
||||
modules: *const RegorusPolicyModule,
|
||||
modules_len: usize,
|
||||
) -> RegorusResult {
|
||||
let data_str = match from_c_str(data_json) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidDataFormat,
|
||||
format!("Invalid data JSON string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Parse data JSON
|
||||
let data = match Value::from_json_str(&data_str) {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidDataFormat,
|
||||
format!("Failed to parse data JSON: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Convert C modules array to Rust Vec
|
||||
let policy_modules = match convert_c_modules_to_rust(modules, modules_len) {
|
||||
Ok(modules) => modules,
|
||||
Err(status) => return RegorusResult::err(status),
|
||||
};
|
||||
|
||||
// Call the convenience function
|
||||
match compile_policy_for_target(data, &policy_modules) {
|
||||
Ok(compiled_policy) => {
|
||||
let wrapped_policy = RegorusCompiledPolicy { compiled_policy };
|
||||
let boxed_policy = Box::new(wrapped_policy);
|
||||
RegorusResult::ok_pointer(Box::into_raw(boxed_policy) as *mut std::os::raw::c_void)
|
||||
}
|
||||
Err(e) => RegorusResult::err_with_message(
|
||||
RegorusStatus::CompilationFailed,
|
||||
format!("Target-aware policy compilation failed: {e}"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to convert C module array to Rust Vec<PolicyModule>.
|
||||
fn convert_c_modules_to_rust(
|
||||
modules: *const RegorusPolicyModule,
|
||||
modules_len: usize,
|
||||
) -> Result<Vec<PolicyModule>, RegorusStatus> {
|
||||
if modules.is_null() && modules_len > 0 {
|
||||
return Err(RegorusStatus::InvalidArgument);
|
||||
}
|
||||
|
||||
let mut policy_modules = Vec::with_capacity(modules_len);
|
||||
|
||||
for i in 0..modules_len {
|
||||
unsafe {
|
||||
let module = modules.add(i);
|
||||
if module.is_null() {
|
||||
return Err(RegorusStatus::InvalidArgument);
|
||||
}
|
||||
|
||||
let module_ref = &*module;
|
||||
|
||||
let id = match from_c_str(module_ref.id) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("Invalid module ID at index {}: {}", i, e);
|
||||
return Err(RegorusStatus::InvalidModuleId);
|
||||
}
|
||||
};
|
||||
|
||||
let content = match from_c_str(module_ref.content) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("Invalid module content at index {}: {}", i, e);
|
||||
return Err(RegorusStatus::InvalidPolicy);
|
||||
}
|
||||
};
|
||||
|
||||
policy_modules.push(PolicyModule {
|
||||
id: id.into(),
|
||||
content: content.into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(policy_modules)
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::common::*;
|
||||
use anyhow::Result;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
/// Wrapper for `regorus::CompiledPolicy`.
|
||||
#[derive(Clone)]
|
||||
pub struct RegorusCompiledPolicy {
|
||||
pub(crate) compiled_policy: regorus::CompiledPolicy,
|
||||
}
|
||||
|
||||
/// Drop a `RegorusCompiledPolicy`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_compiled_policy_drop(compiled_policy: *mut RegorusCompiledPolicy) {
|
||||
if let Ok(cp) = to_ref(compiled_policy) {
|
||||
unsafe {
|
||||
let _ = Box::from_raw(std::ptr::from_mut(cp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate the compiled policy with the given input.
|
||||
///
|
||||
/// For target policies, evaluates the target's effect rule.
|
||||
/// For regular policies, evaluates the originally compiled rule.
|
||||
///
|
||||
/// * `input`: JSON encoded input data (resource) to validate against the policy.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_compiled_policy_eval_with_input(
|
||||
compiled_policy: *mut RegorusCompiledPolicy,
|
||||
input: *const c_char,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
let input_value = regorus::Value::from_json_str(&from_c_str(input)?)?;
|
||||
let result = to_ref(compiled_policy)?
|
||||
.compiled_policy
|
||||
.eval_with_input(input_value)?;
|
||||
result.to_json_str()
|
||||
}();
|
||||
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get information about the compiled policy including metadata about modules,
|
||||
/// target configuration, and resource types.
|
||||
///
|
||||
/// Returns a JSON-encoded `PolicyInfo` struct containing comprehensive
|
||||
/// information about the compiled policy such as module IDs, target name,
|
||||
/// applicable resource types, entry point rule, and parameters.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_compiled_policy_get_policy_info(
|
||||
compiled_policy: *mut RegorusCompiledPolicy,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
let info = to_ref(compiled_policy)?.compiled_policy.get_policy_info()?;
|
||||
serde_json::to_string(&info)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize policy info: {}", e))
|
||||
}();
|
||||
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
//! Effect schema registry functions for FFI.
|
||||
//!
|
||||
//! These functions provide access to regorus's effect schema registry functionality,
|
||||
//! enabling registration and management of Azure Policy effect schemas.
|
||||
|
||||
#![cfg(feature = "azure_policy")]
|
||||
use crate::common::{from_c_str, RegorusResult, RegorusStatus};
|
||||
use regorus::{registry::schemas, Schema};
|
||||
|
||||
use std::os::raw::c_char;
|
||||
|
||||
/// Register an effect schema from JSON with a given name.
|
||||
///
|
||||
/// # Parameters
|
||||
/// * `name` - Name to register the schema under
|
||||
/// * `schema_json` - JSON string representing the schema
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with success/error status.
|
||||
///
|
||||
/// # Safety
|
||||
/// All string parameters must be valid null-terminated UTF-8 strings.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_effect_schema_register(
|
||||
name: *const c_char,
|
||||
schema_json: *const c_char,
|
||||
) -> RegorusResult {
|
||||
let schema_name = match from_c_str(name) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidArgument,
|
||||
format!("Invalid effect schema name string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let schema_str = match from_c_str(schema_json) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidDataFormat,
|
||||
format!("Invalid effect schema JSON string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Parse schema from JSON
|
||||
let schema = match Schema::from_json_str(&schema_str) {
|
||||
Ok(schema) => schema,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidDataFormat,
|
||||
format!("Failed to parse effect schema JSON: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Register the schema
|
||||
match schemas::effect::register(schema_name, schema.into()) {
|
||||
Ok(()) => RegorusResult::ok_pointer(std::ptr::null_mut()),
|
||||
Err(e) => RegorusResult::err_with_message(
|
||||
RegorusStatus::Error,
|
||||
format!("Failed to register effect schema: {e}"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if an effect schema with the given name exists.
|
||||
///
|
||||
/// # Parameters
|
||||
/// * `name` - Name of the schema to check
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with "true" or "false" string output.
|
||||
///
|
||||
/// # Safety
|
||||
/// The name parameter must be a valid null-terminated UTF-8 string.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_effect_schema_contains(name: *const c_char) -> RegorusResult {
|
||||
let schema_name = match from_c_str(name) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidArgument,
|
||||
format!("Invalid effect schema name string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let contains = schemas::effect::contains(&schema_name);
|
||||
RegorusResult::ok_bool(contains)
|
||||
}
|
||||
|
||||
/// Get the number of registered effect schemas.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with the count as a string.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_effect_schema_len() -> RegorusResult {
|
||||
let count = schemas::effect::len();
|
||||
RegorusResult::ok_int(count as i64)
|
||||
}
|
||||
|
||||
/// Check if the effect schema registry is empty.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with "true" or "false" string output.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_effect_schema_is_empty() -> RegorusResult {
|
||||
let is_empty = schemas::effect::is_empty();
|
||||
RegorusResult::ok_bool(is_empty)
|
||||
}
|
||||
|
||||
/// List all registered effect schema names as a JSON array.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with a JSON array of schema names.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_effect_schema_list_names() -> RegorusResult {
|
||||
let names = schemas::effect::list_names();
|
||||
match serde_json::to_string(&names) {
|
||||
Ok(json_str) => RegorusResult::ok_string(json_str),
|
||||
Err(e) => RegorusResult::err_with_message(
|
||||
RegorusStatus::Error,
|
||||
format!("Failed to serialize effect schema names to JSON: {e}"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove an effect schema by name.
|
||||
///
|
||||
/// # Parameters
|
||||
/// * `name` - Name of the schema to remove
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with "true" if removed, "false" if not found.
|
||||
///
|
||||
/// # Safety
|
||||
/// The name parameter must be a valid null-terminated UTF-8 string.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_effect_schema_remove(name: *const c_char) -> RegorusResult {
|
||||
let schema_name = match from_c_str(name) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidArgument,
|
||||
format!("Invalid effect schema name string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let removed = schemas::effect::remove(&schema_name).is_some();
|
||||
RegorusResult::ok_bool(removed)
|
||||
}
|
||||
|
||||
/// Clear all effect schemas from the registry.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with success status.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_effect_schema_clear() -> RegorusResult {
|
||||
schemas::effect::clear();
|
||||
RegorusResult::ok_pointer(std::ptr::null_mut())
|
||||
}
|
||||
@@ -0,0 +1,454 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::common::{
|
||||
from_c_str, to_ref, to_regorus_result, to_regorus_string_result, RegorusResult, RegorusStatus,
|
||||
};
|
||||
use crate::compiled_policy::RegorusCompiledPolicy;
|
||||
use anyhow::Result;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
/// Wrapper for `regorus::Engine`.
|
||||
#[derive(Clone)]
|
||||
pub struct RegorusEngine {
|
||||
engine: ::regorus::Engine,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
/// Construct a new Engine
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html
|
||||
pub extern "C" fn regorus_engine_new() -> *mut RegorusEngine {
|
||||
let mut engine = ::regorus::Engine::new();
|
||||
|
||||
// For more OPA compatibility out of the box, we ask builtins to return undefined
|
||||
// instead of raising errors in certain failure scenarios.
|
||||
engine.set_strict_builtin_errors(false);
|
||||
|
||||
Box::into_raw(Box::new(RegorusEngine { engine }))
|
||||
}
|
||||
|
||||
/// Clone a [`RegorusEngine`]
|
||||
///
|
||||
/// To avoid having to parse same policy again, the engine can be cloned
|
||||
/// after policies and data have been added.
|
||||
///
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_clone(engine: *mut RegorusEngine) -> *mut RegorusEngine {
|
||||
match to_ref(engine) {
|
||||
Ok(e) => Box::into_raw(Box::new(e.clone())),
|
||||
_ => std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_drop(engine: *mut RegorusEngine) {
|
||||
if let Ok(e) = to_ref(engine) {
|
||||
unsafe {
|
||||
let _ = Box::from_raw(std::ptr::from_mut(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a policy
|
||||
///
|
||||
/// The policy is parsed into AST.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_policy
|
||||
///
|
||||
/// * `path`: A filename to be associated with the policy.
|
||||
/// * `rego`: Rego policy.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_add_policy(
|
||||
engine: *mut RegorusEngine,
|
||||
path: *const c_char,
|
||||
rego: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_string_result(|| -> Result<String> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.add_policy(from_c_str(path)?, from_c_str(rego)?)
|
||||
}())
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_add_policy_from_file(
|
||||
engine: *mut RegorusEngine,
|
||||
path: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_string_result(|| -> Result<String> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.add_policy_from_file(from_c_str(path)?)
|
||||
}())
|
||||
}
|
||||
|
||||
/// Add policy data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_data
|
||||
/// * `data`: JSON encoded value to be used as policy data.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_add_data_json(
|
||||
engine: *mut RegorusEngine,
|
||||
data: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.add_data(regorus::Value::from_json_str(&from_c_str(data)?)?)
|
||||
}())
|
||||
}
|
||||
|
||||
/// Get list of loaded Rego packages as JSON.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_packages
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_get_packages(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
to_regorus_string_result(|| -> Result<String> {
|
||||
serde_json::to_string_pretty(&to_ref(engine)?.engine.get_packages()?)
|
||||
.map_err(anyhow::Error::msg)
|
||||
}())
|
||||
}
|
||||
|
||||
/// Get list of policies as JSON.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_get_policies(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
to_regorus_string_result(|| -> Result<String> {
|
||||
to_ref(engine)?.engine.get_policies_as_json()
|
||||
}())
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_add_data_from_json_file(
|
||||
engine: *mut RegorusEngine,
|
||||
path: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.add_data(regorus::Value::from_json_file(from_c_str(path)?)?)
|
||||
}())
|
||||
}
|
||||
|
||||
/// Clear policy data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_data
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_clear_data(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?.engine.clear_data();
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Set input.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_input
|
||||
/// * `input`: JSON encoded value to be used as input to query.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_set_input_json(
|
||||
engine: *mut RegorusEngine,
|
||||
input: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.set_input(regorus::Value::from_json_str(&from_c_str(input)?)?);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_set_input_from_json_file(
|
||||
engine: *mut RegorusEngine,
|
||||
path: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.set_input(regorus::Value::from_json_file(from_c_str(path)?)?);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Evaluate query.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_query
|
||||
/// * `query`: Rego expression to be evaluate.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_eval_query(
|
||||
engine: *mut RegorusEngine,
|
||||
query: *const c_char,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
let results = to_ref(engine)?
|
||||
.engine
|
||||
.eval_query(from_c_str(query)?, false)?;
|
||||
Ok(serde_json::to_string_pretty(&results)?)
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate specified rule.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_rule
|
||||
/// * `rule`: Path to the rule.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_eval_rule(
|
||||
engine: *mut RegorusEngine,
|
||||
rule: *const c_char,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.eval_rule(from_c_str(rule)?)?
|
||||
.to_json_str()
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable/disable coverage.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage
|
||||
/// * `enable`: Whether to enable or disable coverage.
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "C" fn regorus_engine_set_enable_coverage(
|
||||
engine: *mut RegorusEngine,
|
||||
enable: bool,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?.engine.set_enable_coverage(enable);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Get coverage report.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "C" fn regorus_engine_get_coverage_report(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
Ok(serde_json::to_string_pretty(
|
||||
&to_ref(engine)?.engine.get_coverage_report()?,
|
||||
)?)
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable/disable strict builtin errors.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_strict_builtin_errors
|
||||
/// * `strict`: Whether to raise errors or return undefined on certain scenarios.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_set_strict_builtin_errors(
|
||||
engine: *mut RegorusEngine,
|
||||
strict: bool,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?.engine.set_strict_builtin_errors(strict);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Get pretty printed coverage report.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Report.html#method.to_string_pretty
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "C" fn regorus_engine_get_coverage_report_pretty(
|
||||
engine: *mut RegorusEngine,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.get_coverage_report()?
|
||||
.to_string_pretty()
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear coverage data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_coverage_data
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "C" fn regorus_engine_clear_coverage_data(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?.engine.clear_coverage_data();
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Whether to gather output of print statements.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_gather_prints
|
||||
/// * `enable`: Whether to enable or disable gathering print statements.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_set_gather_prints(
|
||||
engine: *mut RegorusEngine,
|
||||
enable: bool,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?.engine.set_gather_prints(enable);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Take all the gathered print statements.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.take_prints
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_take_prints(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
Ok(serde_json::to_string_pretty(
|
||||
&to_ref(engine)?.engine.take_prints()?,
|
||||
)?)
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get AST of policies.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_ast_as_json
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "ast")]
|
||||
pub extern "C" fn regorus_engine_get_ast_as_json(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
let output = || -> Result<String> { to_ref(engine)?.engine.get_ast_as_json() }();
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the package names defined in each policy added to the engine.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_policy_package_names
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_engine_get_policy_package_names(
|
||||
engine: *mut RegorusEngine,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
serde_json::to_string_pretty(&to_ref(engine)?.engine.get_policy_package_names()?)
|
||||
.map_err(anyhow::Error::msg)
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the parameters defined in each policy added to the engine.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_policy_parameters
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_engine_get_policy_parameters(
|
||||
engine: *mut RegorusEngine,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
serde_json::to_string_pretty(&to_ref(engine)?.engine.get_policy_parameters()?)
|
||||
.map_err(anyhow::Error::msg)
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable/disable rego v1.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_rego_v0
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_set_rego_v0(
|
||||
engine: *mut RegorusEngine,
|
||||
enable: bool,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<()> {
|
||||
to_ref(engine)?.engine.set_rego_v0(enable);
|
||||
Ok(())
|
||||
}();
|
||||
match output {
|
||||
Ok(()) => RegorusResult::ok_void(),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compile a target-aware policy from the current engine state.
|
||||
///
|
||||
/// This method creates a compiled policy that can work with Azure Policy targets,
|
||||
/// enabling resource type inference and target-specific evaluation.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.compile_for_target
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_engine_compile_for_target(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
match to_ref(engine) {
|
||||
Ok(e) => match e.engine.compile_for_target() {
|
||||
Ok(compiled_policy) => {
|
||||
let wrapped_policy = RegorusCompiledPolicy { compiled_policy };
|
||||
let boxed_policy = Box::new(wrapped_policy);
|
||||
RegorusResult::ok_pointer(Box::into_raw(boxed_policy) as *mut std::os::raw::c_void)
|
||||
}
|
||||
Err(e) => RegorusResult::err_with_message(
|
||||
RegorusStatus::CompilationFailed,
|
||||
format!("Failed to compile for target: {e}"),
|
||||
),
|
||||
},
|
||||
Err(e) => RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidArgument,
|
||||
format!("Failed to get engine reference: {e}"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compile a policy with a specific entry point rule.
|
||||
///
|
||||
/// This method creates a compiled policy that evaluates a specific rule as the entry point.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.compile_with_entrypoint
|
||||
/// * `rule`: The specific rule path to evaluate (e.g., "data.policy.allow")
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_compile_with_entrypoint(
|
||||
engine: *mut RegorusEngine,
|
||||
rule: *const c_char,
|
||||
) -> RegorusResult {
|
||||
let result = || -> Result<RegorusCompiledPolicy> {
|
||||
let rule_str = from_c_str(rule)?;
|
||||
let rule_rc: regorus::Rc<str> = rule_str.into();
|
||||
let compiled_policy = to_ref(engine)?.engine.compile_with_entrypoint(&rule_rc)?;
|
||||
Ok(RegorusCompiledPolicy { compiled_policy })
|
||||
}();
|
||||
|
||||
match result {
|
||||
Ok(wrapped_policy) => {
|
||||
let boxed_policy = Box::new(wrapped_policy);
|
||||
RegorusResult::ok_pointer(Box::into_raw(boxed_policy) as *mut std::os::raw::c_void)
|
||||
}
|
||||
Err(e) => RegorusResult::err_with_message(
|
||||
RegorusStatus::CompilationFailed,
|
||||
format!("Failed to compile with entrypoint: {e}"),
|
||||
),
|
||||
}
|
||||
}
|
||||
+8
-550
@@ -1,553 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::c_char;
|
||||
|
||||
/// Status of a call on `RegorusEngine`.
|
||||
#[repr(C)]
|
||||
pub enum RegorusStatus {
|
||||
/// The operation was successful.
|
||||
RegorusStatusOk,
|
||||
|
||||
/// The operation was unsuccessful.
|
||||
RegorusStatusError,
|
||||
}
|
||||
|
||||
/// Result of a call on `RegorusEngine`.
|
||||
///
|
||||
/// Must be freed using `regorus_result_drop`.
|
||||
#[repr(C)]
|
||||
pub struct RegorusResult {
|
||||
/// Status
|
||||
status: RegorusStatus,
|
||||
|
||||
/// Output produced by the call.
|
||||
/// Owned by Rust.
|
||||
output: *mut c_char,
|
||||
|
||||
/// Errors produced by the call.
|
||||
/// Owned by Rust.
|
||||
error_message: *mut c_char,
|
||||
}
|
||||
|
||||
fn to_c_str(s: String) -> *mut c_char {
|
||||
match CString::new(s) {
|
||||
Ok(cs) => cs.into_raw(),
|
||||
_ => to_c_str("binding error: failed to create c-style string".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_c_str(name: &str, s: *const c_char) -> Result<String> {
|
||||
if s.is_null() {
|
||||
bail!("null pointer");
|
||||
}
|
||||
unsafe {
|
||||
CStr::from_ptr(s)
|
||||
.to_str()
|
||||
.map_err(|e| anyhow!("`{name}`: invalid utf8.\n{e}"))
|
||||
.map(|s| s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn to_ref<'a, T>(t: *mut T) -> Result<&'a mut T> {
|
||||
unsafe { t.as_mut().ok_or_else(|| anyhow!("null pointer")) }
|
||||
}
|
||||
|
||||
fn to_regorus_result(r: Result<()>) -> RegorusResult {
|
||||
match r {
|
||||
Ok(()) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: std::ptr::null_mut(),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusError,
|
||||
output: std::ptr::null_mut(),
|
||||
error_message: to_c_str(format!("{e}")),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn to_regorus_string_result(r: Result<String>) -> RegorusResult {
|
||||
match r {
|
||||
Ok(s) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: to_c_str(s),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusError,
|
||||
output: std::ptr::null_mut(),
|
||||
error_message: to_c_str(format!("{e}")),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for `regorus::Engine`.
|
||||
#[derive(Clone)]
|
||||
pub struct RegorusEngine {
|
||||
engine: ::regorus::Engine,
|
||||
}
|
||||
|
||||
/// Drop a `RegorusResult`.
|
||||
///
|
||||
/// `output` and `error_message` strings are not valid after drop.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_result_drop(r: RegorusResult) {
|
||||
unsafe {
|
||||
if !r.error_message.is_null() {
|
||||
let _ = CString::from_raw(r.error_message);
|
||||
}
|
||||
if !r.output.is_null() {
|
||||
let _ = CString::from_raw(r.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
/// Construct a new Engine
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html
|
||||
pub extern "C" fn regorus_engine_new() -> *mut RegorusEngine {
|
||||
let mut engine = ::regorus::Engine::new();
|
||||
|
||||
// For more OPA compatibility out of the box, we ask builtins to return undefined
|
||||
// instead of raising errors in certain failure scenarios.
|
||||
engine.set_strict_builtin_errors(false);
|
||||
|
||||
Box::into_raw(Box::new(RegorusEngine { engine }))
|
||||
}
|
||||
|
||||
/// Clone a [`RegorusEngine`]
|
||||
///
|
||||
/// To avoid having to parse same policy again, the engine can be cloned
|
||||
/// after policies and data have been added.
|
||||
///
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_clone(engine: *mut RegorusEngine) -> *mut RegorusEngine {
|
||||
match to_ref(engine) {
|
||||
Ok(e) => Box::into_raw(Box::new(e.clone())),
|
||||
_ => std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_drop(engine: *mut RegorusEngine) {
|
||||
if let Ok(e) = to_ref(engine) {
|
||||
unsafe {
|
||||
let _ = Box::from_raw(std::ptr::from_mut(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a policy
|
||||
///
|
||||
/// The policy is parsed into AST.
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_policy
|
||||
///
|
||||
/// * `path`: A filename to be associated with the policy.
|
||||
/// * `rego`: Rego policy.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_add_policy(
|
||||
engine: *mut RegorusEngine,
|
||||
path: *const c_char,
|
||||
rego: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_string_result(|| -> Result<String> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.add_policy(from_c_str("path", path)?, from_c_str("rego", rego)?)
|
||||
}())
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_add_policy_from_file(
|
||||
engine: *mut RegorusEngine,
|
||||
path: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_string_result(|| -> Result<String> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.add_policy_from_file(from_c_str("path", path)?)
|
||||
}())
|
||||
}
|
||||
|
||||
/// Add policy data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.add_data
|
||||
/// * `data`: JSON encoded value to be used as policy data.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_add_data_json(
|
||||
engine: *mut RegorusEngine,
|
||||
data: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.add_data(regorus::Value::from_json_str(&from_c_str("data", data)?)?)
|
||||
}())
|
||||
}
|
||||
|
||||
/// Get list of loaded Rego packages as JSON.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_packages
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_get_packages(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
to_regorus_string_result(|| -> Result<String> {
|
||||
serde_json::to_string_pretty(&to_ref(engine)?.engine.get_packages()?)
|
||||
.map_err(anyhow::Error::msg)
|
||||
}())
|
||||
}
|
||||
|
||||
/// Get list of policies as JSON.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_get_policies(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
to_regorus_string_result(|| -> Result<String> {
|
||||
to_ref(engine)?.engine.get_policies_as_json()
|
||||
}())
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_add_data_from_json_file(
|
||||
engine: *mut RegorusEngine,
|
||||
path: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.add_data(regorus::Value::from_json_file(from_c_str("path", path)?)?)
|
||||
}())
|
||||
}
|
||||
|
||||
/// Clear policy data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_data
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_clear_data(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?.engine.clear_data();
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Set input.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_input
|
||||
/// * `input`: JSON encoded value to be used as input to query.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_set_input_json(
|
||||
engine: *mut RegorusEngine,
|
||||
input: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.set_input(regorus::Value::from_json_str(&from_c_str("input", input)?)?);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_set_input_from_json_file(
|
||||
engine: *mut RegorusEngine,
|
||||
path: *const c_char,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.set_input(regorus::Value::from_json_file(from_c_str("path", path)?)?);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Evaluate query.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_query
|
||||
/// * `query`: Rego expression to be evaluate.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_eval_query(
|
||||
engine: *mut RegorusEngine,
|
||||
query: *const c_char,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
let results = to_ref(engine)?
|
||||
.engine
|
||||
.eval_query(from_c_str("query", query)?, false)?;
|
||||
Ok(serde_json::to_string_pretty(&results)?)
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: to_c_str(out),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate specified rule.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_rule
|
||||
/// * `rule`: Path to the rule.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_eval_rule(
|
||||
engine: *mut RegorusEngine,
|
||||
rule: *const c_char,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.eval_rule(from_c_str("rule", rule)?)?
|
||||
.to_json_str()
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: to_c_str(out),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable/disable coverage.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage
|
||||
/// * `enable`: Whether to enable or disable coverage.
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "C" fn regorus_engine_set_enable_coverage(
|
||||
engine: *mut RegorusEngine,
|
||||
enable: bool,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?.engine.set_enable_coverage(enable);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Get coverage report.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "C" fn regorus_engine_get_coverage_report(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
Ok(serde_json::to_string_pretty(
|
||||
&to_ref(engine)?.engine.get_coverage_report()?,
|
||||
)?)
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: to_c_str(out),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable/disable strict builtin errors.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_strict_builtin_errors
|
||||
/// * `strict`: Whether to raise errors or return undefined on certain scenarios.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_set_strict_builtin_errors(
|
||||
engine: *mut RegorusEngine,
|
||||
strict: bool,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?.engine.set_strict_builtin_errors(strict);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Get pretty printed coverage report.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Report.html#method.to_string_pretty
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "C" fn regorus_engine_get_coverage_report_pretty(
|
||||
engine: *mut RegorusEngine,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
to_ref(engine)?
|
||||
.engine
|
||||
.get_coverage_report()?
|
||||
.to_string_pretty()
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: to_c_str(out),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear coverage data.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_coverage_data
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "coverage")]
|
||||
pub extern "C" fn regorus_engine_clear_coverage_data(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?.engine.clear_coverage_data();
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Whether to gather output of print statements.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_gather_prints
|
||||
/// * `enable`: Whether to enable or disable gathering print statements.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_set_gather_prints(
|
||||
engine: *mut RegorusEngine,
|
||||
enable: bool,
|
||||
) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
to_ref(engine)?.engine.set_gather_prints(enable);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Take all the gathered print statements.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.take_prints
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_take_prints(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
Ok(serde_json::to_string_pretty(
|
||||
&to_ref(engine)?.engine.take_prints()?,
|
||||
)?)
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: to_c_str(out),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get AST of policies.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_ast_as_json
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "ast")]
|
||||
pub extern "C" fn regorus_engine_get_ast_as_json(engine: *mut RegorusEngine) -> RegorusResult {
|
||||
let output = || -> Result<String> { to_ref(engine)?.engine.get_ast_as_json() }();
|
||||
match output {
|
||||
Ok(out) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: to_c_str(out),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the package names defined in each policy added to the engine.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_policy_package_names
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_engine_get_policy_package_names(
|
||||
engine: *mut RegorusEngine,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
serde_json::to_string_pretty(&to_ref(engine)?.engine.get_policy_package_names()?)
|
||||
.map_err(anyhow::Error::msg)
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: to_c_str(out),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the parameters defined in each policy added to the engine.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_policy_parameters
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_engine_get_policy_parameters(
|
||||
engine: *mut RegorusEngine,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<String> {
|
||||
serde_json::to_string_pretty(&to_ref(engine)?.engine.get_policy_parameters()?)
|
||||
.map_err(anyhow::Error::msg)
|
||||
}();
|
||||
match output {
|
||||
Ok(out) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: to_c_str(out),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable/disable rego v1.
|
||||
///
|
||||
/// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_rego_v0
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_engine_set_rego_v0(
|
||||
engine: *mut RegorusEngine,
|
||||
enable: bool,
|
||||
) -> RegorusResult {
|
||||
let output = || -> Result<()> {
|
||||
to_ref(engine)?.engine.set_rego_v0(enable);
|
||||
Ok(())
|
||||
}();
|
||||
match output {
|
||||
Ok(()) => RegorusResult {
|
||||
status: RegorusStatus::RegorusStatusOk,
|
||||
output: std::ptr::null_mut(),
|
||||
error_message: std::ptr::null_mut(),
|
||||
},
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "custom_allocator")]
|
||||
extern "C" {
|
||||
fn regorus_aligned_alloc(alignment: usize, size: usize) -> *mut u8;
|
||||
fn regorus_free(ptr: *mut u8);
|
||||
}
|
||||
|
||||
#[cfg(feature = "custom_allocator")]
|
||||
mod allocator {
|
||||
use std::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
struct RegorusAllocator {}
|
||||
|
||||
unsafe impl GlobalAlloc for RegorusAllocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
let size = layout.size();
|
||||
let align = layout.align();
|
||||
|
||||
crate::regorus_aligned_alloc(align, size)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||
crate::regorus_free(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: RegorusAllocator = RegorusAllocator {};
|
||||
}
|
||||
mod allocator;
|
||||
mod common;
|
||||
mod compile;
|
||||
mod compiled_policy;
|
||||
mod effect_registry;
|
||||
mod engine;
|
||||
mod schema_registry;
|
||||
mod target_registry;
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
//! Schema registry functions for FFI.
|
||||
//!
|
||||
//! These functions provide access to regorus's resource schema registry functionality,
|
||||
//! enabling registration and management of Azure Policy resource schemas.
|
||||
|
||||
#![cfg(feature = "azure_policy")]
|
||||
|
||||
use crate::common::{from_c_str, RegorusResult, RegorusStatus};
|
||||
use regorus::{registry::schemas, Schema};
|
||||
|
||||
use std::os::raw::c_char;
|
||||
|
||||
// Resource Schema Registry Functions
|
||||
|
||||
/// Register a resource schema from JSON with a given name.
|
||||
///
|
||||
/// # Parameters
|
||||
/// * `name` - Name to register the schema under
|
||||
/// * `schema_json` - JSON string representing the schema
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with success/error status.
|
||||
///
|
||||
/// # Safety
|
||||
/// All string parameters must be valid null-terminated UTF-8 strings.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_resource_schema_register(
|
||||
name: *const c_char,
|
||||
schema_json: *const c_char,
|
||||
) -> RegorusResult {
|
||||
let schema_name = match from_c_str(name) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidArgument,
|
||||
format!("Invalid schema name string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let schema_str = match from_c_str(schema_json) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidDataFormat,
|
||||
format!("Invalid schema JSON string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Parse schema from JSON
|
||||
let schema = match Schema::from_json_str(&schema_str) {
|
||||
Ok(schema) => schema,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidDataFormat,
|
||||
format!("Failed to parse schema JSON: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Register the schema
|
||||
match schemas::resource::register(schema_name, schema.into()) {
|
||||
Ok(()) => RegorusResult::ok_pointer(std::ptr::null_mut()),
|
||||
Err(e) => RegorusResult::err_with_message(
|
||||
RegorusStatus::Error,
|
||||
format!("Failed to register schema: {e}"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a resource schema with the given name exists.
|
||||
///
|
||||
/// # Parameters
|
||||
/// * `name` - Name of the schema to check
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with "true" or "false" string output.
|
||||
///
|
||||
/// # Safety
|
||||
/// The name parameter must be a valid null-terminated UTF-8 string.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_resource_schema_contains(name: *const c_char) -> RegorusResult {
|
||||
let schema_name = match from_c_str(name) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidArgument,
|
||||
format!("Invalid schema name string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let contains = schemas::resource::contains(&schema_name);
|
||||
RegorusResult::ok_bool(contains)
|
||||
}
|
||||
|
||||
/// Get the number of registered resource schemas.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with the count as a string.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_resource_schema_len() -> RegorusResult {
|
||||
let count = schemas::resource::len();
|
||||
RegorusResult::ok_int(count as i64)
|
||||
}
|
||||
|
||||
/// Check if the resource schema registry is empty.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with "true" or "false" string output.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_resource_schema_is_empty() -> RegorusResult {
|
||||
let is_empty = schemas::resource::is_empty();
|
||||
RegorusResult::ok_bool(is_empty)
|
||||
}
|
||||
|
||||
/// List all registered resource schema names as a JSON array.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with a JSON array of schema names.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_resource_schema_list_names() -> RegorusResult {
|
||||
let names = schemas::resource::list_names();
|
||||
match serde_json::to_string(&names) {
|
||||
Ok(json_str) => RegorusResult::ok_string(json_str),
|
||||
Err(e) => RegorusResult::err_with_message(
|
||||
RegorusStatus::Error,
|
||||
format!("Failed to serialize schema names to JSON: {e}"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a resource schema by name.
|
||||
///
|
||||
/// # Parameters
|
||||
/// * `name` - Name of the schema to remove
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with "true" if removed, "false" if not found.
|
||||
///
|
||||
/// # Safety
|
||||
/// The name parameter must be a valid null-terminated UTF-8 string.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_resource_schema_remove(name: *const c_char) -> RegorusResult {
|
||||
let schema_name = match from_c_str(name) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidArgument,
|
||||
format!("Invalid schema name string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let removed = schemas::resource::remove(&schema_name).is_some();
|
||||
RegorusResult::ok_bool(removed)
|
||||
}
|
||||
|
||||
/// Clear all resource schemas from the registry.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with success status.
|
||||
#[cfg(feature = "azure_policy")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_resource_schema_clear() -> RegorusResult {
|
||||
schemas::resource::clear();
|
||||
RegorusResult::ok_pointer(std::ptr::null_mut())
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#![cfg(feature = "azure_policy")]
|
||||
|
||||
use crate::common::*;
|
||||
use anyhow::Result;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// * `target_json`: JSON encoded target definition
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_register_target_from_json(target_json: *const c_char) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
let target_str = from_c_str(target_json)?;
|
||||
let target = regorus::Target::from_json_str(&target_str)?;
|
||||
regorus::registry::targets::register(regorus::Rc::new(target))?;
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Check if a target is registered.
|
||||
///
|
||||
/// # Parameters
|
||||
/// * `name` - Name of the target to check
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with boolean value indicating if the target is registered.
|
||||
///
|
||||
/// # Safety
|
||||
/// The name parameter must be a valid null-terminated UTF-8 string.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_target_registry_contains(name: *const c_char) -> RegorusResult {
|
||||
let target_name = match from_c_str(name) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidArgument,
|
||||
format!("Invalid target name string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let contains = regorus::registry::targets::contains(&target_name);
|
||||
RegorusResult::ok_bool(contains)
|
||||
}
|
||||
|
||||
/// Get a list of all registered target names as JSON array.
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_target_registry_list_names() -> RegorusResult {
|
||||
let names = regorus::registry::targets::list_names();
|
||||
let output = serde_json::to_string_pretty(&names).map_err(anyhow::Error::msg);
|
||||
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a target from the registry by name.
|
||||
///
|
||||
/// * `name`: The target name to remove
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_target_registry_remove(name: *const c_char) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
let name_str = from_c_str(name)?;
|
||||
regorus::registry::targets::remove(&name_str);
|
||||
Ok(())
|
||||
}())
|
||||
}
|
||||
|
||||
/// Clear all targets from the registry.
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_target_registry_clear() -> RegorusResult {
|
||||
regorus::registry::targets::clear();
|
||||
RegorusResult::ok_void()
|
||||
}
|
||||
|
||||
/// Get the number of registered targets.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with the count as an integer value.
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_target_registry_len() -> RegorusResult {
|
||||
let count = regorus::registry::targets::len();
|
||||
RegorusResult::ok_int(count as i64)
|
||||
}
|
||||
|
||||
/// Check if the target registry is empty.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a RegorusResult with boolean value indicating if the registry is empty.
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_target_registry_is_empty() -> RegorusResult {
|
||||
let is_empty = regorus::registry::targets::is_empty();
|
||||
RegorusResult::ok_bool(is_empty)
|
||||
}
|
||||
@@ -32,7 +32,7 @@ func (e *Engine) SetRegoV0(enable bool) error {
|
||||
result := C.regorus_engine_set_rego_v0(e.e, C.bool(enable))
|
||||
defer C.regorus_result_drop(result)
|
||||
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func (e *Engine) AddPolicy(path string, rego string) (string, error) {
|
||||
|
||||
result := C.regorus_engine_add_policy(e.e, path_c, rego_c)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return C.GoString(result.output), nil
|
||||
@@ -60,7 +60,7 @@ func (e *Engine) AddPolicyFromFile(path string) (string, error) {
|
||||
|
||||
result := C.regorus_engine_add_policy_from_file(e.e, path_c)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return C.GoString(result.output), nil
|
||||
@@ -69,7 +69,7 @@ func (e *Engine) AddPolicyFromFile(path string) (string, error) {
|
||||
func (e *Engine) GetPackages() (string, error) {
|
||||
result := C.regorus_engine_get_packages(e.e)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return C.GoString(result.output), nil
|
||||
@@ -78,7 +78,7 @@ func (e *Engine) GetPackages() (string, error) {
|
||||
func (e *Engine) GetPolicies() (string, error) {
|
||||
result := C.regorus_engine_get_policies(e.e)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return C.GoString(result.output), nil
|
||||
@@ -90,7 +90,7 @@ func (e *Engine) AddDataJson(data string) error {
|
||||
|
||||
result := C.regorus_engine_add_data_json(e.e, data_c)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return nil
|
||||
@@ -102,7 +102,7 @@ func (e *Engine) AddDataFromJsonFile(path string) error {
|
||||
|
||||
result := C.regorus_engine_add_data_from_json_file(e.e, path_c)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return nil
|
||||
@@ -114,7 +114,7 @@ func (e *Engine) SetInputJson(input string) error {
|
||||
|
||||
result := C.regorus_engine_set_input_json(e.e, input_c)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return nil
|
||||
@@ -126,7 +126,7 @@ func (e *Engine) SetInputFromJsonFile(path string) error {
|
||||
|
||||
result := C.regorus_engine_set_input_from_json_file(e.e, path_c)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return nil
|
||||
@@ -138,7 +138,7 @@ func (e *Engine) EvalQuery(query string) (string, error) {
|
||||
|
||||
result := C.regorus_engine_eval_query(e.e, query_c)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ func (e *Engine) EvalRule(rule string) (string, error) {
|
||||
|
||||
result := C.regorus_engine_eval_rule(e.e, rule_c)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ func (e *Engine) EvalRule(rule string) (string, error) {
|
||||
func (e *Engine) SetEnableCoverage(enable bool) error {
|
||||
result := C.regorus_engine_set_enable_coverage(e.e, C.bool(enable))
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return nil
|
||||
@@ -170,7 +170,7 @@ func (e *Engine) SetEnableCoverage(enable bool) error {
|
||||
func (e *Engine) ClearCoverageData() error {
|
||||
result := C.regorus_engine_clear_coverage_data(e.e)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return nil
|
||||
@@ -179,7 +179,7 @@ func (e *Engine) ClearCoverageData() error {
|
||||
func (e *Engine) GetCoverageReport() (string, error) {
|
||||
result := C.regorus_engine_get_coverage_report(e.e)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ func (e *Engine) GetCoverageReport() (string, error) {
|
||||
func (e *Engine) GetCoverageReportPretty() (string, error) {
|
||||
result := C.regorus_engine_get_coverage_report_pretty(e.e)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ func (e *Engine) GetCoverageReportPretty() (string, error) {
|
||||
func (e *Engine) SetGatherPrints(b bool) error {
|
||||
result := C.regorus_engine_set_gather_prints(e.e, C.bool(b))
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
return nil
|
||||
@@ -208,7 +208,7 @@ func (e *Engine) SetGatherPrints(b bool) error {
|
||||
func (e *Engine) TakePrints() (string, error) {
|
||||
result := C.regorus_engine_take_prints(e.e)
|
||||
defer C.regorus_result_drop(result)
|
||||
if result.status != C.RegorusStatusOk {
|
||||
if result.status != C.Ok {
|
||||
return "", fmt.Errorf("%s", C.GoString(result.error_message))
|
||||
}
|
||||
|
||||
|
||||
Generated
+29
-8
@@ -42,9 +42,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
@@ -435,7 +435,7 @@ dependencies = [
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"walkdir",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
@@ -689,9 +689,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.96"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0"
|
||||
checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -831,6 +831,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"thiserror 2.0.14",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
@@ -969,9 +970,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.104"
|
||||
version = "2.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
||||
checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -995,7 +996,16 @@ version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1009,6 +1019,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.8.1"
|
||||
|
||||
Generated
+27
-6
@@ -42,9 +42,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
@@ -681,9 +681,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.96"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0"
|
||||
checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -887,6 +887,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
@@ -1017,9 +1018,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.104"
|
||||
version = "2.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
||||
checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1043,6 +1044,26 @@ version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.8.1"
|
||||
|
||||
Generated
+27
-6
@@ -42,9 +42,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
@@ -761,9 +761,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.96"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0"
|
||||
checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -933,6 +933,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
@@ -1091,9 +1092,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.104"
|
||||
version = "2.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
||||
checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1117,6 +1118,26 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.8.1"
|
||||
|
||||
Generated
+27
-6
@@ -42,9 +42,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
@@ -670,9 +670,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.96"
|
||||
version = "1.0.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0"
|
||||
checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -812,6 +812,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
@@ -953,9 +954,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.104"
|
||||
version = "2.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
||||
checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -973,6 +974,26 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.8.1"
|
||||
|
||||
Reference in New Issue
Block a user