test fixes and new product advisories work
This commit is contained in:
@@ -0,0 +1,399 @@
|
||||
// Copyright (c) StellaOps. All rights reserved.
|
||||
// Licensed under the BUSL-1.1 license.
|
||||
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.Attestor.EvidencePack.Models;
|
||||
|
||||
namespace StellaOps.Attestor.EvidencePack.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for ReleaseEvidencePackBuilder.
|
||||
/// </summary>
|
||||
public class ReleaseEvidencePackBuilderTests
|
||||
{
|
||||
private readonly ILogger<ReleaseEvidencePackBuilder> _logger =
|
||||
NullLogger<ReleaseEvidencePackBuilder>.Instance;
|
||||
|
||||
[Fact]
|
||||
public void Build_WithAllRequiredFields_ReturnsValidManifest()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithReleaseVersion("2.5.0")
|
||||
.WithSourceCommit("abc123def456abc123def456abc123def456abc123")
|
||||
.WithSourceDateEpoch(1705315800)
|
||||
.WithSigningKeyFingerprint("SHA256:abc123...")
|
||||
.AddArtifact(CreateTestArtifact());
|
||||
|
||||
// Act
|
||||
var manifest = builder.Build();
|
||||
|
||||
// Assert
|
||||
manifest.Should().NotBeNull();
|
||||
manifest.BundleFormatVersion.Should().Be("1.0.0");
|
||||
manifest.ReleaseVersion.Should().Be("2.5.0");
|
||||
manifest.SourceCommit.Should().Be("abc123def456abc123def456abc123def456abc123");
|
||||
manifest.SourceDateEpoch.Should().Be(1705315800);
|
||||
manifest.SigningKeyFingerprint.Should().Be("SHA256:abc123...");
|
||||
manifest.Artifacts.Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_ComputesManifestHash()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithReleaseVersion("2.5.0")
|
||||
.WithSourceCommit("abc123def456abc123def456abc123def456abc123")
|
||||
.WithSourceDateEpoch(1705315800)
|
||||
.WithSigningKeyFingerprint("SHA256:abc123...")
|
||||
.AddArtifact(CreateTestArtifact());
|
||||
|
||||
// Act
|
||||
var manifest = builder.Build();
|
||||
|
||||
// Assert
|
||||
manifest.ManifestHash.Should().NotBeNullOrWhiteSpace();
|
||||
manifest.ManifestHash.Should().HaveLength(64); // SHA-256 hex string
|
||||
manifest.ManifestHash.Should().MatchRegex("^[a-f0-9]{64}$");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_SetsCreatedAtToUtcNowIfNotProvided()
|
||||
{
|
||||
// Arrange
|
||||
var before = DateTimeOffset.UtcNow;
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithReleaseVersion("2.5.0")
|
||||
.WithSourceCommit("abc123def456abc123def456abc123def456abc123")
|
||||
.WithSourceDateEpoch(1705315800)
|
||||
.WithSigningKeyFingerprint("SHA256:abc123...")
|
||||
.AddArtifact(CreateTestArtifact());
|
||||
|
||||
// Act
|
||||
var manifest = builder.Build();
|
||||
var after = DateTimeOffset.UtcNow;
|
||||
|
||||
// Assert
|
||||
manifest.CreatedAt.Should().BeOnOrAfter(before);
|
||||
manifest.CreatedAt.Should().BeOnOrBefore(after);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_UsesProvidedCreatedAt()
|
||||
{
|
||||
// Arrange
|
||||
var customTimestamp = new DateTimeOffset(2025, 1, 15, 10, 30, 0, TimeSpan.Zero);
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithReleaseVersion("2.5.0")
|
||||
.WithSourceCommit("abc123def456abc123def456abc123def456abc123")
|
||||
.WithSourceDateEpoch(1705315800)
|
||||
.WithSigningKeyFingerprint("SHA256:abc123...")
|
||||
.WithCreatedAt(customTimestamp)
|
||||
.AddArtifact(CreateTestArtifact());
|
||||
|
||||
// Act
|
||||
var manifest = builder.Build();
|
||||
|
||||
// Assert
|
||||
manifest.CreatedAt.Should().Be(customTimestamp);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithoutReleaseVersion_ThrowsInvalidOperationException()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithSourceCommit("abc123def456abc123def456abc123def456abc123")
|
||||
.WithSourceDateEpoch(1705315800)
|
||||
.WithSigningKeyFingerprint("SHA256:abc123...")
|
||||
.AddArtifact(CreateTestArtifact());
|
||||
|
||||
// Act & Assert
|
||||
var act = () => builder.Build();
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*Release version is required*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithoutSourceCommit_ThrowsInvalidOperationException()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithReleaseVersion("2.5.0")
|
||||
.WithSourceDateEpoch(1705315800)
|
||||
.WithSigningKeyFingerprint("SHA256:abc123...")
|
||||
.AddArtifact(CreateTestArtifact());
|
||||
|
||||
// Act & Assert
|
||||
var act = () => builder.Build();
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*Source commit is required*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithoutSourceDateEpoch_ThrowsInvalidOperationException()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithReleaseVersion("2.5.0")
|
||||
.WithSourceCommit("abc123def456abc123def456abc123def456abc123")
|
||||
.WithSigningKeyFingerprint("SHA256:abc123...")
|
||||
.AddArtifact(CreateTestArtifact());
|
||||
|
||||
// Act & Assert
|
||||
var act = () => builder.Build();
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*SOURCE_DATE_EPOCH is required*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithoutSigningKeyFingerprint_ThrowsInvalidOperationException()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithReleaseVersion("2.5.0")
|
||||
.WithSourceCommit("abc123def456abc123def456abc123def456abc123")
|
||||
.WithSourceDateEpoch(1705315800)
|
||||
.AddArtifact(CreateTestArtifact());
|
||||
|
||||
// Act & Assert
|
||||
var act = () => builder.Build();
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*Signing key fingerprint is required*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithoutArtifacts_ThrowsInvalidOperationException()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithReleaseVersion("2.5.0")
|
||||
.WithSourceCommit("abc123def456abc123def456abc123def456abc123")
|
||||
.WithSourceDateEpoch(1705315800)
|
||||
.WithSigningKeyFingerprint("SHA256:abc123...");
|
||||
|
||||
// Act & Assert
|
||||
var act = () => builder.Build();
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*At least one artifact is required*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddArtifact_AddsToManifest()
|
||||
{
|
||||
// Arrange
|
||||
var builder = CreateValidBuilder();
|
||||
var artifact = new ArtifactEntry
|
||||
{
|
||||
Path = "artifacts/stella-2.5.0-linux-arm64.tar.gz",
|
||||
Name = "Stella CLI (Linux ARM64)",
|
||||
Platform = "linux-arm64",
|
||||
Sha256 = "b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3",
|
||||
Size = 11223344
|
||||
};
|
||||
|
||||
// Act
|
||||
builder.AddArtifact(artifact);
|
||||
var manifest = builder.Build();
|
||||
|
||||
// Assert
|
||||
manifest.Artifacts.Should().HaveCount(2);
|
||||
manifest.Artifacts.Should().Contain(a => a.Platform == "linux-arm64");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddArtifact_AddsChecksumEntry()
|
||||
{
|
||||
// Arrange
|
||||
var builder = CreateValidBuilder();
|
||||
var artifact = new ArtifactEntry
|
||||
{
|
||||
Path = "artifacts/stella-2.5.0-linux-arm64.tar.gz",
|
||||
Name = "Stella CLI (Linux ARM64)",
|
||||
Platform = "linux-arm64",
|
||||
Sha256 = "b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3",
|
||||
Sha512 = "b" + new string('c', 127),
|
||||
Size = 11223344
|
||||
};
|
||||
|
||||
// Act
|
||||
builder.AddArtifact(artifact);
|
||||
var manifest = builder.Build();
|
||||
|
||||
// Assert
|
||||
manifest.Checksums.Should().ContainKey("artifacts/stella-2.5.0-linux-arm64.tar.gz");
|
||||
var checksum = manifest.Checksums["artifacts/stella-2.5.0-linux-arm64.tar.gz"];
|
||||
checksum.Sha256.Should().Be(artifact.Sha256);
|
||||
checksum.Sha512.Should().Be(artifact.Sha512);
|
||||
checksum.Size.Should().Be(artifact.Size);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddSbom_AddsToManifest()
|
||||
{
|
||||
// Arrange
|
||||
var builder = CreateValidBuilder();
|
||||
var sbom = new SbomReference
|
||||
{
|
||||
Path = "sbom/stella-cli.cdx.json",
|
||||
Format = "cyclonedx-json",
|
||||
SpecVersion = "1.5",
|
||||
ForArtifact = "stella-2.5.0-linux-x64.tar.gz",
|
||||
Sha256 = "c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"
|
||||
};
|
||||
|
||||
// Act
|
||||
builder.AddSbom(sbom);
|
||||
var manifest = builder.Build();
|
||||
|
||||
// Assert
|
||||
manifest.Sboms.Should().HaveCount(1);
|
||||
manifest.Sboms[0].Format.Should().Be("cyclonedx-json");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddProvenance_AddsToManifest()
|
||||
{
|
||||
// Arrange
|
||||
var builder = CreateValidBuilder();
|
||||
var provenance = new ProvenanceReference
|
||||
{
|
||||
Path = "provenance/stella-cli.slsa.intoto.jsonl",
|
||||
PredicateType = "https://slsa.dev/provenance/v1",
|
||||
ForArtifact = "stella-2.5.0-linux-x64.tar.gz",
|
||||
BuilderId = "https://ci.stella-ops.org/builder/v1",
|
||||
SlsaLevel = 2,
|
||||
Sha256 = "d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5"
|
||||
};
|
||||
|
||||
// Act
|
||||
builder.AddProvenance(provenance);
|
||||
var manifest = builder.Build();
|
||||
|
||||
// Assert
|
||||
manifest.ProvenanceStatements.Should().HaveCount(1);
|
||||
manifest.ProvenanceStatements[0].SlsaLevel.Should().Be(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddAttestation_AddsToManifest()
|
||||
{
|
||||
// Arrange
|
||||
var builder = CreateValidBuilder();
|
||||
var attestation = new AttestationReference
|
||||
{
|
||||
Path = "attestations/build-attestation.dsse.json",
|
||||
Type = "dsse",
|
||||
Description = "Build attestation",
|
||||
Sha256 = "e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6"
|
||||
};
|
||||
|
||||
// Act
|
||||
builder.AddAttestation(attestation);
|
||||
var manifest = builder.Build();
|
||||
|
||||
// Assert
|
||||
manifest.Attestations.Should().HaveCount(1);
|
||||
manifest.Attestations[0].Type.Should().Be("dsse");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddRekorProof_AddsToManifest()
|
||||
{
|
||||
// Arrange
|
||||
var builder = CreateValidBuilder();
|
||||
var proof = new RekorProofEntry
|
||||
{
|
||||
Uuid = "abc123def456abc123def456abc123def456abc123def456abc123def456abc1",
|
||||
LogIndex = 12345678,
|
||||
IntegratedTime = 1705315800,
|
||||
ForArtifact = "stella-2.5.0-linux-x64.tar.gz",
|
||||
InclusionProofPath = "rekor-proofs/log-entries/abc123.json"
|
||||
};
|
||||
|
||||
// Act
|
||||
builder.AddRekorProof(proof);
|
||||
var manifest = builder.Build();
|
||||
|
||||
// Assert
|
||||
manifest.RekorProofs.Should().HaveCount(1);
|
||||
manifest.RekorProofs[0].LogIndex.Should().Be(12345678);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FluentApi_AllowsChaining()
|
||||
{
|
||||
// Arrange & Act
|
||||
var manifest = new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithReleaseVersion("2.5.0")
|
||||
.WithSourceCommit("abc123def456abc123def456abc123def456abc123")
|
||||
.WithSourceDateEpoch(1705315800)
|
||||
.WithSigningKeyFingerprint("SHA256:abc123...")
|
||||
.WithRekorLogId("rekor-log-id-123")
|
||||
.WithCreatedAt(DateTimeOffset.UtcNow)
|
||||
.AddArtifact(CreateTestArtifact())
|
||||
.Build();
|
||||
|
||||
// Assert
|
||||
manifest.Should().NotBeNull();
|
||||
manifest.RekorLogId.Should().Be("rekor-log-id-123");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithReleaseVersion_ThrowsOnNull()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger);
|
||||
|
||||
// Act & Assert
|
||||
var act = () => builder.WithReleaseVersion(null!);
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithSourceCommit_ThrowsOnNull()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger);
|
||||
|
||||
// Act & Assert
|
||||
var act = () => builder.WithSourceCommit(null!);
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddArtifact_ThrowsOnNull()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new ReleaseEvidencePackBuilder(_logger);
|
||||
|
||||
// Act & Assert
|
||||
var act = () => builder.AddArtifact(null!);
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
private ReleaseEvidencePackBuilder CreateValidBuilder()
|
||||
{
|
||||
return new ReleaseEvidencePackBuilder(_logger)
|
||||
.WithReleaseVersion("2.5.0")
|
||||
.WithSourceCommit("abc123def456abc123def456abc123def456abc123")
|
||||
.WithSourceDateEpoch(1705315800)
|
||||
.WithSigningKeyFingerprint("SHA256:abc123...")
|
||||
.AddArtifact(CreateTestArtifact());
|
||||
}
|
||||
|
||||
private static ArtifactEntry CreateTestArtifact()
|
||||
{
|
||||
return new ArtifactEntry
|
||||
{
|
||||
Path = "artifacts/stella-2.5.0-linux-x64.tar.gz",
|
||||
Name = "Stella CLI (Linux x64)",
|
||||
Platform = "linux-x64",
|
||||
Sha256 = "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
|
||||
Size = 12345678
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
// Copyright (c) StellaOps. All rights reserved.
|
||||
// Licensed under the BUSL-1.1 license.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Attestor.EvidencePack.Models;
|
||||
|
||||
namespace StellaOps.Attestor.EvidencePack.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for ReleaseEvidencePackManifest model serialization.
|
||||
/// </summary>
|
||||
public class ReleaseEvidencePackManifestTests
|
||||
{
|
||||
[Fact]
|
||||
public void Manifest_SerializesToJson_WithCorrectPropertyNames()
|
||||
{
|
||||
// Arrange
|
||||
var manifest = CreateValidManifest();
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(manifest);
|
||||
var doc = JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
|
||||
// Assert
|
||||
root.TryGetProperty("bundleFormatVersion", out _).Should().BeTrue();
|
||||
root.TryGetProperty("releaseVersion", out _).Should().BeTrue();
|
||||
root.TryGetProperty("createdAt", out _).Should().BeTrue();
|
||||
root.TryGetProperty("sourceCommit", out _).Should().BeTrue();
|
||||
root.TryGetProperty("sourceDateEpoch", out _).Should().BeTrue();
|
||||
root.TryGetProperty("artifacts", out _).Should().BeTrue();
|
||||
root.TryGetProperty("checksums", out _).Should().BeTrue();
|
||||
root.TryGetProperty("sboms", out _).Should().BeTrue();
|
||||
root.TryGetProperty("provenanceStatements", out _).Should().BeTrue();
|
||||
root.TryGetProperty("attestations", out _).Should().BeTrue();
|
||||
root.TryGetProperty("rekorProofs", out _).Should().BeTrue();
|
||||
root.TryGetProperty("signingKeyFingerprint", out _).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Manifest_RoundTrips_Successfully()
|
||||
{
|
||||
// Arrange
|
||||
var original = CreateValidManifest();
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(original);
|
||||
var deserialized = JsonSerializer.Deserialize<ReleaseEvidencePackManifest>(json);
|
||||
|
||||
// Assert
|
||||
deserialized.Should().NotBeNull();
|
||||
deserialized!.BundleFormatVersion.Should().Be(original.BundleFormatVersion);
|
||||
deserialized.ReleaseVersion.Should().Be(original.ReleaseVersion);
|
||||
deserialized.SourceCommit.Should().Be(original.SourceCommit);
|
||||
deserialized.SourceDateEpoch.Should().Be(original.SourceDateEpoch);
|
||||
deserialized.Artifacts.Should().HaveCount(original.Artifacts.Length);
|
||||
deserialized.SigningKeyFingerprint.Should().Be(original.SigningKeyFingerprint);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArtifactEntry_SerializesCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var artifact = new ArtifactEntry
|
||||
{
|
||||
Path = "artifacts/stella-2.5.0-linux-x64.tar.gz",
|
||||
Name = "Stella CLI",
|
||||
Platform = "linux-x64",
|
||||
Sha256 = "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
|
||||
Sha512 = "a" + new string('b', 127),
|
||||
Size = 12345678,
|
||||
SignaturePath = "artifacts/stella-2.5.0-linux-x64.tar.gz.sig"
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(artifact);
|
||||
var doc = JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
|
||||
// Assert
|
||||
root.GetProperty("path").GetString().Should().Be(artifact.Path);
|
||||
root.GetProperty("name").GetString().Should().Be(artifact.Name);
|
||||
root.GetProperty("platform").GetString().Should().Be(artifact.Platform);
|
||||
root.GetProperty("sha256").GetString().Should().Be(artifact.Sha256);
|
||||
root.GetProperty("size").GetInt64().Should().Be(artifact.Size);
|
||||
root.GetProperty("signaturePath").GetString().Should().Be(artifact.SignaturePath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ChecksumEntry_SerializesCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var checksum = new ChecksumEntry
|
||||
{
|
||||
Sha256 = "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
|
||||
Sha512 = "a" + new string('b', 127),
|
||||
Size = 12345678
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(checksum);
|
||||
var deserialized = JsonSerializer.Deserialize<ChecksumEntry>(json);
|
||||
|
||||
// Assert
|
||||
deserialized.Should().NotBeNull();
|
||||
deserialized!.Sha256.Should().Be(checksum.Sha256);
|
||||
deserialized.Sha512.Should().Be(checksum.Sha512);
|
||||
deserialized.Size.Should().Be(checksum.Size);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SbomReference_SerializesCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var sbom = new SbomReference
|
||||
{
|
||||
Path = "sbom/stella-cli.cdx.json",
|
||||
Format = "cyclonedx-json",
|
||||
SpecVersion = "1.5",
|
||||
ForArtifact = "stella-2.5.0-linux-x64.tar.gz",
|
||||
SignaturePath = "sbom/stella-cli.cdx.json.sig",
|
||||
Sha256 = "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(sbom);
|
||||
var doc = JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
|
||||
// Assert
|
||||
root.GetProperty("path").GetString().Should().Be(sbom.Path);
|
||||
root.GetProperty("format").GetString().Should().Be(sbom.Format);
|
||||
root.GetProperty("specVersion").GetString().Should().Be(sbom.SpecVersion);
|
||||
root.GetProperty("forArtifact").GetString().Should().Be(sbom.ForArtifact);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProvenanceReference_SerializesCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var provenance = new ProvenanceReference
|
||||
{
|
||||
Path = "provenance/stella-cli.slsa.intoto.jsonl",
|
||||
PredicateType = "https://slsa.dev/provenance/v1",
|
||||
ForArtifact = "stella-2.5.0-linux-x64.tar.gz",
|
||||
SignaturePath = "provenance/stella-cli.slsa.intoto.jsonl.sig",
|
||||
BuilderId = "https://ci.stella-ops.org/builder/v1",
|
||||
SlsaLevel = 2,
|
||||
Sha256 = "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(provenance);
|
||||
var doc = JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
|
||||
// Assert
|
||||
root.GetProperty("predicateType").GetString().Should().Be(provenance.PredicateType);
|
||||
root.GetProperty("builderId").GetString().Should().Be(provenance.BuilderId);
|
||||
root.GetProperty("slsaLevel").GetInt32().Should().Be(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RekorProofEntry_SerializesCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var proof = new RekorProofEntry
|
||||
{
|
||||
Uuid = "abc123def456abc123def456abc123def456abc123def456abc123def456abc1",
|
||||
LogIndex = 12345678,
|
||||
IntegratedTime = 1705315800,
|
||||
ForArtifact = "stella-2.5.0-linux-x64.tar.gz",
|
||||
InclusionProofPath = "rekor-proofs/log-entries/abc123.json"
|
||||
};
|
||||
|
||||
// Act
|
||||
var json = JsonSerializer.Serialize(proof);
|
||||
var deserialized = JsonSerializer.Deserialize<RekorProofEntry>(json);
|
||||
|
||||
// Assert
|
||||
deserialized.Should().NotBeNull();
|
||||
deserialized!.Uuid.Should().Be(proof.Uuid);
|
||||
deserialized.LogIndex.Should().Be(proof.LogIndex);
|
||||
deserialized.IntegratedTime.Should().Be(proof.IntegratedTime);
|
||||
deserialized.ForArtifact.Should().Be(proof.ForArtifact);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Manifest_OptionalFieldsOmittedWhenNull()
|
||||
{
|
||||
// Arrange
|
||||
var manifest = CreateValidManifest();
|
||||
|
||||
// Act
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
|
||||
};
|
||||
var json = JsonSerializer.Serialize(manifest, options);
|
||||
var doc = JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
|
||||
// Assert - RekorLogId is null in the test manifest
|
||||
root.TryGetProperty("rekorLogId", out _).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Manifest_ArtifactsArrayIsImmutable()
|
||||
{
|
||||
// Arrange
|
||||
var manifest = CreateValidManifest();
|
||||
|
||||
// Assert - ImmutableArray cannot be modified
|
||||
manifest.Artifacts.Should().BeOfType<ImmutableArray<ArtifactEntry>>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Manifest_ChecksumsDictionaryIsImmutable()
|
||||
{
|
||||
// Arrange
|
||||
var manifest = CreateValidManifest();
|
||||
|
||||
// Assert - ImmutableDictionary cannot be modified
|
||||
manifest.Checksums.Should().BeAssignableTo<IImmutableDictionary<string, ChecksumEntry>>();
|
||||
}
|
||||
|
||||
private static ReleaseEvidencePackManifest CreateValidManifest()
|
||||
{
|
||||
var artifacts = ImmutableArray.Create(
|
||||
new ArtifactEntry
|
||||
{
|
||||
Path = "artifacts/stella-2.5.0-linux-x64.tar.gz",
|
||||
Name = "Stella CLI (Linux x64)",
|
||||
Platform = "linux-x64",
|
||||
Sha256 = "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
|
||||
Size = 12345678
|
||||
}
|
||||
);
|
||||
|
||||
var checksums = ImmutableDictionary.CreateRange(new[]
|
||||
{
|
||||
KeyValuePair.Create(
|
||||
"artifacts/stella-2.5.0-linux-x64.tar.gz",
|
||||
new ChecksumEntry
|
||||
{
|
||||
Sha256 = "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
|
||||
Size = 12345678
|
||||
})
|
||||
});
|
||||
|
||||
return new ReleaseEvidencePackManifest
|
||||
{
|
||||
BundleFormatVersion = "1.0.0",
|
||||
ReleaseVersion = "2.5.0",
|
||||
CreatedAt = new DateTimeOffset(2025, 1, 15, 10, 30, 0, TimeSpan.Zero),
|
||||
SourceCommit = "abc123def456abc123def456abc123def456abc123",
|
||||
SourceDateEpoch = 1705315800,
|
||||
Artifacts = artifacts,
|
||||
Checksums = checksums,
|
||||
Sboms = ImmutableArray<SbomReference>.Empty,
|
||||
ProvenanceStatements = ImmutableArray<ProvenanceReference>.Empty,
|
||||
Attestations = ImmutableArray<AttestationReference>.Empty,
|
||||
RekorProofs = ImmutableArray<RekorProofEntry>.Empty,
|
||||
SigningKeyFingerprint = "SHA256:abc123def456..."
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Include="Moq" />
|
||||
<PackageReference Include="xunit" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" />
|
||||
<PackageReference Include="coverlet.collector" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Attestor.EvidencePack\StellaOps.Attestor.EvidencePack.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user