release orchestrator v1 draft and build fixes
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// ChangeTracePredicateTests.cs
|
||||
// Sprint: SPRINT_20260112_200_005_ATTEST_predicate
|
||||
// Description: Tests for ChangeTracePredicate serialization.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Attestor.ProofChain.Predicates;
|
||||
|
||||
namespace StellaOps.Attestor.ProofChain.Tests.ChangeTrace;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for ChangeTracePredicate serialization and deserialization.
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class ChangeTracePredicateTests
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public void PredicateTypeUri_IsCorrect()
|
||||
{
|
||||
// Assert
|
||||
ChangeTracePredicate.PredicateTypeUri.Should().Be("stella.ops/changetrace@v1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_MinimalPredicate_ProducesValidJson()
|
||||
{
|
||||
// Arrange
|
||||
var predicate = new ChangeTracePredicate
|
||||
{
|
||||
FromDigest = "sha256:abc123",
|
||||
ToDigest = "sha256:def456",
|
||||
TenantId = "tenant-1",
|
||||
Summary = new ChangeTracePredicateSummary
|
||||
{
|
||||
ChangedPackages = 5,
|
||||
ChangedSymbols = 20,
|
||||
ChangedBytes = 1024,
|
||||
RiskDelta = -0.25,
|
||||
Verdict = "risk_down"
|
||||
},
|
||||
TrustDelta = new TrustDeltaRecord
|
||||
{
|
||||
Score = -0.25,
|
||||
ReachabilityImpact = "reduced",
|
||||
ExploitabilityImpact = "down"
|
||||
},
|
||||
AnalyzedAt = new DateTimeOffset(2026, 1, 12, 14, 30, 0, TimeSpan.Zero)
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(predicate, JsonOptions);
|
||||
|
||||
// Assert
|
||||
json.Should().NotBeNullOrEmpty();
|
||||
json.Should().Contain("\"fromDigest\"");
|
||||
json.Should().Contain("\"toDigest\"");
|
||||
json.Should().Contain("\"tenantId\"");
|
||||
json.Should().Contain("\"summary\"");
|
||||
json.Should().Contain("\"trustDelta\"");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RoundTrip_FullPredicate_PreservesAllData()
|
||||
{
|
||||
// Arrange
|
||||
var predicate = new ChangeTracePredicate
|
||||
{
|
||||
FromDigest = "sha256:abc123",
|
||||
ToDigest = "sha256:def456",
|
||||
TenantId = "tenant-1",
|
||||
Deltas =
|
||||
[
|
||||
new ChangeTraceDeltaEntry
|
||||
{
|
||||
Purl = "pkg:deb/debian/openssl@3.0.9",
|
||||
FromVersion = "3.0.9",
|
||||
ToVersion = "3.0.9-1+deb12u3",
|
||||
ChangeType = "Modified",
|
||||
Explain = "VendorBackport",
|
||||
SymbolsChanged = 10,
|
||||
BytesChanged = 2048,
|
||||
Confidence = 0.95,
|
||||
TrustDeltaScore = -0.3,
|
||||
CveIds = ["CVE-2026-12345"],
|
||||
Functions = ["ssl3_get_record"]
|
||||
}
|
||||
],
|
||||
Summary = new ChangeTracePredicateSummary
|
||||
{
|
||||
ChangedPackages = 1,
|
||||
ChangedSymbols = 10,
|
||||
ChangedBytes = 2048,
|
||||
RiskDelta = -0.3,
|
||||
Verdict = "risk_down"
|
||||
},
|
||||
TrustDelta = new TrustDeltaRecord
|
||||
{
|
||||
Score = -0.3,
|
||||
BeforeScore = 0.5,
|
||||
AfterScore = 0.8,
|
||||
ReachabilityImpact = "reduced",
|
||||
ExploitabilityImpact = "down"
|
||||
},
|
||||
ProofSteps = ["CVE patched", "Function verified"],
|
||||
DiffMethods = ["pkg", "symbol"],
|
||||
Policies = ["lattice:default@v3"],
|
||||
AnalyzedAt = new DateTimeOffset(2026, 1, 12, 14, 30, 0, TimeSpan.Zero),
|
||||
AlgorithmVersion = "1.0.0",
|
||||
CommitmentHash = "a1b2c3d4e5f6"
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(predicate, JsonOptions);
|
||||
var deserialized = JsonSerializer.Deserialize<ChangeTracePredicate>(json, JsonOptions);
|
||||
|
||||
// Assert
|
||||
deserialized.Should().NotBeNull();
|
||||
deserialized!.FromDigest.Should().Be(predicate.FromDigest);
|
||||
deserialized.ToDigest.Should().Be(predicate.ToDigest);
|
||||
deserialized.TenantId.Should().Be(predicate.TenantId);
|
||||
deserialized.Deltas.Should().HaveCount(1);
|
||||
deserialized.Deltas[0].Purl.Should().Be("pkg:deb/debian/openssl@3.0.9");
|
||||
deserialized.Summary.ChangedPackages.Should().Be(1);
|
||||
deserialized.TrustDelta.Score.Should().Be(-0.3);
|
||||
deserialized.ProofSteps.Should().HaveCount(2);
|
||||
deserialized.DiffMethods.Should().HaveCount(2);
|
||||
deserialized.Policies.Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_DeltaEntry_ContainsAllFields()
|
||||
{
|
||||
// Arrange
|
||||
var entry = new ChangeTraceDeltaEntry
|
||||
{
|
||||
Purl = "pkg:npm/lodash@4.17.21",
|
||||
FromVersion = "4.17.20",
|
||||
ToVersion = "4.17.21",
|
||||
ChangeType = "Upgraded",
|
||||
Explain = "UpstreamUpgrade",
|
||||
SymbolsChanged = 5,
|
||||
BytesChanged = 512,
|
||||
Confidence = 0.88,
|
||||
TrustDeltaScore = -0.1,
|
||||
CveIds = ["CVE-2026-00001"],
|
||||
Functions = ["merge", "clone"]
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(entry, JsonOptions);
|
||||
|
||||
// Assert
|
||||
json.Should().Contain("\"purl\"");
|
||||
json.Should().Contain("\"fromVersion\"");
|
||||
json.Should().Contain("\"toVersion\"");
|
||||
json.Should().Contain("\"changeType\"");
|
||||
json.Should().Contain("\"explain\"");
|
||||
json.Should().Contain("\"symbolsChanged\"");
|
||||
json.Should().Contain("\"bytesChanged\"");
|
||||
json.Should().Contain("\"confidence\"");
|
||||
json.Should().Contain("\"trustDeltaScore\"");
|
||||
json.Should().Contain("\"cveIds\"");
|
||||
json.Should().Contain("\"functions\"");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_Summary_ContainsAllFields()
|
||||
{
|
||||
// Arrange
|
||||
var summary = new ChangeTracePredicateSummary
|
||||
{
|
||||
ChangedPackages = 3,
|
||||
ChangedSymbols = 25,
|
||||
ChangedBytes = 8192,
|
||||
RiskDelta = 0.15,
|
||||
Verdict = "neutral"
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(summary, JsonOptions);
|
||||
|
||||
// Assert
|
||||
json.Should().Contain("\"changedPackages\"");
|
||||
json.Should().Contain("\"changedSymbols\"");
|
||||
json.Should().Contain("\"changedBytes\"");
|
||||
json.Should().Contain("\"riskDelta\"");
|
||||
json.Should().Contain("\"verdict\"");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_TrustDeltaRecord_ContainsAllFields()
|
||||
{
|
||||
// Arrange
|
||||
var trustDelta = new TrustDeltaRecord
|
||||
{
|
||||
Score = -0.45,
|
||||
BeforeScore = 0.4,
|
||||
AfterScore = 0.85,
|
||||
ReachabilityImpact = "eliminated",
|
||||
ExploitabilityImpact = "eliminated"
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(trustDelta, JsonOptions);
|
||||
|
||||
// Assert
|
||||
json.Should().Contain("\"score\"");
|
||||
json.Should().Contain("\"beforeScore\"");
|
||||
json.Should().Contain("\"afterScore\"");
|
||||
json.Should().Contain("\"reachabilityImpact\"");
|
||||
json.Should().Contain("\"exploitabilityImpact\"");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_EmptyDeltas_ProducesEmptyArray()
|
||||
{
|
||||
// Arrange
|
||||
var predicate = new ChangeTracePredicate
|
||||
{
|
||||
FromDigest = "sha256:abc",
|
||||
ToDigest = "sha256:def",
|
||||
TenantId = "test",
|
||||
Deltas = ImmutableArray<ChangeTraceDeltaEntry>.Empty,
|
||||
Summary = new ChangeTracePredicateSummary
|
||||
{
|
||||
ChangedPackages = 0,
|
||||
ChangedSymbols = 0,
|
||||
ChangedBytes = 0,
|
||||
RiskDelta = 0,
|
||||
Verdict = "neutral"
|
||||
},
|
||||
TrustDelta = new TrustDeltaRecord
|
||||
{
|
||||
Score = 0,
|
||||
ReachabilityImpact = "unchanged",
|
||||
ExploitabilityImpact = "unchanged"
|
||||
},
|
||||
AnalyzedAt = DateTimeOffset.UtcNow
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(predicate, JsonOptions);
|
||||
|
||||
// Assert
|
||||
json.Should().Contain("\"deltas\": []");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deserialize_JsonWithMissingOptionalFields_Succeeds()
|
||||
{
|
||||
// Arrange
|
||||
var json = """
|
||||
{
|
||||
"fromDigest": "sha256:abc",
|
||||
"toDigest": "sha256:def",
|
||||
"tenantId": "test",
|
||||
"summary": {
|
||||
"changedPackages": 1,
|
||||
"changedSymbols": 5,
|
||||
"changedBytes": 256,
|
||||
"riskDelta": -0.1,
|
||||
"verdict": "risk_down"
|
||||
},
|
||||
"trustDelta": {
|
||||
"score": -0.1,
|
||||
"reachabilityImpact": "reduced",
|
||||
"exploitabilityImpact": "down"
|
||||
},
|
||||
"analyzedAt": "2026-01-12T14:30:00Z"
|
||||
}
|
||||
""";
|
||||
|
||||
// Act
|
||||
var predicate = JsonSerializer.Deserialize<ChangeTracePredicate>(json, JsonOptions);
|
||||
|
||||
// Assert
|
||||
predicate.Should().NotBeNull();
|
||||
predicate!.Deltas.Should().BeEmpty();
|
||||
predicate.ProofSteps.Should().BeEmpty();
|
||||
predicate.DiffMethods.Should().BeEmpty();
|
||||
predicate.Policies.Should().BeEmpty();
|
||||
predicate.CommitmentHash.Should().BeNull();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user