diff --git a/.github/workflows/test-csharp.yml b/.github/workflows/test-csharp.yml
index ce566e6..ff258e8 100644
--- a/.github/workflows/test-csharp.yml
+++ b/.github/workflows/test-csharp.yml
@@ -6,9 +6,101 @@ on:
pull_request:
branches: [ "main" ]
-jobs:
- test:
+jobs:
+ build-ffi:
+ name: 'Build Regorus FFI: (${{ matrix.runtime.target }})'
+ runs-on: ${{ matrix.runtime.os }}
+ strategy:
+ # let us get failures from other jobs even if one fails
+ fail-fast: false
+ matrix:
+ runtime:
+ - os: windows-latest
+ target: x86_64-pc-windows-msvc
+ libpath: |
+ **/release/regorus_ffi.dll
+ **/release/regorus_ffi.pdb
+ - os: ubuntu-latest
+ target: x86_64-unknown-linux-gnu
+ libpath: |
+ **/release/libregorus_ffi.so
+ # Disabled for now
+ #- os: macos-latest
+ # target: aarch64-apple-darwin
+ # libpath: |
+ # **/release/libregorus_ffi.dylib
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Build Regorus binding
+ run: cargo build -r --target ${{ matrix.runtime.target }}
+ working-directory: ./bindings/ffi
+
+ - name: Upload regorus ffi shared library
+ uses: actions/upload-artifact@v4
+ with:
+ name: regorus-ffi-artifacts-${{ matrix.runtime.target }}
+ # Note: The full path of each artifact relative to . is preserved.
+ path: ${{ matrix.runtime.libpath }}
+ if-no-files-found: error
+ retention-days: 1
+
+ build-nuget:
+ name: 'Build Regorus nuget'
runs-on: ubuntu-latest
+ needs: build-ffi
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - uses: actions/setup-dotnet@v4
+
+ - name: Download regorus ffi shared libraries
+ uses: actions/download-artifact@v4
+ with:
+ pattern: regorus-ffi-artifacts-*
+ merge-multiple: true
+ path: ./bindings/csharp/Regorus/tmp
+
+ - name: Display regorus ffi artifacts
+ run: ls -R ./bindings/csharp/Regorus/tmp
+
+ # Note that we need to supply the target folder within the folder where artifacts are downloaded.
+ - name: Build Regorus binding
+ run: dotnet build /p:Configuration=Release /p:RegorusFFIArtifactsDir=./tmp/bindings/ffi/target
+ working-directory: ./bindings/csharp/Regorus
+
+ - name: Pack
+ run: dotnet pack /p:RegorusFFIArtifactsDir=./tmp/bindings/ffi/target
+ working-directory: ./bindings/csharp/Regorus
+
+ - name: Upload Regorus nuget
+ uses: actions/upload-artifact@v4
+ with:
+ name: regorus-nuget
+ path: bindings/csharp/Regorus/bin/Release/Regorus*.nupkg
+ if-no-files-found: error
+ retention-days: 1
+
+ test-nuget:
+ name: 'Test Regorus Nuget: (${{ matrix.runtime.target }})'
+ needs: build-nuget
+ runs-on: ${{ matrix.runtime.os }}
+ strategy:
+ # let us get failures from other jobs even if one fails
+ fail-fast: false
+ matrix:
+ runtime:
+ - os: windows-latest
+ target: x86_64-pc-windows-msvc
+ - os: ubuntu-latest
+ target: x86_64-unknown-linux-gnu
+ #- os: macos-latest
+ # target: aarch64-apple-darwin
steps:
- name: Checkout repository
uses: actions/checkout@v4
@@ -17,10 +109,21 @@ jobs:
- uses: actions/setup-dotnet@v4
- - name: Build
- run: dotnet build
- working-directory: ./bindings/csharp/net8.0
+ - name: Download regorus nuget
+ uses: actions/download-artifact@v4
+ with:
+ name: regorus-nuget
+ path: ./bindings/csharp/TestApp/regorus-nuget/
+
+ - name: Restore Test App
+ run: dotnet restore /p:RestoreSources=./regorus-nuget/
+ working-directory: ./bindings/csharp/TestApp
- - name: Run
- run: LD_LIBRARY_PATH=. dotnet run
- working-directory: ./bindings/csharp/net8.0
+ - name: Build Test App 8.0
+ run: dotnet build --framework net8.0
+ working-directory: ./bindings/csharp/TestApp
+
+ - name: Run Test App 8.0
+ run: dotnet run --framework net8.0
+ working-directory: ./bindings/csharp/TestApp
+
\ No newline at end of file
diff --git a/.github/workflows/test-csharp40.yml b/.github/workflows/test-csharp40.yml
deleted file mode 100644
index bb06ac9..0000000
--- a/.github/workflows/test-csharp40.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: bindings/csharp40
-
-on:
- push:
- branches: [ "main" ]
- pull_request:
- branches: [ "main" ]
-
-jobs:
- test:
- runs-on: windows-latest
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - uses: actions/setup-dotnet@v1
- with:
- dotnet-version: "5.0.x"
-
- - name: Build
- run: dotnet build
- working-directory: ./bindings/csharp/net40
-
- - name: Run
- run: dotnet run
- working-directory: ./bindings/csharp/net40
diff --git a/.gitignore b/.gitignore
index 51f0ed6..4b69e48 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,4 +27,9 @@ worktrees/
bindings/ffi/regorus.h
bindings/ffi/regorus.ffi.hpp
-bindings/*/target
\ No newline at end of file
+bindings/*/target
+
+# C# build folders
+**bin
+**obj
+*.sln
\ No newline at end of file
diff --git a/bindings/csharp/Regorus/Regorus.cs b/bindings/csharp/Regorus/Regorus.cs
new file mode 100644
index 0000000..69c5e9a
--- /dev/null
+++ b/bindings/csharp/Regorus/Regorus.cs
@@ -0,0 +1,240 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+
+#nullable enable
+namespace Regorus
+{
+ public unsafe sealed class Engine : System.IDisposable
+ {
+ private Regorus.Internal.RegorusEngine* E;
+ // Detect redundant Dispose() calls in a thread-safe manner.
+ // _isDisposed == 0 means Dispose(bool) has not been called yet.
+ // _isDisposed == 1 means Dispose(bool) has been already called.
+ private int isDisposed;
+
+ public Engine()
+ {
+ E = Regorus.Internal.API.regorus_engine_new();
+ }
+
+ public void Dispose()
+ {
+ Dispose(disposing: true);
+
+ // This object will be cleaned up by the Dispose method.
+ // Therefore, call GC.SuppressFinalize to
+ // take this object off the finalization queue
+ // and prevent finalization code for this object
+ // from executing a second time.
+ GC.SuppressFinalize(this);
+ }
+
+ // Dispose(bool disposing) executes in two distinct scenarios.
+ // If disposing equals true, the method has been called directly
+ // or indirectly by a user's code. Managed and unmanaged resources
+ // can be disposed.
+ // If disposing equals false, the method has been called by the
+ // runtime from inside the finalizer and you should not reference
+ // other objects. Only unmanaged resources can be disposed.
+ void Dispose(bool disposing)
+ {
+ // In case _isDisposed is 0, atomically set it to 1.
+ // Enter the branch only if the original value is 0.
+ if (System.Threading.Interlocked.CompareExchange(ref isDisposed, 1, 0) == 0)
+ {
+ // If disposing equals true, dispose all managed
+ // and unmanaged resources.
+ if (disposing)
+ {
+ // No managed resource to dispose.
+ }
+
+ // Call the appropriate methods to clean up
+ // unmanaged resources here.
+ // If disposing is false,
+ // only the following code is executed.
+ if (E != null)
+ {
+ Regorus.Internal.API.regorus_engine_drop(E);
+ E = null;
+ }
+
+ }
+ }
+
+ // Use C# finalizer syntax for finalization code.
+ // This finalizer will run only if the Dispose method
+ // does not get called.
+ ~Engine() => Dispose(disposing: false);
+
+ // Helper for implementing Clone
+ private Engine(Internal.RegorusEngine* engine)
+ {
+ this.E = engine;
+ }
+
+ public Engine Clone() => new(Internal.API.regorus_engine_clone(E));
+
+ byte[] NullTerminatedUTF8Bytes(string s)
+ {
+ return Encoding.UTF8.GetBytes(s + char.MinValue);
+ }
+
+ public string? AddPolicy(string path, string rego)
+ {
+ var pathBytes = NullTerminatedUTF8Bytes(path);
+ var regoBytes = NullTerminatedUTF8Bytes(rego);
+
+
+ fixed (byte* pathPtr = pathBytes)
+ {
+ fixed (byte* regoPtr = regoBytes)
+ {
+ return CheckAndDropResult(Regorus.Internal.API.regorus_engine_add_policy(E, pathPtr, regoPtr));
+ }
+ }
+
+ }
+
+ public void SetRegoV0(bool enable)
+ {
+ CheckAndDropResult(Regorus.Internal.API.regorus_engine_set_rego_v0(E, enable));
+ }
+
+ public string? AddPolicyFromFile(string path)
+ {
+ var pathBytes = NullTerminatedUTF8Bytes(path);
+ fixed (byte* pathPtr = pathBytes)
+ {
+ return CheckAndDropResult(Regorus.Internal.API.regorus_engine_add_policy_from_file(E, pathPtr));
+ }
+
+ }
+
+ public void AddDataJson(string data)
+ {
+ var dataBytes = NullTerminatedUTF8Bytes(data);
+ fixed (byte* dataPtr = dataBytes)
+ {
+ CheckAndDropResult(Regorus.Internal.API.regorus_engine_add_data_json(E, dataPtr));
+ }
+
+ }
+
+ public void AddDataFromJsonFile(string path)
+ {
+ var pathBytes = NullTerminatedUTF8Bytes(path);
+ fixed (byte* pathPtr = pathBytes)
+ {
+ CheckAndDropResult(Regorus.Internal.API.regorus_engine_add_data_from_json_file(E, pathPtr));
+ }
+
+ }
+
+ public void SetInputJson(string input)
+ {
+ var inputBytes = NullTerminatedUTF8Bytes(input);
+ fixed (byte* inputPtr = inputBytes)
+ {
+ CheckAndDropResult(Regorus.Internal.API.regorus_engine_set_input_json(E, inputPtr));
+ }
+ }
+
+ public void SetInputFromJsonFile(string path)
+ {
+ var pathBytes = NullTerminatedUTF8Bytes(path);
+ fixed (byte* pathPtr = pathBytes)
+ {
+ CheckAndDropResult(Regorus.Internal.API.regorus_engine_set_input_from_json_file(E, pathPtr));
+ }
+ }
+
+ public string? EvalQuery(string query)
+ {
+ var queryBytes = NullTerminatedUTF8Bytes(query);
+ fixed (byte* queryPtr = queryBytes)
+ {
+ return CheckAndDropResult(Regorus.Internal.API.regorus_engine_eval_query(E, queryPtr));
+ }
+ }
+
+ public string? EvalRule(string rule)
+ {
+ var ruleBytes = NullTerminatedUTF8Bytes(rule);
+ fixed (byte* rulePtr = ruleBytes)
+ {
+ return CheckAndDropResult(Regorus.Internal.API.regorus_engine_eval_query(E, rulePtr));
+ }
+ }
+
+ public void SetEnableCoverage(bool enable)
+ {
+ CheckAndDropResult(Regorus.Internal.API.regorus_engine_set_enable_coverage(E, enable));
+ }
+
+ public void ClearCoverageData()
+ {
+ CheckAndDropResult(Regorus.Internal.API.regorus_engine_clear_coverage_data(E));
+ }
+
+ public string? GetCoverageReport()
+ {
+ return CheckAndDropResult(Regorus.Internal.API.regorus_engine_get_coverage_report(E));
+ }
+
+ public string? GetCoverageReportPretty()
+ {
+ return CheckAndDropResult(Regorus.Internal.API.regorus_engine_get_coverage_report_pretty(E));
+ }
+
+ public void SetGatherPrints(bool enable)
+ {
+ CheckAndDropResult(Regorus.Internal.API.regorus_engine_set_gather_prints(E, enable));
+ }
+
+ public string? TakePrints()
+ {
+ return CheckAndDropResult(Regorus.Internal.API.regorus_engine_take_prints(E));
+ }
+
+
+
+ string? StringFromUTF8(IntPtr ptr)
+ {
+
+#if NETSTANDARD2_1
+ return System.Runtime.InteropServices.Marshal.PtrToStringUTF8(ptr);
+#else
+ int len = 0;
+ while (Marshal.ReadByte(ptr, len) != 0) { ++len; }
+ byte[] buffer = new byte[len];
+ Marshal.Copy(ptr, buffer, 0, buffer.Length);
+ return Encoding.UTF8.GetString(buffer);
+#endif
+ }
+
+ string? CheckAndDropResult(Regorus.Internal.RegorusResult result)
+ {
+ if (result.status != Regorus.Internal.RegorusStatus.RegorusStatusOk)
+ {
+ var message = StringFromUTF8((IntPtr)result.error_message);
+ var ex = new Exception(message);
+ Regorus.Internal.API.regorus_result_drop(result);
+ throw ex;
+ }
+
+ var resultString = "";
+ if (result.output is not null)
+ {
+ resultString = StringFromUTF8((IntPtr)result.output);
+ }
+ Regorus.Internal.API.regorus_result_drop(result);
+ return resultString;
+ }
+ }
+}
diff --git a/bindings/csharp/Regorus/Regorus.csproj b/bindings/csharp/Regorus/Regorus.csproj
new file mode 100644
index 0000000..39686cb
--- /dev/null
+++ b/bindings/csharp/Regorus/Regorus.csproj
@@ -0,0 +1,48 @@
+
+
+
+ Library
+ Microsoft.Regorus
+ netstandard2.0;netstandard2.1
+ true
+ 0.4.0-preview.1
+ 10.0
+ README.md
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bindings/csharp/Regorus/RegorusFFI.cs b/bindings/csharp/Regorus/RegorusFFI.cs
new file mode 100644
index 0000000..796c6cb
--- /dev/null
+++ b/bindings/csharp/Regorus/RegorusFFI.cs
@@ -0,0 +1,219 @@
+//
+// This code is generated by csbindgen.
+// DON'T CHANGE THIS DIRECTLY.
+//
+#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";
+
+
+
+ ///
+ /// Drop a `RegorusResult`.
+ ///
+ /// `output` and `error_message` strings are not valid after drop.
+ ///
+ [DllImport(__DllName, EntryPoint = "regorus_result_drop", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+ internal static extern void regorus_result_drop(RegorusResult r);
+
+ ///
+ /// Construct a new Engine
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html
+ ///
+ [DllImport(__DllName, EntryPoint = "regorus_engine_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+ internal static extern RegorusEngine* regorus_engine_new();
+
+ ///
+ /// Clone a [`RegorusEngine`]
+ ///
+ /// To avoid having to parse same policy again, the engine can be cloned
+ /// after policies and data have been added.
+ ///
+ ///
+ [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);
+
+ ///
+ /// 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.
+ ///
+ [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);
+
+ ///
+ /// 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.
+ ///
+ [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);
+
+ ///
+ /// Get list of loaded Rego packages as JSON.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_packages
+ ///
+ [DllImport(__DllName, EntryPoint = "regorus_engine_get_packages", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+ internal static extern RegorusResult regorus_engine_get_packages(RegorusEngine* engine);
+
+ ///
+ /// Get list of policies as JSON.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_policies
+ ///
+ [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);
+
+ ///
+ /// Clear policy data.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_data
+ ///
+ [DllImport(__DllName, EntryPoint = "regorus_engine_clear_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+ internal static extern RegorusResult regorus_engine_clear_data(RegorusEngine* engine);
+
+ ///
+ /// 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.
+ ///
+ [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);
+
+ ///
+ /// Evaluate query.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_query
+ /// * `query`: Rego expression to be evaluate.
+ ///
+ [DllImport(__DllName, EntryPoint = "regorus_engine_eval_query", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+ internal static extern RegorusResult regorus_engine_eval_query(RegorusEngine* engine, byte* query);
+
+ ///
+ /// Evaluate specified rule.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.eval_rule
+ /// * `rule`: Path to the rule.
+ ///
+ [DllImport(__DllName, EntryPoint = "regorus_engine_eval_rule", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+ internal static extern RegorusResult regorus_engine_eval_rule(RegorusEngine* engine, byte* rule);
+
+ ///
+ /// Enable/disable coverage.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_enable_coverage
+ /// * `enable`: Whether to enable or disable coverage.
+ ///
+ [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);
+
+ ///
+ /// Get coverage report.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.get_coverage_report
+ ///
+ [DllImport(__DllName, EntryPoint = "regorus_engine_get_coverage_report", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+ internal static extern RegorusResult regorus_engine_get_coverage_report(RegorusEngine* engine);
+
+ ///
+ /// Get pretty printed coverage report.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/coverage/struct.Report.html#method.to_string_pretty
+ ///
+ [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);
+
+ ///
+ /// Clear coverage data.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.clear_coverage_data
+ ///
+ [DllImport(__DllName, EntryPoint = "regorus_engine_clear_coverage_data", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+ internal static extern RegorusResult regorus_engine_clear_coverage_data(RegorusEngine* engine);
+
+ ///
+ /// 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.
+ ///
+ [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);
+
+ ///
+ /// Take all the gathered print statements.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.take_prints
+ ///
+ [DllImport(__DllName, EntryPoint = "regorus_engine_take_prints", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+ internal static extern RegorusResult regorus_engine_take_prints(RegorusEngine* engine);
+
+ ///
+ /// Get AST of policies.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/coverage/struct.Engine.html#method.get_ast_as_json
+ ///
+ [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);
+
+ ///
+ /// Enable/disable rego v1.
+ ///
+ /// See https://docs.rs/regorus/latest/regorus/struct.Engine.html#method.set_rego_v0
+ ///
+ [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,
+ }
+
+
+}
diff --git a/bindings/csharp/Regorus/docs/README.md b/bindings/csharp/Regorus/docs/README.md
new file mode 100644
index 0000000..28c2dd0
--- /dev/null
+++ b/bindings/csharp/Regorus/docs/README.md
@@ -0,0 +1 @@
+C# Bindings for Regorus
\ No newline at end of file
diff --git a/bindings/csharp/net8.0/Program.cs b/bindings/csharp/TestApp/Program.cs
similarity index 65%
rename from bindings/csharp/net8.0/Program.cs
rename to bindings/csharp/TestApp/Program.cs
index fff52a9..565470b 100644
--- a/bindings/csharp/net8.0/Program.cs
+++ b/bindings/csharp/TestApp/Program.cs
@@ -1,69 +1,71 @@
-//-----------------------------------------------------------------------
-//
-// Copyright (c)2012 Microsoft. All rights reserved.
-//
-//
-// Contains code to test the Regorus class for C#
-// and .NET 8.0 bindings.
-//
-//-----------------------------------------------------------------------
-
-using System.Diagnostics;
-
-long nanosecPerTick = (1000L*1000L*1000L) / Stopwatch.Frequency;
-var w = new Stopwatch();
-
-
-// Force load of modules.
-{
- var _e = new Regorus.Engine();
- var _j = System.Text.Json.JsonDocument.Parse("{}");
-}
-
-w.Restart();
-
-var engine = new Regorus.Engine();
-engine.SetRegoV0(true);
-
-w.Stop();
-var newEngineTicks = w.ElapsedTicks;
-
-
-w.Restart();
-
-// Load policies and data.
-engine.AddPolicyFromFile("../../../tests/aci/framework.rego");
-engine.AddPolicyFromFile("../../../tests/aci/api.rego");
-engine.AddPolicyFromFile("../../../tests/aci/policy.rego");
-engine.AddDataFromJsonFile("../../../tests/aci/data.json");
-
-
-w.Stop();
-var loadPoliciesTicks = w.ElapsedTicks;
-
-
-w.Restart();
-
-// Set input and eval rule.
-engine.SetInputFromJsonFile("../../../tests/aci/input.json");
-var value = engine.EvalQuery("data.framework.mount_overlay");
-var valueDoc = System.Text.Json.JsonDocument.Parse(value);
-
-w.Stop();
-var evalTicks = w.ElapsedTicks;
-
-Console.WriteLine("{0}", valueDoc);
-
-
-Console.WriteLine("Engine creation took {0} msecs", (newEngineTicks*nanosecPerTick)/(1000.0*1000.0));
-Console.WriteLine("Load policies and data took {0} msecs", (loadPoliciesTicks*nanosecPerTick)/(1000.0*1000.0));
-Console.WriteLine("EvalQuery took {0} msecs", (evalTicks*nanosecPerTick)/(1000.0*1000.0));
-
-engine = new Regorus.Engine();
-engine.AddPolicy(
- "test.rego",
- "package test\nx = 1\nmessage = `Hello`");
-
-engine.SetEnableCoverage(true);
-Console.WriteLine("{0}", engine.EvalRule("data.test.message"));
-Console.WriteLine("{0}", engine.GetCoverageReportPretty());
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Diagnostics;
+
+
+long nanosecPerTick = (1000L * 1000L * 1000L) / Stopwatch.Frequency;
+var w = new Stopwatch();
+
+
+// Force load of modules.
+{
+ var _e = new Regorus.Engine();
+#if NET8_0_OR_GREATER
+ var _j = System.Text.Json.JsonDocument.Parse("{}");
+#endif
+}
+
+w.Restart();
+
+var engine = new Regorus.Engine();
+engine.SetRegoV0(true);
+
+w.Stop();
+var newEngineTicks = w.ElapsedTicks;
+
+
+w.Restart();
+
+// Load policies and data.
+engine.AddPolicyFromFile("../../../tests/aci/framework.rego");
+engine.AddPolicyFromFile("../../../tests/aci/api.rego");
+engine.AddPolicyFromFile("../../../tests/aci/policy.rego");
+engine.AddDataFromJsonFile("../../../tests/aci/data.json");
+
+
+w.Stop();
+var loadPoliciesTicks = w.ElapsedTicks;
+
+
+w.Restart();
+
+// Set input and eval rule.
+engine.SetInputFromJsonFile("../../../tests/aci/input.json");
+var value = engine.EvalQuery("data.framework.mount_overlay");
+
+#if NET8_0_OR_GREATER
+var valueDoc = System.Text.Json.JsonDocument.Parse(value);
+
+w.Stop();
+var evalTicks = w.ElapsedTicks;
+
+Console.WriteLine("{0}", valueDoc);
+#else
+w.Stop();
+var evalTicks = w.ElapsedTicks;
+#endif
+
+
+Console.WriteLine("Engine creation took {0} msecs", (newEngineTicks * nanosecPerTick) / (1000.0 * 1000.0));
+Console.WriteLine("Load policies and data took {0} msecs", (loadPoliciesTicks * nanosecPerTick) / (1000.0 * 1000.0));
+Console.WriteLine("EvalQuery took {0} msecs", (evalTicks * nanosecPerTick) / (1000.0 * 1000.0));
+
+engine = new Regorus.Engine();
+engine.AddPolicy(
+ "test.rego",
+ "package test\nx = 1\nmessage = `Hello`");
+
+engine.SetEnableCoverage(true);
+Console.WriteLine("{0}", engine.EvalRule("data.test.message"));
+Console.WriteLine("{0}", engine.GetCoverageReportPretty());
diff --git a/bindings/csharp/TestApp/TestApp.csproj b/bindings/csharp/TestApp/TestApp.csproj
new file mode 100644
index 0000000..4f8ddc0
--- /dev/null
+++ b/bindings/csharp/TestApp/TestApp.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net8.0
+ TestApp
+ enable
+ enable
+ true
+ 10.0
+
+
+
+
+
+
diff --git a/bindings/csharp/net40/Program.cs b/bindings/csharp/net40/Program.cs
deleted file mode 100644
index 6236564..0000000
--- a/bindings/csharp/net40/Program.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-//-----------------------------------------------------------------------
-//
-// Copyright (c)2012 Microsoft. All rights reserved.
-//
-//
-// Contains code to test the Regorus Policy Engine base class for C#
-// and .NET4.0 bindings. It can be built and tested in Windows only.
-//
-//-----------------------------------------------------------------------
-using System;
-using System.Text;
-
-using System.Diagnostics;
-using Microsoft.WindowsAzure.Regorus.IaaS;
-
-namespace regoregorus_test
-{
- class Program
- {
- static void Main(string[] args)
- {
- long nanosecPerTick = (1000L * 1000L * 1000L) / Stopwatch.Frequency;
- var w = new Stopwatch();
- w.Restart();
-
- var engine = new RegorusPolicyEngine();
-
- w.Stop();
- var newEngineTicks = w.ElapsedTicks;
-
-
- w.Restart();
-
- // Load policies and data.
- engine.AddPolicyFromFile("../../../examples/extension_list/agent_extension_policy.rego");
- engine.AddDataFromJsonFile("../../../examples/extension_list/agent-extension-data-allow-only.json");
-
-
- w.Stop();
- var loadPoliciesTicks = w.ElapsedTicks;
-
-
- w.Restart();
-
- // Set input and eval query.
- engine.SetInputFromJsonFile("../../../examples/extension_list/agent-extension-input.json");
- var results = engine.EvalQuery("data.agent_extension_policy.extensions_to_download=x");
- Console.WriteLine("Download query test: \n {0}", results);
-
- results = engine.EvalQuery("data.agent_extension_policy.extensions_validated");
-
- Console.WriteLine("Signing validation test: \n {0}", results);
-
- engine.Dispose();
-
- w.Stop();
- var evalTicks = w.ElapsedTicks;
-
- Console.WriteLine("Engine creation took {0} msecs", (newEngineTicks * nanosecPerTick) / (1000.0 * 1000.0));
- Console.WriteLine("Load policies and data took {0} msecs", (loadPoliciesTicks * nanosecPerTick) / (1000.0 * 1000.0));
- Console.WriteLine("EvalQuery and print results took {0} msecs", (evalTicks * nanosecPerTick) / (1000.0 * 1000.0));
- }
- }
-}
-
diff --git a/bindings/csharp/net40/README b/bindings/csharp/net40/README
deleted file mode 100644
index 68bf4d3..0000000
--- a/bindings/csharp/net40/README
+++ /dev/null
@@ -1,4 +0,0 @@
-The Regorus C# binding library can be built via command "dotnet build". We can use the Regorus C# binding library built from this
-directory to create a Nuget. This Nuget will contain the Regorus C# binding library with definitions that
-work for .NET framework 4.0 (net40) and above. Note the Nuget can only be created after the binding library has been built.
-RegorusCsharp-Lib-x64.nuspec is built for x64 architecture.
\ No newline at end of file
diff --git a/bindings/csharp/net40/Regorus.cs b/bindings/csharp/net40/Regorus.cs
deleted file mode 100644
index c995e63..0000000
--- a/bindings/csharp/net40/Regorus.cs
+++ /dev/null
@@ -1,220 +0,0 @@
-//-----------------------------------------------------------------------
-//
-// Copyright (c)2012 Microsoft. All rights reserved.
-//
-//
-// Contains code for the Regorus Policy Engine base class for C# and
-// .NET4.0 bindings. Currently this base class is not thread-safe. Make
-// sure we use it in a signle-threaded environment or add additional
-// protection when using it.
-//
-//-----------------------------------------------------------------------
-
-
-using System;
-using System.Text;
-using System.IO;
-using System.Threading;
-
-namespace Microsoft.WindowsAzure.Regorus.IaaS
-{
-
- public class RegorusPolicyEngine : ICloneable, IDisposable
- {
- unsafe private RegorusFFI.RegorusEngine* E;
-
- public RegorusPolicyEngine()
- {
- unsafe
- {
- E = RegorusFFI.API.regorus_engine_new();
- }
- }
-
-
- public void Dispose()
- {
- unsafe
- {
- if (E != null)
- {
- RegorusFFI.API.regorus_engine_drop(E);
- // to avoid Dispose() being called multiple times by mistake.
- E = null;
- }
-
- }
-
- }
-
- public object Clone()
- {
- var clone = (RegorusPolicyEngine)this.MemberwiseClone();
- unsafe
- {
- clone.E = RegorusFFI.API.regorus_engine_clone(E);
- }
- return clone;
-
- }
-
- byte[] NullTerminatedUTF8Bytes(string s)
- {
- return Encoding.UTF8.GetBytes(s + char.MinValue);
- }
- public void SetRegoV0(bool enable)
- {
- unsafe
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_set_rego_v0(E, enable));
- }
- }
-
- public void AddPolicy(string path, string rego)
- {
- var pathBytes = NullTerminatedUTF8Bytes(path);
- var regoBytes = NullTerminatedUTF8Bytes(rego);
-
- unsafe
- {
- fixed (byte* pathPtr = pathBytes)
- {
- fixed (byte* regoPtr = regoBytes)
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy(E, pathPtr, regoPtr));
- }
- }
- }
- }
-
- public void AddPolicyFromFile(string path)
- {
- var pathBytes = NullTerminatedUTF8Bytes(path);
-
- unsafe
- {
- fixed (byte* pathPtr = pathBytes)
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy_from_file(E, pathPtr));
- }
- }
- }
-
- public void AddPolicyFromPath(string path)
- {
- if (!Directory.Exists(path))
- {
- return;
- }
-
- string[] regoFiles = Directory.GetFiles(path, "*.rego", SearchOption.AllDirectories);
- foreach (string file in regoFiles)
- {
- AddPolicyFromFile(file);
- }
- }
-
- public void AddDataJson(string data)
- {
- var dataBytes = NullTerminatedUTF8Bytes(data);
-
- unsafe
- {
- fixed (byte* dataPtr = dataBytes)
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_json(E, dataPtr));
- }
- }
- }
-
- public void AddDataFromJsonFile(string path)
- {
- var pathBytes = NullTerminatedUTF8Bytes(path);
-
- unsafe
- {
- fixed (byte* pathPtr = pathBytes)
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_from_json_file(E, pathPtr));
-
- }
- }
- }
-
- public void SetInputJson(string input)
- {
- var inputBytes = NullTerminatedUTF8Bytes(input);
-
- unsafe
- {
- fixed (byte* inputPtr = inputBytes)
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_json(E, inputPtr));
- }
- }
- }
-
- public void SetInputFromJsonFile(string path)
- {
- var pathBytes = NullTerminatedUTF8Bytes(path);
-
- unsafe
- {
- fixed (byte* pathPtr = pathBytes)
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_from_json_file(E, pathPtr));
- }
- }
- }
-
- public string EvalQuery(string query)
- {
- var queryBytes = NullTerminatedUTF8Bytes(query);
-
- var resultJson = "";
- unsafe
- {
- fixed (byte* queryPtr = queryBytes)
- {
- var result = RegorusFFI.API.regorus_engine_eval_query(E, queryPtr);
- if (result.status == RegorusFFI.RegorusStatus.RegorusStatusOk)
- {
- if (result.output != null)
- {
- resultJson = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)result.output);
- }
- RegorusFFI.API.regorus_result_drop(result);
- }
- else
- {
- CheckAndDropResult(result);
- }
- }
- }
- if (resultJson != null)
- {
- return resultJson;
- }
- else
- {
- return "";
- }
- }
-
- void CheckAndDropResult(RegorusFFI.RegorusResult result)
- {
- if (result.status != RegorusFFI.RegorusStatus.RegorusStatusOk)
- {
- unsafe
- {
- var message = System.Runtime.InteropServices.Marshal.PtrToStringAnsi((IntPtr)result.error_message);
- var ex = new Exception(message);
- RegorusFFI.API.regorus_result_drop(result);
- throw ex;
- }
- }
- RegorusFFI.API.regorus_result_drop(result);
- }
-
- }
-}
diff --git a/bindings/csharp/net40/RegorusCsharp-Lib-x64.nuspec b/bindings/csharp/net40/RegorusCsharp-Lib-x64.nuspec
deleted file mode 100644
index 8f8956c..0000000
--- a/bindings/csharp/net40/RegorusCsharp-Lib-x64.nuspec
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- RegorusCsharp-Lib-x64
- 0.2.1
- RegorusCsharp-Lib-x64
- yangjie@microsoft.com
- yangjie@microsoft.com
- https://www.microsoft.com
- false
- Regorus C# library for x64
- remove Regorus.cs from Nuget
- Copyright (C) Microsoft Corp
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/bindings/csharp/net40/regorus-test.csproj b/bindings/csharp/net40/regorus-test.csproj
deleted file mode 100644
index 3e06e3d..0000000
--- a/bindings/csharp/net40/regorus-test.csproj
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- Exe
- net40
- regorus_test
- regoregorus_test.Program
- enable
- true
-
-
-
-
-
diff --git a/bindings/csharp/net8.0/Regorus.cs b/bindings/csharp/net8.0/Regorus.cs
deleted file mode 100644
index 51aa0da..0000000
--- a/bindings/csharp/net8.0/Regorus.cs
+++ /dev/null
@@ -1,236 +0,0 @@
-using System.Text;
-
-namespace Regorus
-{
- public class Exception : System.Exception
- {
- public Exception(string? message) : base(message) { }
- }
-
- public class Engine : ICloneable
- {
- unsafe private RegorusFFI.RegorusEngine* E;
- public Engine()
- {
- unsafe
- {
- E = RegorusFFI.API.regorus_engine_new();
- }
- }
-
- public object Clone()
- {
- var clone = (Engine)this.MemberwiseClone();
- unsafe
- {
- clone.E = RegorusFFI.API.regorus_engine_clone(E);
- }
- return clone;
-
- }
-
- byte[] NullTerminatedUTF8Bytes(string s)
- {
- return Encoding.UTF8.GetBytes(s + char.MinValue);
- }
-
- public string AddPolicy(string path, string rego)
- {
- var pathBytes = NullTerminatedUTF8Bytes(path);
- var regoBytes = NullTerminatedUTF8Bytes(rego);
-
- unsafe
- {
- fixed (byte* pathPtr = pathBytes)
- {
- fixed (byte* regoPtr = regoBytes)
- {
- return CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy(E, pathPtr, regoPtr));
- }
- }
- }
- }
-
- public void SetRegoV0(bool enable)
- {
- unsafe
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_set_rego_v0(E, enable));
- }
- }
-
- public string AddPolicyFromFile(string path)
- {
- var pathBytes = NullTerminatedUTF8Bytes(path);
-
- unsafe
- {
- fixed (byte* pathPtr = pathBytes)
- {
- return CheckAndDropResult(RegorusFFI.API.regorus_engine_add_policy_from_file(E, pathPtr));
- }
- }
- }
-
- public void AddDataJson(string data)
- {
- var dataBytes = NullTerminatedUTF8Bytes(data);
-
- unsafe
- {
- fixed (byte* dataPtr = dataBytes)
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_json(E, dataPtr));
- }
- }
- }
-
- public void AddDataFromJsonFile(string path)
- {
- var pathBytes = NullTerminatedUTF8Bytes(path);
-
- unsafe
- {
- fixed (byte* pathPtr = pathBytes)
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_add_data_from_json_file(E, pathPtr));
- }
- }
- }
-
- public void SetInputJson(string input)
- {
- var inputBytes = NullTerminatedUTF8Bytes(input);
-
- unsafe
- {
- fixed (byte* inputPtr = inputBytes)
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_json(E, inputPtr));
- }
- }
- }
-
- public void SetInputFromJsonFile(string path)
- {
- var pathBytes = NullTerminatedUTF8Bytes(path);
-
- unsafe
- {
- fixed (byte* pathPtr = pathBytes)
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_set_input_from_json_file(E, pathPtr));
- }
- }
- }
-
- public string EvalQuery(string query)
- {
- var queryBytes = NullTerminatedUTF8Bytes(query);
-
- unsafe
- {
- fixed (byte* queryPtr = queryBytes)
- {
- return CheckAndDropResult(RegorusFFI.API.regorus_engine_eval_query(E, queryPtr));
- }
- }
- }
-
- public string EvalRule(string rule)
- {
- var ruleBytes = NullTerminatedUTF8Bytes(rule);
-
- unsafe
- {
- fixed (byte* rulePtr = ruleBytes)
- {
- return CheckAndDropResult(RegorusFFI.API.regorus_engine_eval_query(E, rulePtr));
- }
- }
- }
-
- public void SetEnableCoverage(bool enable)
- {
- unsafe
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_set_enable_coverage(E, enable));
- }
- }
-
- public void ClearCoverageData()
- {
- unsafe
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_clear_coverage_data(E));
- }
- }
-
- public string GetCoverageReport()
- {
- unsafe
- {
- return CheckAndDropResult(RegorusFFI.API.regorus_engine_get_coverage_report(E));
- }
- }
-
- public string GetCoverageReportPretty()
- {
- unsafe
- {
- return CheckAndDropResult(RegorusFFI.API.regorus_engine_get_coverage_report_pretty(E));
- }
- }
-
- public void SetGatherPrints(bool enable)
- {
- unsafe
- {
- CheckAndDropResult(RegorusFFI.API.regorus_engine_set_gather_prints(E, enable));
- }
- }
-
- public string TakePrints()
- {
- unsafe
- {
- return CheckAndDropResult(RegorusFFI.API.regorus_engine_take_prints(E));
- }
- }
-
- ~Engine()
- {
- unsafe
- {
- RegorusFFI.API.regorus_engine_drop(E);
- }
- }
-
-
- string CheckAndDropResult(RegorusFFI.RegorusResult result)
- {
- if (result.status != RegorusFFI.RegorusStatus.RegorusStatusOk)
- {
- unsafe
- {
- var message = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((IntPtr)result.error_message);
- var ex = new Exception(message);
- RegorusFFI.API.regorus_result_drop(result);
- throw ex;
- }
- }
-
- var resultString = "";
- unsafe
- {
- if (result.output is not null)
- {
- resultString = System.Runtime.InteropServices.Marshal.PtrToStringUTF8((IntPtr)result.output);
- }
- RegorusFFI.API.regorus_result_drop(result);
- }
- return resultString;
- }
-
- }
-}
diff --git a/bindings/csharp/net8.0/regorus-test.csproj b/bindings/csharp/net8.0/regorus-test.csproj
deleted file mode 100644
index 05fec4b..0000000
--- a/bindings/csharp/net8.0/regorus-test.csproj
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- Exe
- net8.0
- regorus_test
- enable
- enable
- true
-
-
-
-
-
diff --git a/bindings/ffi/build.rs b/bindings/ffi/build.rs
index 5c0ca06..ac20a59 100644
--- a/bindings/ffi/build.rs
+++ b/bindings/ffi/build.rs
@@ -26,7 +26,7 @@ fn main() {
.input_extern_file("src/lib.rs")
.csharp_dll_name("regorus_ffi")
.csharp_class_name("API")
- .csharp_namespace("RegorusFFI")
+ .csharp_namespace("Regorus.Internal")
.generate_csharp_file("./RegorusFFI.g.cs")
.unwrap();
}