audit, advisories and doctors/setup work
This commit is contained in:
@@ -99,7 +99,7 @@ public sealed class PolicyEngineWebServiceFixture : WebServiceFixture<StellaOps.
|
||||
_ => { });
|
||||
}
|
||||
|
||||
private static void ConfigureWebHost(IWebHostBuilder builder)
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
builder.ConfigureAppConfiguration((_, config) =>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using StellaOps.Policy.Gateway.Contracts;
|
||||
using StellaOps.TestKit;
|
||||
using Xunit;
|
||||
using GatewayProgram = StellaOps.Policy.Gateway.Program;
|
||||
|
||||
namespace StellaOps.Policy.Gateway.Tests;
|
||||
|
||||
public sealed class ToolLatticeEndpointsTests : IClassFixture<WebApplicationFactory<GatewayProgram>>
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public ToolLatticeEndpointsTests(WebApplicationFactory<GatewayProgram> factory)
|
||||
{
|
||||
_client = factory.CreateClient();
|
||||
_client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-a");
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task Evaluate_ReturnsDecision()
|
||||
{
|
||||
var request = new ToolAccessRequest
|
||||
{
|
||||
Tool = "vex.query",
|
||||
Action = "read",
|
||||
Scopes = new[] { "vex:read" }
|
||||
};
|
||||
|
||||
var response = await _client.PostAsJsonAsync("/api/v1/policy/assistant/tools/evaluate", request, CancellationToken.None);
|
||||
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var payload = await response.Content.ReadFromJsonAsync<ToolAccessResponse>(cancellationToken: CancellationToken.None);
|
||||
Assert.NotNull(payload);
|
||||
Assert.True(payload!.Allowed);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task Evaluate_ReturnsBadRequest_WhenToolMissing()
|
||||
{
|
||||
var request = new ToolAccessRequest
|
||||
{
|
||||
Action = "read",
|
||||
Scopes = new[] { "vex:read" }
|
||||
};
|
||||
|
||||
var response = await _client.PostAsJsonAsync("/api/v1/policy/assistant/tools/evaluate", request, CancellationToken.None);
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
var payload = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
|
||||
Assert.True(payload.TryGetProperty("title", out _));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Policy.ToolLattice;
|
||||
using StellaOps.TestKit;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Policy.Tests.ToolLattice;
|
||||
|
||||
public sealed class ToolAccessEvaluatorTests
|
||||
{
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void DefaultRules_AllowReadTool_WhenScopeMatches()
|
||||
{
|
||||
var options = new ToolLatticeOptions
|
||||
{
|
||||
UseDefaultRules = true
|
||||
};
|
||||
var evaluator = new ToolAccessEvaluator(Options.Create(options));
|
||||
|
||||
var decision = evaluator.Evaluate(new ToolAccessContext
|
||||
{
|
||||
TenantId = "tenant-a",
|
||||
Tool = "vex.query",
|
||||
Action = "read",
|
||||
Scopes = new[] { "vex:read" }
|
||||
});
|
||||
|
||||
Assert.True(decision.Allowed);
|
||||
Assert.Equal("rule_allow", decision.Reason);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void DefaultRules_DenyWhenScopeMissing()
|
||||
{
|
||||
var options = new ToolLatticeOptions
|
||||
{
|
||||
UseDefaultRules = true
|
||||
};
|
||||
var evaluator = new ToolAccessEvaluator(Options.Create(options));
|
||||
|
||||
var decision = evaluator.Evaluate(new ToolAccessContext
|
||||
{
|
||||
TenantId = "tenant-a",
|
||||
Tool = "sbom.read",
|
||||
Action = "read",
|
||||
Scopes = new[] { "vex:read" }
|
||||
});
|
||||
|
||||
Assert.False(decision.Allowed);
|
||||
Assert.Equal("default_deny", decision.Reason);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void DefaultRules_DenyWhenActionMismatch()
|
||||
{
|
||||
var options = new ToolLatticeOptions
|
||||
{
|
||||
UseDefaultRules = true
|
||||
};
|
||||
var evaluator = new ToolAccessEvaluator(Options.Create(options));
|
||||
|
||||
var decision = evaluator.Evaluate(new ToolAccessContext
|
||||
{
|
||||
TenantId = "tenant-a",
|
||||
Tool = "scanner.findings.topk",
|
||||
Action = "action",
|
||||
Scopes = new[] { "scanner:read" }
|
||||
});
|
||||
|
||||
Assert.False(decision.Allowed);
|
||||
Assert.Equal("default_deny", decision.Reason);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CustomRule_RespectsTenantConstraint()
|
||||
{
|
||||
var options = new ToolLatticeOptions
|
||||
{
|
||||
UseDefaultRules = false
|
||||
};
|
||||
|
||||
var rule = new ToolAccessRule
|
||||
{
|
||||
Tool = "vex.query",
|
||||
Action = "read",
|
||||
Effect = ToolAccessEffect.Allow
|
||||
};
|
||||
rule.Scopes.Add("vex:read");
|
||||
rule.Tenants.Add("tenant-a");
|
||||
options.Rules.Add(rule);
|
||||
|
||||
var evaluator = new ToolAccessEvaluator(Options.Create(options));
|
||||
|
||||
var decision = evaluator.Evaluate(new ToolAccessContext
|
||||
{
|
||||
TenantId = "tenant-b",
|
||||
Tool = "vex.query",
|
||||
Action = "read",
|
||||
Scopes = new[] { "vex:read" }
|
||||
});
|
||||
|
||||
Assert.False(decision.Allowed);
|
||||
Assert.Equal("default_deny", decision.Reason);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ScopeOrdering_DoesNotChangeDecision()
|
||||
{
|
||||
var options = new ToolLatticeOptions
|
||||
{
|
||||
UseDefaultRules = true
|
||||
};
|
||||
var evaluator = new ToolAccessEvaluator(Options.Create(options));
|
||||
|
||||
var decisionA = evaluator.Evaluate(new ToolAccessContext
|
||||
{
|
||||
TenantId = "tenant-a",
|
||||
Tool = "scanner.findings.topk",
|
||||
Action = "read",
|
||||
Scopes = new[] { "findings:read", "scanner:read" }
|
||||
});
|
||||
|
||||
var decisionB = evaluator.Evaluate(new ToolAccessContext
|
||||
{
|
||||
TenantId = "tenant-a",
|
||||
Tool = "scanner.findings.topk",
|
||||
Action = "read",
|
||||
Scopes = new[] { "scanner:read", "findings:read" }
|
||||
});
|
||||
|
||||
Assert.Equal(decisionA.Allowed, decisionB.Allowed);
|
||||
Assert.Equal(decisionA.Reason, decisionB.Reason);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user