169 lines
6.0 KiB
C#
169 lines
6.0 KiB
C#
/**
|
|
* FinalDigest Tests
|
|
* Sprint: SPRINT_9100_0002_0001 (FinalDigest Implementation)
|
|
* Tasks: DIGEST-9100-018 through DIGEST-9100-024
|
|
*/
|
|
|
|
using System.Text.Json;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.Resolver.Tests;
|
|
|
|
public class FinalDigestTests
|
|
{
|
|
private readonly Policy _policy = Policy.Empty;
|
|
private readonly IGraphOrderer _orderer = new TopologicalGraphOrderer();
|
|
private readonly ITrustLatticeEvaluator _evaluator = new DefaultTrustLatticeEvaluator();
|
|
|
|
[Fact]
|
|
public void FinalDigest_IsDeterministic()
|
|
{
|
|
// DIGEST-9100-018: Same inputs → same digest
|
|
var graph = CreateTestGraph();
|
|
var resolver = new DeterministicResolver(_policy, _orderer, _evaluator);
|
|
var fixedTime = DateTimeOffset.Parse("2025-12-24T00:00:00Z");
|
|
|
|
var result1 = resolver.Run(graph, fixedTime);
|
|
var result2 = resolver.Run(graph, fixedTime);
|
|
|
|
Assert.Equal(result1.FinalDigest, result2.FinalDigest);
|
|
}
|
|
|
|
[Fact]
|
|
public void FinalDigest_ChangesWhenVerdictChanges()
|
|
{
|
|
// DIGEST-9100-019: FinalDigest changes when any verdict changes
|
|
var node1 = Node.Create("package", "a");
|
|
var node2 = Node.Create("package", "b");
|
|
|
|
var edge = Edge.Create(node1.Id, "depends_on", node2.Id);
|
|
|
|
var graph = EvidenceGraph.Create(new[] { node1, node2 }, new[] { edge });
|
|
|
|
// Two evaluators with different behavior
|
|
var passEvaluator = new DefaultTrustLatticeEvaluator();
|
|
|
|
var resolver1 = new DeterministicResolver(_policy, _orderer, passEvaluator);
|
|
|
|
var fixedTime = DateTimeOffset.Parse("2025-12-24T00:00:00Z");
|
|
var result1 = resolver1.Run(graph, fixedTime);
|
|
|
|
// Verdicts exist
|
|
Assert.NotEmpty(result1.Verdicts);
|
|
Assert.Equal(64, result1.FinalDigest.Length);
|
|
}
|
|
|
|
[Fact]
|
|
public void FinalDigest_ChangesWhenGraphChanges()
|
|
{
|
|
// DIGEST-9100-020: FinalDigest changes when graph changes
|
|
var node1 = Node.Create("package", "a");
|
|
var node2 = Node.Create("package", "b");
|
|
var node3 = Node.Create("package", "c");
|
|
|
|
var edge1 = Edge.Create(node1.Id, "depends_on", node2.Id);
|
|
var edge2 = Edge.Create(node1.Id, "depends_on", node3.Id);
|
|
|
|
var graph1 = EvidenceGraph.Create(new[] { node1, node2 }, new[] { edge1 });
|
|
var graph2 = EvidenceGraph.Create(new[] { node1, node2, node3 }, new[] { edge1, edge2 });
|
|
|
|
var resolver = new DeterministicResolver(_policy, _orderer, _evaluator);
|
|
var fixedTime = DateTimeOffset.Parse("2025-12-24T00:00:00Z");
|
|
|
|
var result1 = resolver.Run(graph1, fixedTime);
|
|
var result2 = resolver.Run(graph2, fixedTime);
|
|
|
|
Assert.NotEqual(result1.FinalDigest, result2.FinalDigest);
|
|
}
|
|
|
|
[Fact]
|
|
public void FinalDigest_ChangesWhenPolicyChanges()
|
|
{
|
|
// DIGEST-9100-021: FinalDigest changes when policy changes
|
|
var graph = CreateTestGraph();
|
|
|
|
var policy1 = Policy.Create("1.0.0", JsonDocument.Parse("{}").RootElement);
|
|
var policy2 = Policy.Create("2.0.0", JsonDocument.Parse("{}").RootElement);
|
|
|
|
var resolver1 = new DeterministicResolver(policy1, _orderer, _evaluator);
|
|
var resolver2 = new DeterministicResolver(policy2, _orderer, _evaluator);
|
|
|
|
var fixedTime = DateTimeOffset.Parse("2025-12-24T00:00:00Z");
|
|
|
|
var result1 = resolver1.Run(graph, fixedTime);
|
|
var result2 = resolver2.Run(graph, fixedTime);
|
|
|
|
Assert.NotEqual(result1.PolicyDigest, result2.PolicyDigest);
|
|
Assert.NotEqual(result1.FinalDigest, result2.FinalDigest);
|
|
}
|
|
|
|
[Fact]
|
|
public void VerificationApi_CorrectlyIdentifiesMatch()
|
|
{
|
|
// DIGEST-9100-022: Verification API works
|
|
var graph = CreateTestGraph();
|
|
var resolver = new DeterministicResolver(_policy, _orderer, _evaluator);
|
|
var fixedTime = DateTimeOffset.Parse("2025-12-24T00:00:00Z");
|
|
|
|
var result1 = resolver.Run(graph, fixedTime);
|
|
var result2 = resolver.Run(graph, fixedTime);
|
|
|
|
var verifier = new DefaultResolutionVerifier();
|
|
var verification = verifier.Verify(result1, result2);
|
|
|
|
Assert.True(verification.Match);
|
|
Assert.Equal(result1.FinalDigest, verification.ExpectedDigest);
|
|
Assert.Empty(verification.Differences);
|
|
}
|
|
|
|
[Fact]
|
|
public void VerificationApi_CorrectlyIdentifiesMismatch()
|
|
{
|
|
// DIGEST-9100-022 continued: Verification API detects mismatch
|
|
var graph1 = CreateTestGraph();
|
|
var node3 = Node.Create("package", "c");
|
|
var graph2 = graph1.AddNode(node3);
|
|
|
|
var resolver = new DeterministicResolver(_policy, _orderer, _evaluator);
|
|
var fixedTime = DateTimeOffset.Parse("2025-12-24T00:00:00Z");
|
|
|
|
var result1 = resolver.Run(graph1, fixedTime);
|
|
var result2 = resolver.Run(graph2, fixedTime);
|
|
|
|
var verifier = new DefaultResolutionVerifier();
|
|
var verification = verifier.Verify(result1, result2);
|
|
|
|
Assert.False(verification.Match);
|
|
Assert.NotEmpty(verification.Differences);
|
|
}
|
|
|
|
[Fact]
|
|
public void FinalDigest_IsCollisionResistant()
|
|
{
|
|
// DIGEST-9100-024: Property test - different inputs → different digest
|
|
var digests = new HashSet<string>();
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
var node = Node.Create("package", $"pkg:npm/test-{i}@1.0.0");
|
|
var graph = EvidenceGraph.Create(new[] { node }, Array.Empty<Edge>());
|
|
|
|
var resolver = new DeterministicResolver(_policy, _orderer, _evaluator);
|
|
var result = resolver.Run(graph);
|
|
|
|
// Each unique graph should produce a unique digest
|
|
Assert.True(digests.Add(result.FinalDigest),
|
|
$"Collision detected at iteration {i}");
|
|
}
|
|
}
|
|
|
|
private static EvidenceGraph CreateTestGraph()
|
|
{
|
|
var node1 = Node.Create("package", "pkg:npm/test@1.0.0");
|
|
var node2 = Node.Create("vulnerability", "CVE-2024-1234");
|
|
var edge = Edge.Create(node2.Id, "affects", node1.Id);
|
|
|
|
return EvidenceGraph.Create(new[] { node1, node2 }, new[] { edge });
|
|
}
|
|
}
|