audit, advisories and doctors/setup work

This commit is contained in:
master
2026-01-13 18:53:39 +02:00
parent 9ca7cb183e
commit d7be6ba34b
811 changed files with 54242 additions and 4056 deletions

View File

@@ -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) =>
{

View File

@@ -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 _));
}
}

View File

@@ -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);
}
}