From 9da96ed9e04e7d00d6af55860fd5c9bcf063903e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:10:22 -0400 Subject: [PATCH] =?UTF-8?q?chore:=20=F0=9F=90=9D=20Update=20SDK=20-=201=20?= =?UTF-8?q?-=20Generate=201.3.6=20(#71)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: regenerated with OpenAPI Doc , Speakeasy CLI 1.390.7 * Update project file to version 1.3.6 --------- Co-authored-by: speakeasybot Co-authored-by: GitHub Actions --- .speakeasy/gen.lock | 8 +- .speakeasy/gen.yaml | 2 +- .speakeasy/workflow.lock | 6 +- RELEASES.md | 12 +- Styra/Opa/OpenApi/OpaApiClient.cs | 6 +- Styra/Opa/Styra.Opa.csproj | 2 +- test/SmokeTest.Tests/EOPAContainerFixture.cs | 76 +- test/SmokeTest.Tests/HighLevelTest.cs | 1386 +++++++++--------- test/SmokeTest.Tests/OPAContainerFixture.cs | 62 +- test/SmokeTest.Tests/OpenApiTest.cs | 490 +++---- 10 files changed, 1030 insertions(+), 1020 deletions(-) diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index c15a6f1..ec6b82c 100755 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -3,10 +3,10 @@ id: f1a8c321-72a7-41c5-8f5e-3d925aeafa1a management: docChecksum: 54d33facef3aa19f358d15ab44e34141 docVersion: 0.2.0 - speakeasyVersion: 1.390.1 - generationVersion: 2.409.0 - releaseVersion: 1.3.5 - configChecksum: b92bf2ecb6758e2136783f47b7716616 + speakeasyVersion: 1.390.7 + generationVersion: 2.409.8 + releaseVersion: 1.3.6 + configChecksum: c9d3e694b16f805c25c1ce062ec9f62f repoURL: https://github.com/StyraInc/opa-csharp.git repoSubDirectory: Styra/Opa/OpenApi/ published: true diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index bc76302..90aaf1d 100755 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -12,7 +12,7 @@ generation: auth: oAuth2ClientCredentialsEnabled: false csharp: - version: 1.3.5 + version: 1.3.6 additionalDependencies: [] author: Styra clientServerStatusCodesAsErrors: true diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index 8c30c5d..caba5d9 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -1,8 +1,8 @@ -speakeasyVersion: 1.390.1 +speakeasyVersion: 1.390.7 sources: openapi: sourceNamespace: openapi - sourceRevisionDigest: sha256:a012c80888ddba9f1721a61c3965541749b4108b38a64fd9ec79b8559c6e966c + sourceRevisionDigest: sha256:9eaf842c0774fbf6d90f0022dee2795b9f0897771384d139d544ae9323f91ea7 sourceBlobDigest: sha256:f76f9d1e8be466eef2d0e9612845ce19f9a5f507682e92d7a4355b3b13eaa921 tags: - latest @@ -11,7 +11,7 @@ targets: first-target: source: openapi sourceNamespace: openapi - sourceRevisionDigest: sha256:a012c80888ddba9f1721a61c3965541749b4108b38a64fd9ec79b8559c6e966c + sourceRevisionDigest: sha256:9eaf842c0774fbf6d90f0022dee2795b9f0897771384d139d544ae9323f91ea7 sourceBlobDigest: sha256:f76f9d1e8be466eef2d0e9612845ce19f9a5f507682e92d7a4355b3b13eaa921 outLocation: /github/workspace/repo workflow: diff --git a/RELEASES.md b/RELEASES.md index 087d575..3d0edf0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -275,4 +275,14 @@ Based on: ### Generated - [csharp v1.3.5] . ### Releases -- [NuGet v1.3.5] https://www.nuget.org/packages/Styra.Opa.OpenApi/1.3.5 - . \ No newline at end of file +- [NuGet v1.3.5] https://www.nuget.org/packages/Styra.Opa.OpenApi/1.3.5 - . + +## 2024-09-05 20:05:55 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.390.7 (2.409.8) https://github.com/speakeasy-api/speakeasy +### Generated +- [csharp v1.3.6] . +### Releases +- [NuGet v1.3.6] https://www.nuget.org/packages/Styra.Opa.OpenApi/1.3.6 - . \ No newline at end of file diff --git a/Styra/Opa/OpenApi/OpaApiClient.cs b/Styra/Opa/OpenApi/OpaApiClient.cs index cbf053f..772c20b 100644 --- a/Styra/Opa/OpenApi/OpaApiClient.cs +++ b/Styra/Opa/OpenApi/OpaApiClient.cs @@ -103,10 +103,10 @@ public class OpaApiClient: IOpaApiClient public SDKConfig SDKConfiguration { get; private set; } private const string _language = "csharp"; - private const string _sdkVersion = "1.3.5"; - private const string _sdkGenVersion = "2.409.0"; + private const string _sdkVersion = "1.3.6"; + private const string _sdkGenVersion = "2.409.8"; private const string _openapiDocVersion = "0.2.0"; - private const string _userAgent = "speakeasy-sdk/csharp 1.3.5 2.409.0 0.2.0 Styra.Opa.OpenApi"; + private const string _userAgent = "speakeasy-sdk/csharp 1.3.6 2.409.8 0.2.0 Styra.Opa.OpenApi"; private string _serverUrl = ""; private int _serverIndex = 0; private ISpeakeasyHttpClient _client; diff --git a/Styra/Opa/Styra.Opa.csproj b/Styra/Opa/Styra.Opa.csproj index 4640c3b..91ec9b2 100644 --- a/Styra/Opa/Styra.Opa.csproj +++ b/Styra/Opa/Styra.Opa.csproj @@ -2,7 +2,7 @@ true Styra.Opa - 1.3.5 + 1.3.6 Styra net6.0 enable diff --git a/test/SmokeTest.Tests/EOPAContainerFixture.cs b/test/SmokeTest.Tests/EOPAContainerFixture.cs index d8f6383..15ff3a5 100644 --- a/test/SmokeTest.Tests/EOPAContainerFixture.cs +++ b/test/SmokeTest.Tests/EOPAContainerFixture.cs @@ -1,55 +1,55 @@ namespace SmokeTest.Tests; public class EOPAContainerFixture : IAsyncLifetime { - // Note: We disable this warning because we control when/how the constructor - // will be invoked for this class. + // Note: We disable this warning because we control when/how the constructor + // will be invoked for this class. #pragma warning disable CS8618 - private IContainer _container; + private IContainer _container; #pragma warning restore CS8618 - public async Task InitializeAsync() - { - string[] startupFiles = { + public async Task InitializeAsync() + { + string[] startupFiles = { "testdata/policy.rego", "testdata/weird_name.rego", "testdata/simple/system.rego", "testdata/condfail.rego", "testdata/data.json" }; - string[] opaCmd = { "run", "--server", "--addr=0.0.0.0:8181", "--disable-telemetry" }; - var startupCommand = new List().Concat(opaCmd).Concat(startupFiles).ToArray(); + string[] opaCmd = { "run", "--server", "--addr=0.0.0.0:8181", "--disable-telemetry" }; + var startupCommand = new List().Concat(opaCmd).Concat(startupFiles).ToArray(); - // Create a new instance of a container. - var container = new ContainerBuilder() - .WithImage("ghcr.io/styrainc/enterprise-opa:1.23.0") - .WithEnvironment("EOPA_LICENSE_TOKEN", Environment.GetEnvironmentVariable("EOPA_LICENSE_TOKEN")) - .WithEnvironment("EOPA_LICENSE_KEY", Environment.GetEnvironmentVariable("EOPA_LICENSE_KEY")) - // Bind port 8181 of the container to a random port on the host. - .WithPortBinding(8181, true) - .WithCommand(startupCommand) - // Map our policy and data files into the container instance. - .WithResourceMapping(new DirectoryInfo("testdata"), "/testdata/") - // Wait until the HTTP endpoint of the container is available. - .WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(r => r.ForPort(8181).ForPath("/health"))) - //.WithOutputConsumer(Consume.RedirectStdoutAndStderrToConsole()) // DEBUG - // Build the container configuration. - .Build(); + // Create a new instance of a container. + var container = new ContainerBuilder() + .WithImage("ghcr.io/styrainc/enterprise-opa:1.23.0") + .WithEnvironment("EOPA_LICENSE_TOKEN", Environment.GetEnvironmentVariable("EOPA_LICENSE_TOKEN")) + .WithEnvironment("EOPA_LICENSE_KEY", Environment.GetEnvironmentVariable("EOPA_LICENSE_KEY")) + // Bind port 8181 of the container to a random port on the host. + .WithPortBinding(8181, true) + .WithCommand(startupCommand) + // Map our policy and data files into the container instance. + .WithResourceMapping(new DirectoryInfo("testdata"), "/testdata/") + // Wait until the HTTP endpoint of the container is available. + .WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(r => r.ForPort(8181).ForPath("/health"))) + //.WithOutputConsumer(Consume.RedirectStdoutAndStderrToConsole()) // DEBUG + // Build the container configuration. + .Build(); - // Start the container. - await container.StartAsync() - .ConfigureAwait(false); - // DEBUG: - // var (stderr, stdout) = await container.GetLogsAsync(default); - // Console.WriteLine("STDERR: {0}", stderr); - // Console.WriteLine("STDOUT: {0}", stdout); + // Start the container. + await container.StartAsync() + .ConfigureAwait(false); + // DEBUG: + // var (stderr, stdout) = await container.GetLogsAsync(default); + // Console.WriteLine("STDERR: {0}", stderr); + // Console.WriteLine("STDOUT: {0}", stdout); - _container = container; - } - public async Task DisposeAsync() - { - await _container.DisposeAsync(); - } + _container = container; + } + public async Task DisposeAsync() + { + await _container.DisposeAsync(); + } - // Expose the container for tests - public IContainer GetContainer() => _container; + // Expose the container for tests + public IContainer GetContainer() => _container; } diff --git a/test/SmokeTest.Tests/HighLevelTest.cs b/test/SmokeTest.Tests/HighLevelTest.cs index 6ed0a88..fe86fa4 100644 --- a/test/SmokeTest.Tests/HighLevelTest.cs +++ b/test/SmokeTest.Tests/HighLevelTest.cs @@ -8,830 +8,830 @@ namespace SmokeTest.Tests; // Used to verify presence of log messages in tests. public class ListLogger : ILogger -{ - public List Logs { get; } = new List(); - - IDisposable ILogger.BeginScope(TState state) - { - return null!; - } - - public bool IsEnabled(LogLevel logLevel) => true; - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) - { - if (formatter == null) { throw new ArgumentNullException(nameof(formatter)); }; - - var message = formatter(state, exception); - if (!string.IsNullOrEmpty(message)) - { - Logs.Add(message); +{ + public List Logs { get; } = new List(); + + IDisposable ILogger.BeginScope(TState state) + { + return null!; + } + + public bool IsEnabled(LogLevel logLevel) => true; + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) + { + if (formatter == null) { throw new ArgumentNullException(nameof(formatter)); }; + + var message = formatter(state, exception); + if (!string.IsNullOrEmpty(message)) + { + Logs.Add(message); + } } - } } // Note(philip): Run with `--logger "console;verbosity=detailed"` to see logged messages. public class HighLevelTest : IClassFixture, IClassFixture -{ - private readonly ITestOutputHelper _testOutput; - public IContainer _containerOpa; - public IContainer _containerEopa; - - private class CustomRBACInputObject - { - - [JsonProperty("user")] - public string User = ""; - - [JsonProperty("action")] - public string Action = ""; - - [JsonProperty("object")] - public string Object = ""; - - [JsonProperty("type")] - public string Type = ""; - - [JsonIgnore] - public string UUID = System.Guid.NewGuid().ToString(); - - public CustomRBACInputObject() { } - - public CustomRBACInputObject(string user, string action, string obj, string type) - { - User = user; - Action = action; - Object = obj; - Type = type; - } - } - - public class CustomRBACOutputObject - { - [JsonProperty("allow")] - public bool Allow = false; - - [JsonProperty("user_is_admin")] - public bool? IsAdmin; - - [JsonProperty("user_is_granted")] - public List? Grants; - - public CustomRBACOutputObject() { } - } - - public HighLevelTest(OPAContainerFixture opaFixture, EOPAContainerFixture eopaFixture, ITestOutputHelper output) - { - _containerOpa = opaFixture.GetContainer(); - _containerEopa = eopaFixture.GetContainer(); - _testOutput = output; - } - - private OpaClient GetOpaClient() - { - // Construct the request URI by specifying the scheme, hostname, assigned random host port, and the endpoint "uuid". - var requestUri = new UriBuilder(Uri.UriSchemeHttp, _containerOpa.Hostname, _containerOpa.GetMappedPublicPort(8181)).Uri; - return new OpaClient(serverUrl: requestUri.ToString()); - } - - private OpaClient GetOpaClientWithLogger(ILogger logger) - { - var requestUri = new UriBuilder(Uri.UriSchemeHttp, _containerOpa.Hostname, _containerOpa.GetMappedPublicPort(8181)).Uri; - return new OpaClient(serverUrl: requestUri.ToString(), logger: logger); - } - - private OpaClient GetEOpaClient() - { - var requestUri = new UriBuilder(Uri.UriSchemeHttp, _containerEopa.Hostname, _containerEopa.GetMappedPublicPort(8181)).Uri; - return new OpaClient(serverUrl: requestUri.ToString()); - } - - [Fact] - public async Task RBACCheckDictionaryTest() - { - var client = GetOpaClient(); - - var allow = await client.check("app/rbac/allow", new Dictionary() { +{ + private readonly ITestOutputHelper _testOutput; + public IContainer _containerOpa; + public IContainer _containerEopa; + + private class CustomRBACInputObject + { + + [JsonProperty("user")] + public string User = ""; + + [JsonProperty("action")] + public string Action = ""; + + [JsonProperty("object")] + public string Object = ""; + + [JsonProperty("type")] + public string Type = ""; + + [JsonIgnore] + public string UUID = System.Guid.NewGuid().ToString(); + + public CustomRBACInputObject() { } + + public CustomRBACInputObject(string user, string action, string obj, string type) + { + User = user; + Action = action; + Object = obj; + Type = type; + } + } + + public class CustomRBACOutputObject + { + [JsonProperty("allow")] + public bool Allow = false; + + [JsonProperty("user_is_admin")] + public bool? IsAdmin; + + [JsonProperty("user_is_granted")] + public List? Grants; + + public CustomRBACOutputObject() { } + } + + public HighLevelTest(OPAContainerFixture opaFixture, EOPAContainerFixture eopaFixture, ITestOutputHelper output) + { + _containerOpa = opaFixture.GetContainer(); + _containerEopa = eopaFixture.GetContainer(); + _testOutput = output; + } + + private OpaClient GetOpaClient() + { + // Construct the request URI by specifying the scheme, hostname, assigned random host port, and the endpoint "uuid". + var requestUri = new UriBuilder(Uri.UriSchemeHttp, _containerOpa.Hostname, _containerOpa.GetMappedPublicPort(8181)).Uri; + return new OpaClient(serverUrl: requestUri.ToString()); + } + + private OpaClient GetOpaClientWithLogger(ILogger logger) + { + var requestUri = new UriBuilder(Uri.UriSchemeHttp, _containerOpa.Hostname, _containerOpa.GetMappedPublicPort(8181)).Uri; + return new OpaClient(serverUrl: requestUri.ToString(), logger: logger); + } + + private OpaClient GetEOpaClient() + { + var requestUri = new UriBuilder(Uri.UriSchemeHttp, _containerEopa.Hostname, _containerEopa.GetMappedPublicPort(8181)).Uri; + return new OpaClient(serverUrl: requestUri.ToString()); + } + + [Fact] + public async Task RBACCheckDictionaryTest() + { + var client = GetOpaClient(); + + var allow = await client.check("app/rbac/allow", new Dictionary() { { "user", "alice" }, { "action", "read" }, { "object", "id123" }, { "type", "dog" }, - }); - - // BUG: This can fail as long as Speakeasy generates the upstream SDK with - // deserializers occurring in the same ordering as the OpenAPI spec. - Assert.True(allow); - } - - [Fact] - public async Task RBACCheckNullTest() - { - var client = GetOpaClient(); - - var allow = await client.check("app/rbac/allow"); - - Assert.False(allow); - } - - [Fact] - public async Task RBACCheckBoolTest() - { - var client = GetOpaClient(); - - var allow = await client.check("app/rbac/allow", true); - - Assert.False(allow); - } - - [Fact] - public async Task RBACCheckDoubleTest() - { - var client = GetOpaClient(); - - var allow = await client.check("app/rbac/allow", 42); - - Assert.False(allow); - } - - [Fact] - public async Task RBACCheckStringTest() - { - var client = GetOpaClient(); - - var allow = await client.check("app/rbac/allow", "alice"); - - Assert.False(allow); - } - - [Fact] - public async Task RBACCheckListObjTest() - { - var client = GetOpaClient(); - - var allow = await client.check("app/rbac/allow", new List() { "A", "B", "C", "D" }); - - Assert.False(allow); - } - - [Fact] - public async Task DictionaryTypeCoerceTest() - { - var client = GetOpaClient(); - - var input = new Dictionary() { + }); + + // BUG: This can fail as long as Speakeasy generates the upstream SDK with + // deserializers occurring in the same ordering as the OpenAPI spec. + Assert.True(allow); + } + + [Fact] + public async Task RBACCheckNullTest() + { + var client = GetOpaClient(); + + var allow = await client.check("app/rbac/allow"); + + Assert.False(allow); + } + + [Fact] + public async Task RBACCheckBoolTest() + { + var client = GetOpaClient(); + + var allow = await client.check("app/rbac/allow", true); + + Assert.False(allow); + } + + [Fact] + public async Task RBACCheckDoubleTest() + { + var client = GetOpaClient(); + + var allow = await client.check("app/rbac/allow", 42); + + Assert.False(allow); + } + + [Fact] + public async Task RBACCheckStringTest() + { + var client = GetOpaClient(); + + var allow = await client.check("app/rbac/allow", "alice"); + + Assert.False(allow); + } + + [Fact] + public async Task RBACCheckListObjTest() + { + var client = GetOpaClient(); + + var allow = await client.check("app/rbac/allow", new List() { "A", "B", "C", "D" }); + + Assert.False(allow); + } + + [Fact] + public async Task DictionaryTypeCoerceTest() + { + var client = GetOpaClient(); + + var input = new Dictionary() { { "user", "alice" }, { "action", "read" }, { "object", "id123" }, { "type", "dog" }, - }; - - var result = new Dictionary(); - - try - { - result = await client.evaluate>("app/rbac", input); - } - catch (OpaException e) - { - _testOutput.WriteLine("exception while making request against OPA: " + e.Message); - } - - var expected = new Dictionary() { + }; + + var result = new Dictionary(); + + try + { + result = await client.evaluate>("app/rbac", input); + } + catch (OpaException e) + { + _testOutput.WriteLine("exception while making request against OPA: " + e.Message); + } + + var expected = new Dictionary() { { "allow", true }, { "user_is_admin", true }, { "user_is_granted", new List()}, - }; - - Assert.NotNull(result); - Assert.Equivalent(expected, result); - Assert.Equal(expected.Count, result.Count); - } - - [Fact] - public async Task BooleanInputTypeCoerceTest() - { - var client = GetOpaClient(); - - var input = false; - - var result = new Dictionary(); - - try - { - result = await client.evaluate>("app/rbac", input); - } - catch (OpaException e) - { - _testOutput.WriteLine("exception while making request against OPA: " + e.Message); - } - - var expected = new Dictionary() { + }; + + Assert.NotNull(result); + Assert.Equivalent(expected, result); + Assert.Equal(expected.Count, result.Count); + } + + [Fact] + public async Task BooleanInputTypeCoerceTest() + { + var client = GetOpaClient(); + + var input = false; + + var result = new Dictionary(); + + try + { + result = await client.evaluate>("app/rbac", input); + } + catch (OpaException e) + { + _testOutput.WriteLine("exception while making request against OPA: " + e.Message); + } + + var expected = new Dictionary() { { "allow", false }, { "user_is_granted", new List()}, - }; - - Assert.NotNull(result); - Assert.Equivalent(expected, result); - Assert.Equal(expected.Count, result.Count); - } - - [Fact] - public async Task CustomClassInputTypeCoerceTest() - { - var client = GetOpaClient(); - - var input = new CustomRBACInputObject("alice", "read", "id123", "dog"); - - var result = new Dictionary(); - - try - { - result = await client.evaluate>("app/rbac", input); - } - catch (OpaException e) - { - _testOutput.WriteLine("exception while making request against OPA: " + e.Message); - } - - var expected = new Dictionary() { + }; + + Assert.NotNull(result); + Assert.Equivalent(expected, result); + Assert.Equal(expected.Count, result.Count); + } + + [Fact] + public async Task CustomClassInputTypeCoerceTest() + { + var client = GetOpaClient(); + + var input = new CustomRBACInputObject("alice", "read", "id123", "dog"); + + var result = new Dictionary(); + + try + { + result = await client.evaluate>("app/rbac", input); + } + catch (OpaException e) + { + _testOutput.WriteLine("exception while making request against OPA: " + e.Message); + } + + var expected = new Dictionary() { { "allow", true }, { "user_is_admin", true }, { "user_is_granted", new List()}, - }; - - Assert.NotNull(result); - Assert.Equivalent(expected, result); - Assert.Equal(expected.Count, result.Count); - } - - [Fact] - public async Task CustomClassOutputTypeCoerceTest() - { - var client = GetOpaClient(); - - var input = new CustomRBACInputObject("alice", "read", "id123", "dog"); - - var result = new CustomRBACOutputObject(); - try - { - var res = await client.evaluate("app/rbac", input); - if (res is CustomRBACOutputObject value) - { - result = value; - } - else - { - Assert.Fail("Test did not deserialize to a custom C# type properly."); - } - } - catch (OpaException e) - { - _testOutput.WriteLine("exception while making request against OPA: " + e.Message); - } - - var expected = new CustomRBACOutputObject() - { - Allow = true, - IsAdmin = true, - Grants = new List(), - }; - - Assert.NotNull(result); - Assert.Equivalent(expected, result); - } - - [Fact] - public async Task BadOutputTypeCoerceTest() - { - var client = GetOpaClient(); - - var input = new CustomRBACInputObject("alice", "read", "id123", "dog"); - - // Attempt to coerce an object return type into a bool. This should always fail! - await Assert.ThrowsAsync(async () => { var res = await client.evaluate("app/rbac", input); }); - } - - [Fact] - public async Task AnonymousObjectInputTypeCoerceTest() - { - var client = GetOpaClient(); - - // Relies on Newtonsoft.Json's default serialization rules. `object` is unused by - // the policy, thankfully, so we can get away with mangling that field's name. - var input = new { user = "alice", action = "read", _object = "id123", type = "dog" }; - - var result = new Dictionary(); - - try - { - result = await client.evaluate>("app/rbac", input); - } - catch (OpaException e) - { - _testOutput.WriteLine("exception while making request against OPA: " + e.Message); - } - - var expected = new Dictionary() { + }; + + Assert.NotNull(result); + Assert.Equivalent(expected, result); + Assert.Equal(expected.Count, result.Count); + } + + [Fact] + public async Task CustomClassOutputTypeCoerceTest() + { + var client = GetOpaClient(); + + var input = new CustomRBACInputObject("alice", "read", "id123", "dog"); + + var result = new CustomRBACOutputObject(); + try + { + var res = await client.evaluate("app/rbac", input); + if (res is CustomRBACOutputObject value) + { + result = value; + } + else + { + Assert.Fail("Test did not deserialize to a custom C# type properly."); + } + } + catch (OpaException e) + { + _testOutput.WriteLine("exception while making request against OPA: " + e.Message); + } + + var expected = new CustomRBACOutputObject() + { + Allow = true, + IsAdmin = true, + Grants = new List(), + }; + + Assert.NotNull(result); + Assert.Equivalent(expected, result); + } + + [Fact] + public async Task BadOutputTypeCoerceTest() + { + var client = GetOpaClient(); + + var input = new CustomRBACInputObject("alice", "read", "id123", "dog"); + + // Attempt to coerce an object return type into a bool. This should always fail! + await Assert.ThrowsAsync(async () => { var res = await client.evaluate("app/rbac", input); }); + } + + [Fact] + public async Task AnonymousObjectInputTypeCoerceTest() + { + var client = GetOpaClient(); + + // Relies on Newtonsoft.Json's default serialization rules. `object` is unused by + // the policy, thankfully, so we can get away with mangling that field's name. + var input = new { user = "alice", action = "read", _object = "id123", type = "dog" }; + + var result = new Dictionary(); + + try + { + result = await client.evaluate>("app/rbac", input); + } + catch (OpaException e) + { + _testOutput.WriteLine("exception while making request against OPA: " + e.Message); + } + + var expected = new Dictionary() { { "allow", true }, { "user_is_admin", true }, { "user_is_granted", new List()}, - }; - - Assert.NotNull(result); - Assert.Equivalent(expected, result); - Assert.Equal(expected.Count, result.Count); - } - - [Fact] - public async Task EvaluateDefaultTest() - { - var client = GetOpaClient(); - - var res = await client.evaluateDefault>( - new Dictionary() { - { "hello", "world" }, - }); - - Assert.Equal(new Dictionary() { { "hello", "world" } }, res?.GetValueOrDefault("echo", "")); - } - - [Fact] - public async Task EvaluateDefaultWithAnonymousObjectInputTest() - { - var client = GetOpaClient(); - - var res = await client.evaluateDefault>(new { hello = "world" }); - - Assert.Equal(new Dictionary() { { "hello", "world" } }, res?.GetValueOrDefault("echo", "")); - } - - [Fact] - public async Task RBACBatchAllSuccessTest() - { - var client = GetEOpaClient(); - - var goodInput = new Dictionary() { + }; + + Assert.NotNull(result); + Assert.Equivalent(expected, result); + Assert.Equal(expected.Count, result.Count); + } + + [Fact] + public async Task EvaluateDefaultTest() + { + var client = GetOpaClient(); + + var res = await client.evaluateDefault>( + new Dictionary() { + { "hello", "world" }, + }); + + Assert.Equal(new Dictionary() { { "hello", "world" } }, res?.GetValueOrDefault("echo", "")); + } + + [Fact] + public async Task EvaluateDefaultWithAnonymousObjectInputTest() + { + var client = GetOpaClient(); + + var res = await client.evaluateDefault>(new { hello = "world" }); + + Assert.Equal(new Dictionary() { { "hello", "world" } }, res?.GetValueOrDefault("echo", "")); + } + + [Fact] + public async Task RBACBatchAllSuccessTest() + { + var client = GetEOpaClient(); + + var goodInput = new Dictionary() { { "user", "alice" }, { "action", "read" }, { "object", "id123" }, { "type", "dog" } - }; - - var (successes, failures) = await client.evaluateBatch("app/rbac/allow", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch("app/rbac/allow", new Dictionary>() { {"AAA", goodInput }, {"BBB", goodInput }, {"CCC", goodInput }, - }); - - var expSuccess = new OpaResult() { Result = Result.CreateBoolean(true) }; - - // Assert that the successes dictionary has all expected elements, and the - // failures dictionary is empty. - Assert.Equivalent(new Dictionary() { + }); + + var expSuccess = new OpaResult() { Result = Result.CreateBoolean(true) }; + + // Assert that the successes dictionary has all expected elements, and the + // failures dictionary is empty. + Assert.Equivalent(new Dictionary() { { "AAA", expSuccess }, { "BBB", expSuccess }, { "CCC", expSuccess }, - }, successes); - Assert.Empty(failures); - } - - [Fact] - public async Task RBACBatchMixedTest() - { - var client = GetEOpaClient(); - - var goodInput = new Dictionary() { + }, successes); + Assert.Empty(failures); + } + + [Fact] + public async Task RBACBatchMixedTest() + { + var client = GetEOpaClient(); + + var goodInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 1, 1} }, - }; - - var badInput = new Dictionary() { + }; + + var badInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 2, 1} }, - }; - - var (successes, failures) = await client.evaluateBatch("testmod/condfail", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch("testmod/condfail", new Dictionary>() { {"AAA", badInput }, {"BBB", goodInput }, {"CCC", badInput }, - }); - - var expSuccess = new OpaResult() - { - HttpStatusCode = "200", - Result = Result.CreateMapOfAny( - new Dictionary() { - {"p", new Dictionary() { { "1", 2 }, { "3", 4 } } } - } - ) - }; - var expError = new OpaError() - { - Code = "internal_error", - DecisionId = null, - HttpStatusCode = "500", - Message = "object insert conflict" - }; - - // Assert that the failures dictionary has all expected elements, and the - // successes dictionary is empty. - Assert.Equivalent(new OpaBatchResults() { { "BBB", expSuccess } }, successes); - Assert.Equivalent(new Dictionary() { + }); + + var expSuccess = new OpaResult() + { + HttpStatusCode = "200", + Result = Result.CreateMapOfAny( + new Dictionary() { + {"p", new Dictionary() { { "1", 2 }, { "3", 4 } } } + } + ) + }; + var expError = new OpaError() + { + Code = "internal_error", + DecisionId = null, + HttpStatusCode = "500", + Message = "object insert conflict" + }; + + // Assert that the failures dictionary has all expected elements, and the + // successes dictionary is empty. + Assert.Equivalent(new OpaBatchResults() { { "BBB", expSuccess } }, successes); + Assert.Equivalent(new Dictionary() { { "AAA", expError }, { "CCC", expError }, - }, failures); - - } - - [Fact] - public async Task RBACBatchAllFailuresTest() - { - var client = GetEOpaClient(); - - var badInput = new Dictionary() { + }, failures); + + } + + [Fact] + public async Task RBACBatchAllFailuresTest() + { + var client = GetEOpaClient(); + + var badInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 2, 1} }, - }; - - var (successes, failures) = await client.evaluateBatch("testmod/condfail", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch("testmod/condfail", new Dictionary>() { {"AAA", badInput }, {"BBB", badInput }, {"CCC", badInput }, - }); - - var expError = new OpaError() - { - Code = "internal_error", - DecisionId = null, - Message = "object insert conflict" - }; - - // Assert that the failures dictionary has all expected elements, and the - // successes dictionary is empty. - Assert.Empty(successes); - Assert.Equivalent(new Dictionary() { + }); + + var expError = new OpaError() + { + Code = "internal_error", + DecisionId = null, + Message = "object insert conflict" + }; + + // Assert that the failures dictionary has all expected elements, and the + // successes dictionary is empty. + Assert.Empty(successes); + Assert.Equivalent(new Dictionary() { { "AAA", expError }, { "BBB", expError }, { "CCC", expError }, - }, failures); - - } - - [Fact] - public async Task RBACBatchAllSuccessFallbackTest() - { - var client = GetOpaClient(); - - var goodInput = new Dictionary() { + }, failures); + + } + + [Fact] + public async Task RBACBatchAllSuccessFallbackTest() + { + var client = GetOpaClient(); + + var goodInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 1, 1} }, - }; - - var (successes, failures) = await client.evaluateBatch("testmod/condfail", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch("testmod/condfail", new Dictionary>() { {"AAA", goodInput }, {"BBB", goodInput }, {"CCC", goodInput }, - }); - - var expSuccess = new OpaResult() - { - Result = Result.CreateMapOfAny( - new Dictionary() { - {"p", new Dictionary() { { "1", 2 }, { "3", 4 } } } - } - ) - }; - - // Assert that the failures dictionary has all expected elements, and the - // successes dictionary is empty. - Assert.Equivalent(new OpaBatchResults() { + }); + + var expSuccess = new OpaResult() + { + Result = Result.CreateMapOfAny( + new Dictionary() { + {"p", new Dictionary() { { "1", 2 }, { "3", 4 } } } + } + ) + }; + + // Assert that the failures dictionary has all expected elements, and the + // successes dictionary is empty. + Assert.Equivalent(new OpaBatchResults() { { "BBB", expSuccess }, { "AAA", expSuccess }, { "CCC", expSuccess } - }, successes); - Assert.Empty(failures); - - } - - [Fact] - public async Task RBACBatchMixedFallbackTest() - { - var client = GetOpaClient(); - - var goodInput = new Dictionary() { + }, successes); + Assert.Empty(failures); + + } + + [Fact] + public async Task RBACBatchMixedFallbackTest() + { + var client = GetOpaClient(); + + var goodInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 1, 1} }, - }; - - var badInput = new Dictionary() { + }; + + var badInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 2, 1} }, - }; - - var (successes, failures) = await client.evaluateBatch("testmod/condfail", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch("testmod/condfail", new Dictionary>() { {"AAA", badInput }, {"BBB", goodInput }, {"CCC", badInput }, - }); - - var expSuccess = new OpaResult() - { - HttpStatusCode = "200", - Result = Result.CreateMapOfAny( - new Dictionary() { - {"p", new Dictionary() { { "1", 2 }, { "3", 4 } } } - } - ) - }; - var expError = new OpaError() - { - Code = "internal_error", - DecisionId = null, - HttpStatusCode = "500", - Message = "error(s) occurred while evaluating query" // Note: different error message for OPA mode. - }; - - // Assert that the failures dictionary has all expected elements, and the - // successes dictionary is empty. - Assert.Equivalent(new OpaBatchResults() { { "BBB", expSuccess } }, successes); - Assert.Equivalent(new Dictionary() { + }); + + var expSuccess = new OpaResult() + { + HttpStatusCode = "200", + Result = Result.CreateMapOfAny( + new Dictionary() { + {"p", new Dictionary() { { "1", 2 }, { "3", 4 } } } + } + ) + }; + var expError = new OpaError() + { + Code = "internal_error", + DecisionId = null, + HttpStatusCode = "500", + Message = "error(s) occurred while evaluating query" // Note: different error message for OPA mode. + }; + + // Assert that the failures dictionary has all expected elements, and the + // successes dictionary is empty. + Assert.Equivalent(new OpaBatchResults() { { "BBB", expSuccess } }, successes); + Assert.Equivalent(new Dictionary() { { "AAA", expError }, { "CCC", expError }, - }, failures); - - } - - [Fact] - public async Task RBACBatchAllFailuresFallbackTest() - { - var client = GetOpaClient(); - - var badInput = new Dictionary() { + }, failures); + + } + + [Fact] + public async Task RBACBatchAllFailuresFallbackTest() + { + var client = GetOpaClient(); + + var badInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 2, 1} }, - }; - - var (successes, failures) = await client.evaluateBatch("testmod/condfail", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch("testmod/condfail", new Dictionary>() { {"AAA", badInput }, {"BBB", badInput }, {"CCC", badInput }, - }); - - var expError = new OpaError() - { - Code = "internal_error", - DecisionId = null, - Message = "error(s) occurred while evaluating query" // Note: different error message for OPA mode. - }; - - // Assert that the failures dictionary has all expected elements, and the - // successes dictionary is empty. - Assert.Empty(successes); - Assert.Equivalent(new Dictionary() { + }); + + var expError = new OpaError() + { + Code = "internal_error", + DecisionId = null, + Message = "error(s) occurred while evaluating query" // Note: different error message for OPA mode. + }; + + // Assert that the failures dictionary has all expected elements, and the + // successes dictionary is empty. + Assert.Empty(successes); + Assert.Equivalent(new Dictionary() { { "AAA", expError }, { "BBB", expError }, { "CCC", expError }, - }, failures); - - } - - // The generic version of the batch queries. - [Fact] - public async Task RBACBatchGenericAllSuccessTest() - { - var client = GetEOpaClient(); - - var goodInput = new Dictionary() { + }, failures); + + } + + // The generic version of the batch queries. + [Fact] + public async Task RBACBatchGenericAllSuccessTest() + { + var client = GetEOpaClient(); + + var goodInput = new Dictionary() { { "user", "alice" }, { "action", "read" }, { "object", "id123" }, { "type", "dog" } - }; - - var (successes, failures) = await client.evaluateBatch("app/rbac/allow", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch("app/rbac/allow", new Dictionary>() { {"AAA", goodInput }, {"BBB", goodInput }, {"CCC", goodInput }, - }); - - var expSuccess = true; - - // Assert that the successes dictionary has all expected elements, and the - // failures dictionary is empty. - Assert.Equivalent(new Dictionary() { + }); + + var expSuccess = true; + + // Assert that the successes dictionary has all expected elements, and the + // failures dictionary is empty. + Assert.Equivalent(new Dictionary() { { "AAA", expSuccess }, { "BBB", expSuccess }, { "CCC", expSuccess }, - }, successes); - Assert.Empty(failures); - } - - [Fact] - public async Task RBACBatchGenericMixedTest() - { - var client = GetEOpaClient(); - - var goodInput = new Dictionary() { + }, successes); + Assert.Empty(failures); + } + + [Fact] + public async Task RBACBatchGenericMixedTest() + { + var client = GetEOpaClient(); + + var goodInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 1, 1} }, - }; - - var badInput = new Dictionary() { + }; + + var badInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 2, 1} }, - }; - - var (successes, failures) = await client.evaluateBatch>("testmod/condfail", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch>("testmod/condfail", new Dictionary>() { {"AAA", badInput }, {"BBB", goodInput }, {"CCC", badInput }, - }); - - var expSuccess = - new Dictionary() { - {"p", new Dictionary() { { "1", 2 }, { "3", 4 } } } - }; - var expError = new OpaError() - { - Code = "internal_error", - DecisionId = null, - HttpStatusCode = "500", - Message = "object insert conflict" - }; - - // Assert that the failures dictionary has all expected elements, and the - // successes dictionary is empty. - Assert.Equivalent(new OpaBatchResultGeneric>() { { "BBB", expSuccess } }, successes); - Assert.Equivalent(new Dictionary() { + }); + + var expSuccess = + new Dictionary() { + {"p", new Dictionary() { { "1", 2 }, { "3", 4 } } } + }; + var expError = new OpaError() + { + Code = "internal_error", + DecisionId = null, + HttpStatusCode = "500", + Message = "object insert conflict" + }; + + // Assert that the failures dictionary has all expected elements, and the + // successes dictionary is empty. + Assert.Equivalent(new OpaBatchResultGeneric>() { { "BBB", expSuccess } }, successes); + Assert.Equivalent(new Dictionary() { { "AAA", expError }, { "CCC", expError }, - }, failures); - - } - - [Fact] - public async Task RBACBatchGenericAllFailuresTest() - { - var client = GetEOpaClient(); - - var badInput = new Dictionary() { + }, failures); + + } + + [Fact] + public async Task RBACBatchGenericAllFailuresTest() + { + var client = GetEOpaClient(); + + var badInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 2, 1} }, - }; - - var (successes, failures) = await client.evaluateBatch>("testmod/condfail", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch>("testmod/condfail", new Dictionary>() { {"AAA", badInput }, {"BBB", badInput }, {"CCC", badInput }, - }); - - var expError = new OpaError() - { - Code = "internal_error", - DecisionId = null, - Message = "object insert conflict" - }; - - // Assert that the failures dictionary has all expected elements, and the - // successes dictionary is empty. - Assert.Empty(successes); - Assert.Equivalent(new Dictionary() { + }); + + var expError = new OpaError() + { + Code = "internal_error", + DecisionId = null, + Message = "object insert conflict" + }; + + // Assert that the failures dictionary has all expected elements, and the + // successes dictionary is empty. + Assert.Empty(successes); + Assert.Equivalent(new Dictionary() { { "AAA", expError }, { "BBB", expError }, { "CCC", expError }, - }, failures); - - } - - [Fact] - public async Task RBACBatchGenericAllSuccessFallbackTest() - { - var client = GetOpaClient(); - - var goodInput = new Dictionary() { + }, failures); + + } + + [Fact] + public async Task RBACBatchGenericAllSuccessFallbackTest() + { + var client = GetOpaClient(); + + var goodInput = new Dictionary() { { "user", "alice" }, { "action", "read" }, { "object", "id123" }, { "type", "dog" } - }; - - var (successes, failures) = await client.evaluateBatch("app/rbac/allow", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch("app/rbac/allow", new Dictionary>() { {"AAA", goodInput }, {"BBB", goodInput }, {"CCC", goodInput }, - }); - - var expSuccess = true; - - // Assert that the successes dictionary has all expected elements, and the - // failures dictionary is empty. - Assert.Equivalent(new Dictionary() { + }); + + var expSuccess = true; + + // Assert that the successes dictionary has all expected elements, and the + // failures dictionary is empty. + Assert.Equivalent(new Dictionary() { { "AAA", expSuccess }, { "BBB", expSuccess }, { "CCC", expSuccess }, - }, successes); - Assert.Empty(failures); - } - - [Fact] - public async Task RBACBatchGenericMixedFallbackTest() - { - var client = GetOpaClient(); - - var goodInput = new Dictionary() { + }, successes); + Assert.Empty(failures); + } + + [Fact] + public async Task RBACBatchGenericMixedFallbackTest() + { + var client = GetOpaClient(); + + var goodInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 1, 1} }, - }; - - var badInput = new Dictionary() { + }; + + var badInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 2, 1} }, - }; - - var (successes, failures) = await client.evaluateBatch>("testmod/condfail", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch>("testmod/condfail", new Dictionary>() { {"AAA", badInput }, {"BBB", goodInput }, {"CCC", badInput }, - }); - - var expSuccess = - new Dictionary() { - {"p", new Dictionary() { { "1", 2 }, { "3", 4 } } } - }; - var expError = new OpaError() - { - Code = "internal_error", - DecisionId = null, - HttpStatusCode = "500", - Message = "error(s) occurred while evaluating query" // Note: different error message for OPA mode. - }; - - // Assert that the failures dictionary has all expected elements, and the - // successes dictionary is empty. - Assert.Equivalent(new OpaBatchResultGeneric>() { { "BBB", expSuccess } }, successes); - Assert.Equivalent(new Dictionary() { + }); + + var expSuccess = + new Dictionary() { + {"p", new Dictionary() { { "1", 2 }, { "3", 4 } } } + }; + var expError = new OpaError() + { + Code = "internal_error", + DecisionId = null, + HttpStatusCode = "500", + Message = "error(s) occurred while evaluating query" // Note: different error message for OPA mode. + }; + + // Assert that the failures dictionary has all expected elements, and the + // successes dictionary is empty. + Assert.Equivalent(new OpaBatchResultGeneric>() { { "BBB", expSuccess } }, successes); + Assert.Equivalent(new Dictionary() { { "AAA", expError }, { "CCC", expError }, - }, failures); - - } - - [Fact] - public async Task RBACBatchGenericAllFailuresFallbackTest() - { - var client = GetOpaClient(); - - var badInput = new Dictionary() { + }, failures); + + } + + [Fact] + public async Task RBACBatchGenericAllFailuresFallbackTest() + { + var client = GetOpaClient(); + + var badInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 2, 1} }, - }; - - var (successes, failures) = await client.evaluateBatch>("testmod/condfail", new Dictionary>() { + }; + + var (successes, failures) = await client.evaluateBatch>("testmod/condfail", new Dictionary>() { {"AAA", badInput }, {"BBB", badInput }, {"CCC", badInput }, - }); - - var expError = new OpaError() - { - Code = "internal_error", - DecisionId = null, - Message = "error(s) occurred while evaluating query" // Note: different error message for OPA mode. - }; - - // Assert that the failures dictionary has all expected elements, and the - // successes dictionary is empty. - Assert.Empty(successes); - Assert.Equivalent(new Dictionary() { + }); + + var expError = new OpaError() + { + Code = "internal_error", + DecisionId = null, + Message = "error(s) occurred while evaluating query" // Note: different error message for OPA mode. + }; + + // Assert that the failures dictionary has all expected elements, and the + // successes dictionary is empty. + Assert.Empty(successes); + Assert.Equivalent(new Dictionary() { { "AAA", expError }, { "BBB", expError }, { "CCC", expError }, - }, failures); - - } - - [Fact] - public async Task LogsExistTest() - { - var logger = new ListLogger(); - var client = GetOpaClientWithLogger(logger); - - var badInput = new Dictionary() { + }, failures); + + } + + [Fact] + public async Task LogsExistTest() + { + var logger = new ListLogger(); + var client = GetOpaClientWithLogger(logger); + + var badInput = new Dictionary() { { "x", new List {1, 1, 3} }, { "y", new List {1, 2, 1} }, - }; - - try - { - var result = await client.evaluate("testmod/condfail", badInput); + }; + + try + { + var result = await client.evaluate("testmod/condfail", badInput); + } + catch (OpaException e) + { + // Do nothing. + _testOutput.WriteLine(e.Message); + } + + Assert.Single(logger.Logs); + Assert.Contains("executing policy 'testmod/condfail' failed with exception: ", logger.Logs[0]); } - catch (OpaException e) - { - // Do nothing. - _testOutput.WriteLine(e.Message); - } - - Assert.Single(logger.Logs); - Assert.Contains("executing policy 'testmod/condfail' failed with exception: ", logger.Logs[0]); - } } \ No newline at end of file diff --git a/test/SmokeTest.Tests/OPAContainerFixture.cs b/test/SmokeTest.Tests/OPAContainerFixture.cs index dc0238e..3b08221 100644 --- a/test/SmokeTest.Tests/OPAContainerFixture.cs +++ b/test/SmokeTest.Tests/OPAContainerFixture.cs @@ -1,47 +1,47 @@ namespace SmokeTest.Tests; public class OPAContainerFixture : IAsyncLifetime { - // Note: We disable this warning because we control when/how the constructor - // will be invoked for this class. + // Note: We disable this warning because we control when/how the constructor + // will be invoked for this class. #pragma warning disable CS8618 - private IContainer _container; + private IContainer _container; #pragma warning restore CS8618 - public async Task InitializeAsync() - { - string[] startupFiles = { + public async Task InitializeAsync() + { + string[] startupFiles = { "testdata/policy.rego", "testdata/weird_name.rego", "testdata/simple/system.rego", "testdata/condfail.rego", "testdata/data.json" }; - string[] opaCmd = { "run", "--server" }; - var startupCommand = new List().Concat(opaCmd).Concat(startupFiles).ToArray(); + string[] opaCmd = { "run", "--server" }; + var startupCommand = new List().Concat(opaCmd).Concat(startupFiles).ToArray(); - // Create a new instance of a container. - var container = new ContainerBuilder() - .WithImage("openpolicyagent/opa:latest") - // Bind port 8181 of the container to a random port on the host. - .WithPortBinding(8181, true) - .WithCommand(startupCommand) - // Map our policy and data files into the container instance. - .WithResourceMapping(new DirectoryInfo("testdata"), "/testdata/") - // Wait until the HTTP endpoint of the container is available. - .WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(r => r.ForPort(8181).ForPath("/health"))) - // Build the container configuration. - .Build(); + // Create a new instance of a container. + var container = new ContainerBuilder() + .WithImage("openpolicyagent/opa:latest") + // Bind port 8181 of the container to a random port on the host. + .WithPortBinding(8181, true) + .WithCommand(startupCommand) + // Map our policy and data files into the container instance. + .WithResourceMapping(new DirectoryInfo("testdata"), "/testdata/") + // Wait until the HTTP endpoint of the container is available. + .WithWaitStrategy(Wait.ForUnixContainer().UntilHttpRequestIsSucceeded(r => r.ForPort(8181).ForPath("/health"))) + // Build the container configuration. + .Build(); - // Start the container. - await container.StartAsync() - .ConfigureAwait(false); - _container = container; - } - public async Task DisposeAsync() - { - await _container.DisposeAsync(); - } + // Start the container. + await container.StartAsync() + .ConfigureAwait(false); + _container = container; + } + public async Task DisposeAsync() + { + await _container.DisposeAsync(); + } - // Expose the container for tests - public IContainer GetContainer() => _container; + // Expose the container for tests + public IContainer GetContainer() => _container; } diff --git a/test/SmokeTest.Tests/OpenApiTest.cs b/test/SmokeTest.Tests/OpenApiTest.cs index 9a602df..1a04ca8 100644 --- a/test/SmokeTest.Tests/OpenApiTest.cs +++ b/test/SmokeTest.Tests/OpenApiTest.cs @@ -7,136 +7,136 @@ namespace SmokeTest.Tests; public class OpenApiTest : IClassFixture, IClassFixture { - public IContainer _containerOpa; - public IContainer _containerEopa; - - public OpenApiTest(OPAContainerFixture opaFixture, EOPAContainerFixture eopaFixture) - { - _containerOpa = opaFixture.GetContainer(); - _containerEopa = eopaFixture.GetContainer(); - } - - private OpaApiClient GetOpaApiClient() - { - // Construct the request URI by specifying the scheme, hostname, assigned random host port, and the endpoint "uuid". - var requestUri = new UriBuilder(Uri.UriSchemeHttp, _containerOpa.Hostname, _containerOpa.GetMappedPublicPort(8181)).Uri; - - // Send an HTTP GET request to the specified URI and retrieve the response as a string. - return new OpaApiClient(serverIndex: 0, serverUrl: requestUri.ToString()); - } - - private OpaApiClient GetEOpaApiClient() - { - // Construct the request URI by specifying the scheme, hostname, assigned random host port, and the endpoint "uuid". - var requestUri = new UriBuilder(Uri.UriSchemeHttp, _containerEopa.Hostname, _containerEopa.GetMappedPublicPort(8181)).Uri; - - // Send an HTTP GET request to the specified URI and retrieve the response as a string. - return new OpaApiClient(serverIndex: 0, serverUrl: requestUri.ToString()); - } - - [Fact] - public async Task OpenApiClientRBACTestcontainersTest() - { - var client = GetOpaApiClient(); - - // Exercise the low-level OPA C# SDK. - var req = new ExecutePolicyWithInputRequest() + public IContainer _containerOpa; + public IContainer _containerEopa; + + public OpenApiTest(OPAContainerFixture opaFixture, EOPAContainerFixture eopaFixture) + { + _containerOpa = opaFixture.GetContainer(); + _containerEopa = eopaFixture.GetContainer(); + } + + private OpaApiClient GetOpaApiClient() + { + // Construct the request URI by specifying the scheme, hostname, assigned random host port, and the endpoint "uuid". + var requestUri = new UriBuilder(Uri.UriSchemeHttp, _containerOpa.Hostname, _containerOpa.GetMappedPublicPort(8181)).Uri; + + // Send an HTTP GET request to the specified URI and retrieve the response as a string. + return new OpaApiClient(serverIndex: 0, serverUrl: requestUri.ToString()); + } + + private OpaApiClient GetEOpaApiClient() { - Path = "app/rbac", - RequestBody = new ExecutePolicyWithInputRequestBody() - { - Input = Input.CreateMapOfAny( - new Dictionary() { + // Construct the request URI by specifying the scheme, hostname, assigned random host port, and the endpoint "uuid". + var requestUri = new UriBuilder(Uri.UriSchemeHttp, _containerEopa.Hostname, _containerEopa.GetMappedPublicPort(8181)).Uri; + + // Send an HTTP GET request to the specified URI and retrieve the response as a string. + return new OpaApiClient(serverIndex: 0, serverUrl: requestUri.ToString()); + } + + [Fact] + public async Task OpenApiClientRBACTestcontainersTest() + { + var client = GetOpaApiClient(); + + // Exercise the low-level OPA C# SDK. + var req = new ExecutePolicyWithInputRequest() + { + Path = "app/rbac", + RequestBody = new ExecutePolicyWithInputRequestBody() + { + Input = Input.CreateMapOfAny( + new Dictionary() { { "user", "alice" }, { "action", "read" }, { "object", "id123" }, { "type", "dog" }, - }), - }, - }; - - var res = await client.ExecutePolicyWithInputAsync(req); - var resultMap = res.SuccessfulPolicyResponse?.Result?.MapOfAny; - - // Ensure we got back the expected fields from the eval. - Assert.Equal(true, resultMap?.GetValueOrDefault("allow", false)); - Assert.Equal(true, resultMap?.GetValueOrDefault("user_is_admin", false)); - Assert.Equal(new List(), resultMap?.GetValueOrDefault("user_is_granted")); - } - - [Fact] - public async Task OpenApiClientEncodedPathTest() - { - var client = GetOpaApiClient(); - - // Exercise the low-level OPA C# SDK. - var req = new ExecutePolicyRequest() - { - Path = "this/is%2fallowed/pkg", - }; + }), + }, + }; - var res = await client.ExecutePolicyAsync(req); - var resultMap = res.SuccessfulPolicyResponse?.Result?.MapOfAny; + var res = await client.ExecutePolicyWithInputAsync(req); + var resultMap = res.SuccessfulPolicyResponse?.Result?.MapOfAny; - Assert.Equal(true, resultMap?.GetValueOrDefault("allow", false)); - } + // Ensure we got back the expected fields from the eval. + Assert.Equal(true, resultMap?.GetValueOrDefault("allow", false)); + Assert.Equal(true, resultMap?.GetValueOrDefault("user_is_admin", false)); + Assert.Equal(new List(), resultMap?.GetValueOrDefault("user_is_granted")); + } - [Fact] - public async Task OpenApiClientEvaluateDefaultTest() - { - var client = GetOpaApiClient(); + [Fact] + public async Task OpenApiClientEncodedPathTest() + { + var client = GetOpaApiClient(); - // Note(philip): Due to how the API is generated, we have to fire off - // requests directly-- there's no building of requests in advance for later - // launching. - var res = await client.ExecuteDefaultPolicyWithInputAsync(Input.CreateMapOfAny( - new Dictionary() { - { "hello", "world" }, - })); - var resultMap = res.Result?.MapOfAny; + // Exercise the low-level OPA C# SDK. + var req = new ExecutePolicyRequest() + { + Path = "this/is%2fallowed/pkg", + }; - // Ensure we got back the expected fields from the eval. - Assert.Equal("this is the default path", resultMap?.GetValueOrDefault("msg", "")); - Assert.Equal(new Dictionary() { { "hello", "world" } }, resultMap?.GetValueOrDefault("echo", "")); - } + var res = await client.ExecutePolicyAsync(req); + var resultMap = res.SuccessfulPolicyResponse?.Result?.MapOfAny; - [Fact] - public async Task OpenApiClientBatchPolicyNoInputTest() - { - // Currently, this API only exists in Enterprise OPA. - var client = GetEOpaApiClient(); + Assert.Equal(true, resultMap?.GetValueOrDefault("allow", false)); + } - var req = new ExecuteBatchPolicyWithInputRequest() + [Fact] + public async Task OpenApiClientEvaluateDefaultTest() { - Path = "app/rbac", - RequestBody = new ExecuteBatchPolicyWithInputRequestBody() - { - Inputs = new Dictionary() { }, - } - }; + var client = GetOpaApiClient(); - var res = await client.ExecuteBatchPolicyWithInputAsync(req); - - // Assert we get the expected "success" response - Assert.Equal(200, res.StatusCode); + // Note(philip): Due to how the API is generated, we have to fire off + // requests directly-- there's no building of requests in advance for later + // launching. + var res = await client.ExecuteDefaultPolicyWithInputAsync(Input.CreateMapOfAny( + new Dictionary() { + { "hello", "world" }, + })); + var resultMap = res.Result?.MapOfAny; - // Assert no responses. - Assert.NotNull(res.BatchSuccessfulPolicyEvaluation); - Assert.Null(res.BatchSuccessfulPolicyEvaluation?.Responses); - } + // Ensure we got back the expected fields from the eval. + Assert.Equal("this is the default path", resultMap?.GetValueOrDefault("msg", "")); + Assert.Equal(new Dictionary() { { "hello", "world" } }, resultMap?.GetValueOrDefault("echo", "")); + } - [Fact] - public async Task OpenApiClientBatchPolicyAllSuccessTest() - { - // Currently, this API only exists in Enterprise OPA. - var client = GetEOpaApiClient(); + [Fact] + public async Task OpenApiClientBatchPolicyNoInputTest() + { + // Currently, this API only exists in Enterprise OPA. + var client = GetEOpaApiClient(); + + var req = new ExecuteBatchPolicyWithInputRequest() + { + Path = "app/rbac", + RequestBody = new ExecuteBatchPolicyWithInputRequestBody() + { + Inputs = new Dictionary() { }, + } + }; + + var res = await client.ExecuteBatchPolicyWithInputAsync(req); + + // Assert we get the expected "success" response + Assert.Equal(200, res.StatusCode); + + // Assert no responses. + Assert.NotNull(res.BatchSuccessfulPolicyEvaluation); + Assert.Null(res.BatchSuccessfulPolicyEvaluation?.Responses); + } - var req = new ExecuteBatchPolicyWithInputRequest() + [Fact] + public async Task OpenApiClientBatchPolicyAllSuccessTest() { - Path = "app/rbac", - RequestBody = new ExecuteBatchPolicyWithInputRequestBody() - { - Inputs = new Dictionary() { + // Currently, this API only exists in Enterprise OPA. + var client = GetEOpaApiClient(); + + var req = new ExecuteBatchPolicyWithInputRequest() + { + Path = "app/rbac", + RequestBody = new ExecuteBatchPolicyWithInputRequestBody() + { + Inputs = new Dictionary() { {"AAA", Input.CreateMapOfAny( new Dictionary() { { "user", "alice" }, @@ -154,39 +154,39 @@ public async Task OpenApiClientBatchPolicyAllSuccessTest() }) }, } - } - }; + } + }; - var res = await client.ExecuteBatchPolicyWithInputAsync(req); + var res = await client.ExecuteBatchPolicyWithInputAsync(req); - // Assert we get the expected "success" response - Assert.Equal(200, res.StatusCode); + // Assert we get the expected "success" response + Assert.Equal(200, res.StatusCode); - var responsesMap = res.BatchSuccessfulPolicyEvaluation?.Responses; - { - var resp = responsesMap?.GetValueOrDefault("AAA"); - Assert.NotNull(resp); - Assert.Equal(true, resp?.Result?.MapOfAny?.GetValueOrDefault("allow")); - } + var responsesMap = res.BatchSuccessfulPolicyEvaluation?.Responses; + { + var resp = responsesMap?.GetValueOrDefault("AAA"); + Assert.NotNull(resp); + Assert.Equal(true, resp?.Result?.MapOfAny?.GetValueOrDefault("allow")); + } - { - var resp = responsesMap?.GetValueOrDefault("BBB"); - Assert.Equal(false, resp?.Result?.MapOfAny?.GetValueOrDefault("allow")); + { + var resp = responsesMap?.GetValueOrDefault("BBB"); + Assert.Equal(false, resp?.Result?.MapOfAny?.GetValueOrDefault("allow")); + } } - } - - [Fact] - public async Task OpenApiClientBatchPolicyMixedTest() - { - // Currently, this API only exists in Enterprise OPA. - var client = GetEOpaApiClient(); - var req = new ExecuteBatchPolicyWithInputRequest() + [Fact] + public async Task OpenApiClientBatchPolicyMixedTest() { - Path = "testmod/condfail", - RequestBody = new ExecuteBatchPolicyWithInputRequestBody() - { - Inputs = new Dictionary() { + // Currently, this API only exists in Enterprise OPA. + var client = GetEOpaApiClient(); + + var req = new ExecuteBatchPolicyWithInputRequest() + { + Path = "testmod/condfail", + RequestBody = new ExecuteBatchPolicyWithInputRequestBody() + { + Inputs = new Dictionary() { {"AAA", Input.CreateMapOfAny( new Dictionary() { { "x", new List {1, 1, 3} }, @@ -206,50 +206,50 @@ public async Task OpenApiClientBatchPolicyMixedTest() }) } }, - } - }; - - var res = await client.ExecuteBatchPolicyWithInputAsync(req); - - // Assert we get the expected "success" response - Assert.Equal(207, res.StatusCode); - - var responsesMap = res.BatchMixedResults?.Responses; - { - var resp = responsesMap?.GetValueOrDefault("AAA"); - Assert.NotNull(resp); - Assert.Equivalent(new Dictionary() { { "1", 2 }, { "3", 4 } }, resp?.SuccessfulPolicyResponseWithStatusCode?.Result?.MapOfAny?.GetValueOrDefault("p")); - Assert.Equal("200", resp?.SuccessfulPolicyResponseWithStatusCode?.HttpStatusCode); - } - - { - var resp = responsesMap?.GetValueOrDefault("BBB"); - Assert.NotNull(resp?.ServerErrorWithStatusCode); - Assert.Equal("internal_error", resp?.ServerErrorWithStatusCode?.Code); - Assert.Equal("500", resp?.ServerErrorWithStatusCode?.HttpStatusCode); - Assert.Equal("object insert conflict", resp?.ServerErrorWithStatusCode?.Message); + } + }; + + var res = await client.ExecuteBatchPolicyWithInputAsync(req); + + // Assert we get the expected "success" response + Assert.Equal(207, res.StatusCode); + + var responsesMap = res.BatchMixedResults?.Responses; + { + var resp = responsesMap?.GetValueOrDefault("AAA"); + Assert.NotNull(resp); + Assert.Equivalent(new Dictionary() { { "1", 2 }, { "3", 4 } }, resp?.SuccessfulPolicyResponseWithStatusCode?.Result?.MapOfAny?.GetValueOrDefault("p")); + Assert.Equal("200", resp?.SuccessfulPolicyResponseWithStatusCode?.HttpStatusCode); + } + + { + var resp = responsesMap?.GetValueOrDefault("BBB"); + Assert.NotNull(resp?.ServerErrorWithStatusCode); + Assert.Equal("internal_error", resp?.ServerErrorWithStatusCode?.Code); + Assert.Equal("500", resp?.ServerErrorWithStatusCode?.HttpStatusCode); + Assert.Equal("object insert conflict", resp?.ServerErrorWithStatusCode?.Message); + } + + { + var resp = responsesMap?.GetValueOrDefault("CCC"); + Assert.NotNull(resp); + Assert.Equivalent(new Dictionary() { { "1", 2 }, { "3", 4 } }, resp?.SuccessfulPolicyResponseWithStatusCode?.Result?.MapOfAny?.GetValueOrDefault("p")); + Assert.Equal("200", resp?.SuccessfulPolicyResponseWithStatusCode?.HttpStatusCode); + } } + [Fact] + public async Task OpenApiClientBatchPolicyAllFailureTest() { - var resp = responsesMap?.GetValueOrDefault("CCC"); - Assert.NotNull(resp); - Assert.Equivalent(new Dictionary() { { "1", 2 }, { "3", 4 } }, resp?.SuccessfulPolicyResponseWithStatusCode?.Result?.MapOfAny?.GetValueOrDefault("p")); - Assert.Equal("200", resp?.SuccessfulPolicyResponseWithStatusCode?.HttpStatusCode); - } - } - - [Fact] - public async Task OpenApiClientBatchPolicyAllFailureTest() - { - // Currently, this API only exists in Enterprise OPA. - var client = GetEOpaApiClient(); - - var req = new ExecuteBatchPolicyWithInputRequest() - { - Path = "testmod/condfail", - RequestBody = new ExecuteBatchPolicyWithInputRequestBody() - { - Inputs = new Dictionary() { + // Currently, this API only exists in Enterprise OPA. + var client = GetEOpaApiClient(); + + var req = new ExecuteBatchPolicyWithInputRequest() + { + Path = "testmod/condfail", + RequestBody = new ExecuteBatchPolicyWithInputRequestBody() + { + Inputs = new Dictionary() { {"AAA", Input.CreateMapOfAny( new Dictionary() { { "x", new List {1, 1, 3} }, @@ -269,71 +269,71 @@ public async Task OpenApiClientBatchPolicyAllFailureTest() }) } }, - } - }; - - // We populate this variable later in the catch block, otherwise this would - // not be a terribly good idea. - Dictionary responsesMap = null!; - try - { - var res = await client.ExecuteBatchPolicyWithInputAsync(req); - } - catch (Exception ex) - { - if (ex is ClientError ce) - { - Assert.Fail(string.Format("ClientError: {0}, Message: {1}", ce.Code, ce.Message)); - } - else if (ex is BatchServerError bse) - { - Assert.NotNull(bse.Responses); - responsesMap = bse.Responses; - } - else if (ex is SDKException sdke) - { - Assert.Fail(string.Format("SDKException: {0}, Message: {1}", sdke.Body, sdke.Message)); - } - else - { - Assert.Fail(string.Format("Unknown Error: {0}, Message: {1}", ex, ex.Message)); - } - } - - { - var resp = responsesMap?.GetValueOrDefault("AAA"); - Assert.NotNull(resp); - Assert.Equal("internal_error", resp?.Code); - if (resp!.Message.Contains("eval_conflict_error")) - { - Assert.Fail("Test failure due to OPA Fallback mode. Please check the EOPA license environment variables."); - } - - Assert.Contains("object insert conflict", resp?.Message); - } - - { - var resp = responsesMap?.GetValueOrDefault("BBB"); - Assert.NotNull(resp); - Assert.Equal("internal_error", resp?.Code); - if (resp!.Message.Contains("eval_conflict_error")) - { - Assert.Fail("Test failure due to OPA Fallback mode. Please check the EOPA license environment variables."); - } - - Assert.Equal("object insert conflict", resp?.Message); - } - - { - var resp = responsesMap?.GetValueOrDefault("CCC"); - Assert.NotNull(resp); - Assert.Equal("internal_error", resp?.Code); - if (resp!.Message.Contains("eval_conflict_error")) - { - Assert.Fail("Test failure due to OPA Fallback mode. Please check the EOPA license environment variables."); - } - - Assert.Equal("object insert conflict", resp?.Message); + } + }; + + // We populate this variable later in the catch block, otherwise this would + // not be a terribly good idea. + Dictionary responsesMap = null!; + try + { + var res = await client.ExecuteBatchPolicyWithInputAsync(req); + } + catch (Exception ex) + { + if (ex is ClientError ce) + { + Assert.Fail(string.Format("ClientError: {0}, Message: {1}", ce.Code, ce.Message)); + } + else if (ex is BatchServerError bse) + { + Assert.NotNull(bse.Responses); + responsesMap = bse.Responses; + } + else if (ex is SDKException sdke) + { + Assert.Fail(string.Format("SDKException: {0}, Message: {1}", sdke.Body, sdke.Message)); + } + else + { + Assert.Fail(string.Format("Unknown Error: {0}, Message: {1}", ex, ex.Message)); + } + } + + { + var resp = responsesMap?.GetValueOrDefault("AAA"); + Assert.NotNull(resp); + Assert.Equal("internal_error", resp?.Code); + if (resp!.Message.Contains("eval_conflict_error")) + { + Assert.Fail("Test failure due to OPA Fallback mode. Please check the EOPA license environment variables."); + } + + Assert.Contains("object insert conflict", resp?.Message); + } + + { + var resp = responsesMap?.GetValueOrDefault("BBB"); + Assert.NotNull(resp); + Assert.Equal("internal_error", resp?.Code); + if (resp!.Message.Contains("eval_conflict_error")) + { + Assert.Fail("Test failure due to OPA Fallback mode. Please check the EOPA license environment variables."); + } + + Assert.Equal("object insert conflict", resp?.Message); + } + + { + var resp = responsesMap?.GetValueOrDefault("CCC"); + Assert.NotNull(resp); + Assert.Equal("internal_error", resp?.Code); + if (resp!.Message.Contains("eval_conflict_error")) + { + Assert.Fail("Test failure due to OPA Fallback mode. Please check the EOPA license environment variables."); + } + + Assert.Equal("object insert conflict", resp?.Message); + } } - } }