up
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using StellaOps.Policy.Engine.AdvisoryAI;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Tests;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using StellaOps.Policy.Engine.Domain;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using StellaOps.Policy.Engine.Ledger;
|
||||
using StellaOps.Policy.Engine.Orchestration;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using StellaOps.Policy.Engine.Orchestration;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Policy.Engine.Overlay;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Policy.Engine.Overlay;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Policy.Engine.Streaming;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Policy;
|
||||
using StellaOps.Policy.Engine.Compilation;
|
||||
using StellaOps.PolicyDsl;
|
||||
using StellaOps.Policy.Engine.Options;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
using Xunit;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using StellaOps.Policy;
|
||||
using StellaOps.Policy.Engine.Compilation;
|
||||
using StellaOps.PolicyDsl;
|
||||
using Xunit;
|
||||
using Xunit.Sdk;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using StellaOps.Policy;
|
||||
using StellaOps.Policy.Engine.Compilation;
|
||||
using StellaOps.PolicyDsl;
|
||||
using StellaOps.Policy.Engine.Evaluation;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
using Xunit;
|
||||
@@ -51,26 +51,26 @@ policy "Baseline Production Policy" syntax "stella-dsl@1" {
|
||||
because "Respect strong vendor VEX claims."
|
||||
}
|
||||
|
||||
rule alert_warn_eol_runtime priority 1 {
|
||||
when severity.normalized <= "Medium"
|
||||
and sbom.has_tag("runtime:eol")
|
||||
then warn message "Runtime marked as EOL; upgrade recommended."
|
||||
because "Deprecated runtime should be upgraded."
|
||||
}
|
||||
|
||||
rule block_ruby_dev priority 4 {
|
||||
when sbom.any_component(ruby.group("development") and ruby.declared_only())
|
||||
then status := "blocked"
|
||||
because "Development-only Ruby gems without install evidence cannot ship."
|
||||
}
|
||||
|
||||
rule warn_ruby_git_sources {
|
||||
when sbom.any_component(ruby.source("git"))
|
||||
then warn message "Git-sourced Ruby gem present; review required."
|
||||
because "Git-sourced Ruby dependencies require explicit review."
|
||||
}
|
||||
}
|
||||
""";
|
||||
rule alert_warn_eol_runtime priority 1 {
|
||||
when severity.normalized <= "Medium"
|
||||
and sbom.has_tag("runtime:eol")
|
||||
then warn message "Runtime marked as EOL; upgrade recommended."
|
||||
because "Deprecated runtime should be upgraded."
|
||||
}
|
||||
|
||||
rule block_ruby_dev priority 4 {
|
||||
when sbom.any_component(ruby.group("development") and ruby.declared_only())
|
||||
then status := "blocked"
|
||||
because "Development-only Ruby gems without install evidence cannot ship."
|
||||
}
|
||||
|
||||
rule warn_ruby_git_sources {
|
||||
when sbom.any_component(ruby.source("git"))
|
||||
then warn message "Git-sourced Ruby gem present; review required."
|
||||
because "Git-sourced Ruby dependencies require explicit review."
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
private readonly PolicyCompiler compiler = new();
|
||||
private readonly PolicyEvaluationService evaluationService = new();
|
||||
@@ -125,11 +125,11 @@ policy "Baseline Production Policy" syntax "stella-dsl@1" {
|
||||
public void Evaluate_WarnRuleEmitsWarning()
|
||||
{
|
||||
var document = CompileBaseline();
|
||||
var tags = ImmutableHashSet.Create("runtime:eol");
|
||||
var context = CreateContext("Medium", "internal") with
|
||||
{
|
||||
Sbom = new PolicyEvaluationSbom(tags)
|
||||
};
|
||||
var tags = ImmutableHashSet.Create("runtime:eol");
|
||||
var context = CreateContext("Medium", "internal") with
|
||||
{
|
||||
Sbom = new PolicyEvaluationSbom(tags)
|
||||
};
|
||||
|
||||
var result = evaluationService.Evaluate(document, context);
|
||||
|
||||
@@ -273,74 +273,74 @@ policy "Baseline Production Policy" syntax "stella-dsl@1" {
|
||||
Assert.NotNull(result.AppliedException);
|
||||
Assert.Equal("exc-rule", result.AppliedException!.ExceptionId);
|
||||
Assert.Equal("Rule Critical Suppress", result.AppliedException!.Metadata["effectName"]);
|
||||
Assert.Equal("alice", result.AppliedException!.Metadata["requestedBy"]);
|
||||
Assert.Equal("alice", result.Annotations["exception.meta.requestedBy"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Evaluate_RubyDevComponentBlocked()
|
||||
{
|
||||
var document = CompileBaseline();
|
||||
var component = CreateRubyComponent(
|
||||
name: "dev-only",
|
||||
version: "1.0.0",
|
||||
groups: "development;test",
|
||||
declaredOnly: true,
|
||||
source: "https://rubygems.org/",
|
||||
capabilities: new[] { "exec" });
|
||||
|
||||
var context = CreateContext("Medium", "internal") with
|
||||
{
|
||||
Sbom = new PolicyEvaluationSbom(
|
||||
ImmutableHashSet<string>.Empty.WithComparer(StringComparer.OrdinalIgnoreCase),
|
||||
ImmutableArray.Create(component))
|
||||
};
|
||||
|
||||
var result = evaluationService.Evaluate(document, context);
|
||||
|
||||
Assert.True(result.Matched);
|
||||
Assert.Equal("block_ruby_dev", result.RuleName);
|
||||
Assert.Equal("blocked", result.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Evaluate_RubyGitComponentWarns()
|
||||
{
|
||||
var document = CompileBaseline();
|
||||
var component = CreateRubyComponent(
|
||||
name: "git-gem",
|
||||
version: "0.5.0",
|
||||
groups: "default",
|
||||
declaredOnly: false,
|
||||
source: "git:https://github.com/example/git-gem.git@0123456789abcdef0123456789abcdef01234567",
|
||||
capabilities: Array.Empty<string>(),
|
||||
schedulerCapabilities: new[] { "sidekiq" });
|
||||
|
||||
var context = CreateContext("Low", "internal") with
|
||||
{
|
||||
Sbom = new PolicyEvaluationSbom(
|
||||
ImmutableHashSet<string>.Empty.WithComparer(StringComparer.OrdinalIgnoreCase),
|
||||
ImmutableArray.Create(component))
|
||||
};
|
||||
|
||||
var result = evaluationService.Evaluate(document, context);
|
||||
|
||||
Assert.True(result.Matched);
|
||||
Assert.Equal("warn_ruby_git_sources", result.RuleName);
|
||||
Assert.Equal("warned", result.Status);
|
||||
Assert.Contains(result.Warnings, warning => warning.Contains("Git-sourced", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private PolicyIrDocument CompileBaseline()
|
||||
{
|
||||
var compilation = compiler.Compile(BaselinePolicy);
|
||||
if (!compilation.Success)
|
||||
{
|
||||
Console.WriteLine(Describe(compilation.Diagnostics));
|
||||
}
|
||||
Assert.True(compilation.Success, Describe(compilation.Diagnostics));
|
||||
return Assert.IsType<PolicyIrDocument>(compilation.Document);
|
||||
}
|
||||
Assert.Equal("alice", result.AppliedException!.Metadata["requestedBy"]);
|
||||
Assert.Equal("alice", result.Annotations["exception.meta.requestedBy"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Evaluate_RubyDevComponentBlocked()
|
||||
{
|
||||
var document = CompileBaseline();
|
||||
var component = CreateRubyComponent(
|
||||
name: "dev-only",
|
||||
version: "1.0.0",
|
||||
groups: "development;test",
|
||||
declaredOnly: true,
|
||||
source: "https://rubygems.org/",
|
||||
capabilities: new[] { "exec" });
|
||||
|
||||
var context = CreateContext("Medium", "internal") with
|
||||
{
|
||||
Sbom = new PolicyEvaluationSbom(
|
||||
ImmutableHashSet<string>.Empty.WithComparer(StringComparer.OrdinalIgnoreCase),
|
||||
ImmutableArray.Create(component))
|
||||
};
|
||||
|
||||
var result = evaluationService.Evaluate(document, context);
|
||||
|
||||
Assert.True(result.Matched);
|
||||
Assert.Equal("block_ruby_dev", result.RuleName);
|
||||
Assert.Equal("blocked", result.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Evaluate_RubyGitComponentWarns()
|
||||
{
|
||||
var document = CompileBaseline();
|
||||
var component = CreateRubyComponent(
|
||||
name: "git-gem",
|
||||
version: "0.5.0",
|
||||
groups: "default",
|
||||
declaredOnly: false,
|
||||
source: "git:https://github.com/example/git-gem.git@0123456789abcdef0123456789abcdef01234567",
|
||||
capabilities: Array.Empty<string>(),
|
||||
schedulerCapabilities: new[] { "sidekiq" });
|
||||
|
||||
var context = CreateContext("Low", "internal") with
|
||||
{
|
||||
Sbom = new PolicyEvaluationSbom(
|
||||
ImmutableHashSet<string>.Empty.WithComparer(StringComparer.OrdinalIgnoreCase),
|
||||
ImmutableArray.Create(component))
|
||||
};
|
||||
|
||||
var result = evaluationService.Evaluate(document, context);
|
||||
|
||||
Assert.True(result.Matched);
|
||||
Assert.Equal("warn_ruby_git_sources", result.RuleName);
|
||||
Assert.Equal("warned", result.Status);
|
||||
Assert.Contains(result.Warnings, warning => warning.Contains("Git-sourced", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private PolicyIrDocument CompileBaseline()
|
||||
{
|
||||
var compilation = compiler.Compile(BaselinePolicy);
|
||||
if (!compilation.Success)
|
||||
{
|
||||
Console.WriteLine(Describe(compilation.Diagnostics));
|
||||
}
|
||||
Assert.True(compilation.Success, Describe(compilation.Diagnostics));
|
||||
return Assert.IsType<PolicyIrDocument>(compilation.Document);
|
||||
}
|
||||
|
||||
private static PolicyEvaluationContext CreateContext(string severity, string exposure, PolicyEvaluationExceptions? exceptions = null)
|
||||
{
|
||||
@@ -352,67 +352,67 @@ policy "Baseline Production Policy" syntax "stella-dsl@1" {
|
||||
}.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase)),
|
||||
new PolicyEvaluationAdvisory("GHSA", ImmutableDictionary<string, string>.Empty),
|
||||
PolicyEvaluationVexEvidence.Empty,
|
||||
PolicyEvaluationSbom.Empty,
|
||||
exceptions ?? PolicyEvaluationExceptions.Empty);
|
||||
}
|
||||
PolicyEvaluationSbom.Empty,
|
||||
exceptions ?? PolicyEvaluationExceptions.Empty);
|
||||
}
|
||||
|
||||
private static string Describe(ImmutableArray<PolicyIssue> issues) =>
|
||||
string.Join(" | ", issues.Select(issue => $"{issue.Severity}:{issue.Code}:{issue.Message}"));
|
||||
|
||||
private static PolicyEvaluationComponent CreateRubyComponent(
|
||||
string name,
|
||||
string version,
|
||||
string groups,
|
||||
bool declaredOnly,
|
||||
string source,
|
||||
IEnumerable<string>? capabilities = null,
|
||||
IEnumerable<string>? schedulerCapabilities = null)
|
||||
{
|
||||
var metadataBuilder = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
if (!string.IsNullOrWhiteSpace(groups))
|
||||
{
|
||||
metadataBuilder["groups"] = groups;
|
||||
}
|
||||
|
||||
metadataBuilder["declaredOnly"] = declaredOnly ? "true" : "false";
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(source))
|
||||
{
|
||||
metadataBuilder["source"] = source.Trim();
|
||||
}
|
||||
|
||||
if (capabilities is not null)
|
||||
{
|
||||
foreach (var capability in capabilities)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(capability))
|
||||
{
|
||||
metadataBuilder[$"capability.{capability.Trim()}"] = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (schedulerCapabilities is not null)
|
||||
{
|
||||
var schedulerList = string.Join(
|
||||
';',
|
||||
schedulerCapabilities
|
||||
.Where(static s => !string.IsNullOrWhiteSpace(s))
|
||||
.Select(static s => s.Trim()));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(schedulerList))
|
||||
{
|
||||
metadataBuilder["capability.scheduler"] = schedulerList;
|
||||
}
|
||||
}
|
||||
|
||||
metadataBuilder["lockfile"] = "Gemfile.lock";
|
||||
|
||||
return new PolicyEvaluationComponent(
|
||||
name,
|
||||
version,
|
||||
"gem",
|
||||
$"pkg:gem/{name}@{version}",
|
||||
metadataBuilder.ToImmutable());
|
||||
}
|
||||
}
|
||||
private static string Describe(ImmutableArray<PolicyIssue> issues) =>
|
||||
string.Join(" | ", issues.Select(issue => $"{issue.Severity}:{issue.Code}:{issue.Message}"));
|
||||
|
||||
private static PolicyEvaluationComponent CreateRubyComponent(
|
||||
string name,
|
||||
string version,
|
||||
string groups,
|
||||
bool declaredOnly,
|
||||
string source,
|
||||
IEnumerable<string>? capabilities = null,
|
||||
IEnumerable<string>? schedulerCapabilities = null)
|
||||
{
|
||||
var metadataBuilder = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
if (!string.IsNullOrWhiteSpace(groups))
|
||||
{
|
||||
metadataBuilder["groups"] = groups;
|
||||
}
|
||||
|
||||
metadataBuilder["declaredOnly"] = declaredOnly ? "true" : "false";
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(source))
|
||||
{
|
||||
metadataBuilder["source"] = source.Trim();
|
||||
}
|
||||
|
||||
if (capabilities is not null)
|
||||
{
|
||||
foreach (var capability in capabilities)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(capability))
|
||||
{
|
||||
metadataBuilder[$"capability.{capability.Trim()}"] = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (schedulerCapabilities is not null)
|
||||
{
|
||||
var schedulerList = string.Join(
|
||||
';',
|
||||
schedulerCapabilities
|
||||
.Where(static s => !string.IsNullOrWhiteSpace(s))
|
||||
.Select(static s => s.Trim()));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(schedulerList))
|
||||
{
|
||||
metadataBuilder["capability.scheduler"] = schedulerList;
|
||||
}
|
||||
}
|
||||
|
||||
metadataBuilder["lockfile"] = "Gemfile.lock";
|
||||
|
||||
return new PolicyEvaluationComponent(
|
||||
name,
|
||||
version,
|
||||
"gem",
|
||||
$"pkg:gem/{name}@{version}",
|
||||
metadataBuilder.ToImmutable());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using System.Collections.Immutable;
|
||||
using StellaOps.Policy.Engine.Domain;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using StellaOps.Policy.Engine.Orchestration;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using StellaOps.Policy.Engine.Ledger;
|
||||
using StellaOps.Policy.Engine.Orchestration;
|
||||
|
||||
@@ -6,9 +6,25 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<UseConcelierTestInfra>false</UseConcelierTestInfra>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../StellaOps.Policy.Engine/StellaOps.Policy.Engine.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using StellaOps.Policy.Engine.TrustWeighting;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Tests;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Xunit;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using StellaOps.Policy.Engine.Ledger;
|
||||
using StellaOps.Policy.Engine.Orchestration;
|
||||
|
||||
Reference in New Issue
Block a user