333 lines
9.6 KiB
C#
333 lines
9.6 KiB
C#
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
// Copyright (c) StellaOps
|
|
|
|
using System.Collections.Immutable;
|
|
using FluentAssertions;
|
|
using StellaOps.Scanner.Emit.Lineage;
|
|
|
|
using StellaOps.TestKit;
|
|
namespace StellaOps.Scanner.Emit.Lineage.Tests;
|
|
|
|
public class RebuildProofTests
|
|
{
|
|
#region RebuildProof Model Tests
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void RebuildProof_RequiredProperties_MustBeSet()
|
|
{
|
|
var proof = new RebuildProof
|
|
{
|
|
SbomId = SbomId.New(),
|
|
ImageDigest = "sha256:abc123",
|
|
StellaOpsVersion = "1.0.0",
|
|
FeedSnapshots = [],
|
|
AnalyzerVersions = [],
|
|
PolicyHash = "sha256:policy",
|
|
GeneratedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
proof.SbomId.Should().NotBe(default(SbomId));
|
|
proof.ImageDigest.Should().NotBeNullOrEmpty();
|
|
proof.StellaOpsVersion.Should().Be("1.0.0");
|
|
proof.PolicyHash.Should().NotBeNullOrEmpty();
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void RebuildProof_WithFeedSnapshots_TracksAllFeeds()
|
|
{
|
|
var feeds = ImmutableArray.Create(
|
|
new FeedSnapshot
|
|
{
|
|
FeedId = "nvd",
|
|
FeedName = "NVD CVE Feed",
|
|
SnapshotHash = "sha256:nvdhash",
|
|
AsOf = DateTimeOffset.UtcNow,
|
|
EntryCount = 200000
|
|
},
|
|
new FeedSnapshot
|
|
{
|
|
FeedId = "ghsa",
|
|
FeedName = "GitHub Security Advisories",
|
|
SnapshotHash = "sha256:ghsahash",
|
|
AsOf = DateTimeOffset.UtcNow,
|
|
EntryCount = 15000
|
|
}
|
|
);
|
|
|
|
var proof = new RebuildProof
|
|
{
|
|
SbomId = SbomId.New(),
|
|
ImageDigest = "sha256:image",
|
|
StellaOpsVersion = "1.0.0",
|
|
FeedSnapshots = feeds,
|
|
AnalyzerVersions = [],
|
|
PolicyHash = "sha256:policy",
|
|
GeneratedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
proof.FeedSnapshots.Should().HaveCount(2);
|
|
proof.FeedSnapshots[0].FeedId.Should().Be("nvd");
|
|
proof.FeedSnapshots[1].EntryCount.Should().Be(15000);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void RebuildProof_WithAnalyzerVersions_TracksAllAnalyzers()
|
|
{
|
|
var analyzers = ImmutableArray.Create(
|
|
new AnalyzerVersion
|
|
{
|
|
AnalyzerId = "npm-analyzer",
|
|
AnalyzerName = "NPM Package Analyzer",
|
|
Version = "2.0.0",
|
|
CodeHash = "sha256:npmhash"
|
|
},
|
|
new AnalyzerVersion
|
|
{
|
|
AnalyzerId = "dotnet-analyzer",
|
|
AnalyzerName = ".NET Package Analyzer",
|
|
Version = "3.1.0"
|
|
}
|
|
);
|
|
|
|
var proof = new RebuildProof
|
|
{
|
|
SbomId = SbomId.New(),
|
|
ImageDigest = "sha256:image",
|
|
StellaOpsVersion = "1.0.0",
|
|
FeedSnapshots = [],
|
|
AnalyzerVersions = analyzers,
|
|
PolicyHash = "sha256:policy",
|
|
GeneratedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
proof.AnalyzerVersions.Should().HaveCount(2);
|
|
proof.AnalyzerVersions[0].AnalyzerId.Should().Be("npm-analyzer");
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void RebuildProof_OptionalDsseSignature_IsNullByDefault()
|
|
{
|
|
var proof = new RebuildProof
|
|
{
|
|
SbomId = SbomId.New(),
|
|
ImageDigest = "sha256:image",
|
|
StellaOpsVersion = "1.0.0",
|
|
FeedSnapshots = [],
|
|
AnalyzerVersions = [],
|
|
PolicyHash = "sha256:policy",
|
|
GeneratedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
proof.DsseSignature.Should().BeNull();
|
|
proof.ProofHash.Should().BeNull();
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void RebuildProof_WithSignature_StoresSignature()
|
|
{
|
|
var proof = new RebuildProof
|
|
{
|
|
SbomId = SbomId.New(),
|
|
ImageDigest = "sha256:image",
|
|
StellaOpsVersion = "1.0.0",
|
|
FeedSnapshots = [],
|
|
AnalyzerVersions = [],
|
|
PolicyHash = "sha256:policy",
|
|
GeneratedAt = DateTimeOffset.UtcNow,
|
|
DsseSignature = "eyJwYXlsb2FkIjoiLi4uIn0=",
|
|
ProofHash = "sha256:proofhash"
|
|
};
|
|
|
|
proof.DsseSignature.Should().NotBeNullOrEmpty();
|
|
proof.ProofHash.Should().StartWith("sha256:");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region FeedSnapshot Tests
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void FeedSnapshot_RequiredProperties_MustBeSet()
|
|
{
|
|
var snapshot = new FeedSnapshot
|
|
{
|
|
FeedId = "nvd",
|
|
FeedName = "NVD CVE Feed",
|
|
SnapshotHash = "sha256:hash",
|
|
AsOf = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
snapshot.FeedId.Should().Be("nvd");
|
|
snapshot.FeedName.Should().Be("NVD CVE Feed");
|
|
snapshot.SnapshotHash.Should().NotBeNullOrEmpty();
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void FeedSnapshot_OptionalProperties_AreNullByDefault()
|
|
{
|
|
var snapshot = new FeedSnapshot
|
|
{
|
|
FeedId = "nvd",
|
|
FeedName = "NVD",
|
|
SnapshotHash = "sha256:hash",
|
|
AsOf = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
snapshot.EntryCount.Should().BeNull();
|
|
snapshot.FeedVersion.Should().BeNull();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AnalyzerVersion Tests
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void AnalyzerVersion_RequiredProperties_MustBeSet()
|
|
{
|
|
var analyzer = new AnalyzerVersion
|
|
{
|
|
AnalyzerId = "npm-analyzer",
|
|
AnalyzerName = "NPM Package Analyzer",
|
|
Version = "2.0.0"
|
|
};
|
|
|
|
analyzer.AnalyzerId.Should().Be("npm-analyzer");
|
|
analyzer.AnalyzerName.Should().Be("NPM Package Analyzer");
|
|
analyzer.Version.Should().Be("2.0.0");
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void AnalyzerVersion_OptionalHashes_AreNullByDefault()
|
|
{
|
|
var analyzer = new AnalyzerVersion
|
|
{
|
|
AnalyzerId = "test",
|
|
AnalyzerName = "Test",
|
|
Version = "1.0.0"
|
|
};
|
|
|
|
analyzer.CodeHash.Should().BeNull();
|
|
analyzer.ConfigHash.Should().BeNull();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RebuildVerification Tests
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void RebuildVerification_SuccessfulRebuild_HasMatchingHash()
|
|
{
|
|
var proof = new RebuildProof
|
|
{
|
|
SbomId = SbomId.New(),
|
|
ImageDigest = "sha256:image",
|
|
StellaOpsVersion = "1.0.0",
|
|
FeedSnapshots = [],
|
|
AnalyzerVersions = [],
|
|
PolicyHash = "sha256:policy",
|
|
GeneratedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
var verification = new RebuildVerification
|
|
{
|
|
Proof = proof,
|
|
Success = true,
|
|
RebuiltSbomId = SbomId.New(),
|
|
HashMatches = true,
|
|
VerifiedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
verification.Success.Should().BeTrue();
|
|
verification.HashMatches.Should().BeTrue();
|
|
verification.Differences.Should().BeNull();
|
|
verification.ErrorMessage.Should().BeNull();
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void RebuildVerification_FailedRebuild_HasErrorMessage()
|
|
{
|
|
var proof = new RebuildProof
|
|
{
|
|
SbomId = SbomId.New(),
|
|
ImageDigest = "sha256:image",
|
|
StellaOpsVersion = "1.0.0",
|
|
FeedSnapshots = [],
|
|
AnalyzerVersions = [],
|
|
PolicyHash = "sha256:policy",
|
|
GeneratedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
var verification = new RebuildVerification
|
|
{
|
|
Proof = proof,
|
|
Success = false,
|
|
ErrorMessage = "Feed snapshot not available",
|
|
VerifiedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
verification.Success.Should().BeFalse();
|
|
verification.ErrorMessage.Should().Be("Feed snapshot not available");
|
|
verification.RebuiltSbomId.Should().BeNull();
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void RebuildVerification_MismatchRebuild_HasDifferences()
|
|
{
|
|
var proof = new RebuildProof
|
|
{
|
|
SbomId = SbomId.New(),
|
|
ImageDigest = "sha256:image",
|
|
StellaOpsVersion = "1.0.0",
|
|
FeedSnapshots = [],
|
|
AnalyzerVersions = [],
|
|
PolicyHash = "sha256:policy",
|
|
GeneratedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
var diff = new SbomDiff
|
|
{
|
|
FromId = proof.SbomId,
|
|
ToId = SbomId.New(),
|
|
Deltas = [],
|
|
Summary = new DiffSummary
|
|
{
|
|
Added = 1,
|
|
Removed = 0,
|
|
VersionChanged = 0,
|
|
OtherModified = 0,
|
|
Unchanged = 100
|
|
},
|
|
ComputedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
var verification = new RebuildVerification
|
|
{
|
|
Proof = proof,
|
|
Success = true,
|
|
RebuiltSbomId = SbomId.New(),
|
|
HashMatches = false,
|
|
Differences = diff,
|
|
VerifiedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
verification.Success.Should().BeTrue();
|
|
verification.HashMatches.Should().BeFalse();
|
|
verification.Differences.Should().NotBeNull();
|
|
verification.Differences!.Summary.Added.Should().Be(1);
|
|
}
|
|
|
|
#endregion
|
|
}
|