From 962c0cc459eb87e42b9545c5616157bfff87f7f1 Mon Sep 17 00:00:00 2001 From: Anthony Martin <38542602+anthony-c-martin@users.noreply.github.com> Date: Wed, 23 Apr 2025 09:01:51 -0400 Subject: [PATCH] Add C# test examples (#397) --- .devcontainer/devcontainer.json | 13 +- .github/workflows/test-csharp.yml | 19 +- .gitignore | 3 +- .../csharp/Regorus.Tests/Regorus.Tests.csproj | 22 +++ bindings/csharp/Regorus.Tests/RegorusTests.cs | 176 ++++++++++++++++++ bindings/csharp/global.json | 2 +- 6 files changed, 218 insertions(+), 17 deletions(-) create mode 100644 bindings/csharp/Regorus.Tests/Regorus.Tests.csproj create mode 100644 bindings/csharp/Regorus.Tests/RegorusTests.cs diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 8d65a11..63985dd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,11 +4,20 @@ "name": "Rust", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile "image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye", + "customizations": { + "vscode": { + "extensions": [ + "ms-dotnettools.csharp", + "ms-dotnettools.csdevkit" + ] + } + }, "features": { - "ghcr.io/devcontainers/features/dotnet:2": {}, + "ghcr.io/devcontainers/features/dotnet:2": { + "version": "8.0" + }, "ghcr.io/devcontainers/features/python:1": {} } - // Use 'mounts' to make the cargo cache persistent in a Docker Volume. // "mounts": [ // { diff --git a/.github/workflows/test-csharp.yml b/.github/workflows/test-csharp.yml index fad9d3f..66b5edf 100644 --- a/.github/workflows/test-csharp.yml +++ b/.github/workflows/test-csharp.yml @@ -121,17 +121,12 @@ jobs: 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 + path: ./bindings/csharp/Regorus.Tests/regorus-nuget/ - - name: Build Test App 8.0 - run: dotnet build --framework net8.0 - working-directory: ./bindings/csharp/TestApp + - name: Restore Regorus.Tests + run: dotnet restore /p:RestoreAdditionalProjectSources=./regorus-nuget + working-directory: ./bindings/csharp/Regorus.Tests - - name: Run Test App 8.0 - run: dotnet run --framework net8.0 - working-directory: ./bindings/csharp/TestApp - \ No newline at end of file + - name: Run Regorus.Tests + run: dotnet test --no-restore + working-directory: ./bindings/csharp/Regorus.Tests \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6f7cf72..1bd9f24 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,4 @@ bindings/*/target # C# build folders **bin -**obj -*.sln \ No newline at end of file +**obj \ No newline at end of file diff --git a/bindings/csharp/Regorus.Tests/Regorus.Tests.csproj b/bindings/csharp/Regorus.Tests/Regorus.Tests.csproj new file mode 100644 index 0000000..8cd9812 --- /dev/null +++ b/bindings/csharp/Regorus.Tests/Regorus.Tests.csproj @@ -0,0 +1,22 @@ + + + Enable + net8.0 + true + + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bindings/csharp/Regorus.Tests/RegorusTests.cs b/bindings/csharp/Regorus.Tests/RegorusTests.cs new file mode 100644 index 0000000..c0b341f --- /dev/null +++ b/bindings/csharp/Regorus.Tests/RegorusTests.cs @@ -0,0 +1,176 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Regorus.Tests; + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Text.Json.Nodes; + +[TestClass] +public class RegorusTests +{ + [TestMethod] + public void Basic_evaluation_succeeds() + { + using var engine = new Engine(); + engine.AddPolicy( + "test.rego", + "package test\nx = 1\nmessage = `Hello`"); + + var result = engine.EvalRule("data.test.message"); + + Assert.AreEqual("\"Hello\"", result); + } + + [TestMethod] + public void Evaluation_using_file_policies_succeeds() + { + using var engine = new Engine(); + engine.SetRegoV0(true); + + // 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"); + + // Set input and eval rule. + engine.SetInputFromJsonFile("tests/aci/input.json"); + var result = engine.EvalRule("data.framework.mount_overlay"); + + var expected = """ +{ + "allowed": true, + "metadata": [ + { + "action": "add", + "key": "container0", + "name": "matches", + "value": [ + { + "allow_elevated": true, + "allow_stdio_access": false, + "capabilities": { + "ambient": [ + "CAP_SYS_ADMIN" + ], + "bounding": [ + "CAP_SYS_ADMIN" + ], + "effective": [ + "CAP_SYS_ADMIN" + ], + "inheritable": [ + "CAP_SYS_ADMIN" + ], + "permitted": [ + "CAP_SYS_ADMIN" + ] + }, + "command": [ + "rustc", + "--help" + ], + "env_rules": [ + { + "pattern": "PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": true, + "strategy": "string" + }, + { + "pattern": "RUSTUP_HOME=/usr/local/rustup", + "required": true, + "strategy": "string" + }, + { + "pattern": "CARGO_HOME=/usr/local/cargo", + "required": true, + "strategy": "string" + }, + { + "pattern": "RUST_VERSION=1.52.1", + "required": true, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "PREFIX_.+=.+", + "required": false, + "strategy": "re2" + } + ], + "exec_processes": [ + { + "command": [ + "top" + ], + "signals": [] + } + ], + "layers": [ + "fe84c9d5bfddd07a2624d00333cf13c1a9c941f3a261f13ead44fc6a93bc0e7a", + "4dedae42847c704da891a28c25d32201a1ae440bce2aecccfa8e6f03b97a6a6c", + "41d64cdeb347bf236b4c13b7403b633ff11f1cf94dbc7cf881a44d6da88c5156", + "eb36921e1f82af46dfe248ef8f1b3afb6a5230a64181d960d10237a08cd73c79", + "e769d7487cc314d3ee748a4440805317c19262c7acd2fdbdb0d47d2e4613a15c", + "1b80f120dbd88e4355d6241b519c3e25290215c469516b49dece9cf07175a766" + ], + "mounts": [ + { + "destination": "/container/path/one", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///host/path/one", + "type": "bind" + }, + { + "destination": "/container/path/two", + "options": [ + "rbind", + "rshared", + "ro" + ], + "source": "sandbox:///host/path/two", + "type": "bind" + } + ], + "no_new_privileges": true, + "seccomp_profile_sha256": "", + "signals": [], + "user": { + "group_idnames": [ + { + "pattern": "", + "strategy": "any" + } + ], + "umask": "0022", + "user_idname": { + "pattern": "", + "strategy": "any" + } + }, + "working_dir": "/home/user" + } + ] + }, + { + "action": "add", + "key": "/run/gcs/c/container0/rootfs", + "name": "overlayTargets", + "value": true + } + ] +} +"""; + + Assert.IsTrue(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(result!)), $"Actual: {result}"); + } +} \ No newline at end of file diff --git a/bindings/csharp/global.json b/bindings/csharp/global.json index a6a3854..a811d8b 100644 --- a/bindings/csharp/global.json +++ b/bindings/csharp/global.json @@ -4,7 +4,7 @@ }, "sdk": { "allowPrerelease": false, - "version": "8.0.407", + "version": "8.0.408", "rollForward": "disable" } } \ No newline at end of file