more audit work
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
// <copyright file="IdentityEvidenceBuilderTests.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Scanner.Core.Contracts;
|
||||
using StellaOps.Scanner.Emit.Evidence;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Scanner.Emit.Tests.Evidence;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="IdentityEvidenceBuilder"/>.
|
||||
/// Sprint: SPRINT_20260107_005_001 Task EV-011
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class IdentityEvidenceBuilderTests
|
||||
{
|
||||
private readonly IdentityEvidenceBuilder _sut = new();
|
||||
|
||||
[Fact]
|
||||
public void Build_WithPurl_ReturnsFieldAsPurl()
|
||||
{
|
||||
// Arrange
|
||||
var component = CreateComponent(purl: "pkg:npm/lodash@4.17.21");
|
||||
|
||||
// Act
|
||||
var result = _sut.Build(component);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
result!.Field.Should().Be("purl");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithNameOnly_ReturnsFieldAsName()
|
||||
{
|
||||
// Arrange
|
||||
var component = CreateComponent(name: "my-package");
|
||||
|
||||
// Act
|
||||
var result = _sut.Build(component);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
result!.Field.Should().Be("name");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithManifestEvidence_IncludesManifestAnalysisMethod()
|
||||
{
|
||||
// Arrange
|
||||
var evidence = ImmutableArray.Create(
|
||||
new ComponentEvidence { Kind = "manifest", Value = "package.json", Source = "/app/package.json" });
|
||||
var component = CreateComponent(purl: "pkg:npm/lodash@4.17.21", evidence: evidence);
|
||||
|
||||
// Act
|
||||
var result = _sut.Build(component);
|
||||
|
||||
// Assert
|
||||
result!.Methods.Should().ContainSingle(m =>
|
||||
m.Technique == IdentityEvidenceTechnique.ManifestAnalysis);
|
||||
result.Methods![0].Confidence.Should().Be(0.95);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithBinaryEvidence_IncludesBinaryAnalysisMethod()
|
||||
{
|
||||
// Arrange
|
||||
var evidence = ImmutableArray.Create(
|
||||
new ComponentEvidence { Kind = "binary", Value = "lodash.dll", Source = "/app/lodash.dll" });
|
||||
var component = CreateComponent(purl: "pkg:npm/lodash@4.17.21", evidence: evidence);
|
||||
|
||||
// Act
|
||||
var result = _sut.Build(component);
|
||||
|
||||
// Assert
|
||||
result!.Methods.Should().ContainSingle(m =>
|
||||
m.Technique == IdentityEvidenceTechnique.BinaryAnalysis);
|
||||
result.Methods![0].Confidence.Should().Be(0.80);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithHashEvidence_IncludesHighConfidenceMethod()
|
||||
{
|
||||
// Arrange
|
||||
var evidence = ImmutableArray.Create(
|
||||
new ComponentEvidence { Kind = "hash", Value = "sha256:abc123", Source = "/app/lib.so" });
|
||||
var component = CreateComponent(purl: "pkg:npm/lodash@4.17.21", evidence: evidence);
|
||||
|
||||
// Act
|
||||
var result = _sut.Build(component);
|
||||
|
||||
// Assert
|
||||
result!.Methods.Should().ContainSingle(m =>
|
||||
m.Technique == IdentityEvidenceTechnique.HashComparison);
|
||||
result.Methods![0].Confidence.Should().Be(0.99);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithMultipleSources_IncludesAllMethods()
|
||||
{
|
||||
// Arrange
|
||||
var evidence = ImmutableArray.Create(
|
||||
new ComponentEvidence { Kind = "manifest", Value = "package.json", Source = "/app/package.json" },
|
||||
new ComponentEvidence { Kind = "binary", Value = "lib.dll", Source = "/app/lib.dll" },
|
||||
new ComponentEvidence { Kind = "hash", Value = "sha256:abc", Source = "/app/lib.so" });
|
||||
var component = CreateComponent(purl: "pkg:npm/lodash@4.17.21", evidence: evidence);
|
||||
|
||||
// Act
|
||||
var result = _sut.Build(component);
|
||||
|
||||
// Assert
|
||||
result!.Methods.Should().HaveCount(3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_CalculatesOverallConfidenceFromHighestMethod()
|
||||
{
|
||||
// Arrange
|
||||
var evidence = ImmutableArray.Create(
|
||||
new ComponentEvidence { Kind = "binary", Value = "lib.dll", Source = "/app/lib.dll" },
|
||||
new ComponentEvidence { Kind = "hash", Value = "sha256:abc", Source = "/app/lib.so" });
|
||||
var component = CreateComponent(purl: "pkg:npm/lodash@4.17.21", evidence: evidence);
|
||||
|
||||
// Act
|
||||
var result = _sut.Build(component);
|
||||
|
||||
// Assert
|
||||
result!.Confidence.Should().Be(0.99); // Hash match has highest confidence
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithNoIdentifyingData_ReturnsNull()
|
||||
{
|
||||
// Arrange - unknown name means no identification
|
||||
var component = new AggregatedComponent
|
||||
{
|
||||
Identity = ComponentIdentity.Create("unknown", "unknown"),
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _sut.Build(component);
|
||||
|
||||
// Assert
|
||||
result.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_WithPurlNoEvidence_ReturnsAttestationMethod()
|
||||
{
|
||||
// Arrange
|
||||
var component = CreateComponent(purl: "pkg:npm/lodash@4.17.21");
|
||||
|
||||
// Act
|
||||
var result = _sut.Build(component);
|
||||
|
||||
// Assert
|
||||
result!.Methods.Should().ContainSingle(m =>
|
||||
m.Technique == IdentityEvidenceTechnique.Attestation);
|
||||
result.Methods![0].Confidence.Should().Be(0.70);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_NullComponent_ThrowsArgumentNullException()
|
||||
{
|
||||
// Act & Assert
|
||||
var act = () => _sut.Build(null!);
|
||||
act.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
private static AggregatedComponent CreateComponent(
|
||||
string? purl = null,
|
||||
string? name = null,
|
||||
ImmutableArray<ComponentEvidence> evidence = default)
|
||||
{
|
||||
var identity = ComponentIdentity.Create(
|
||||
key: purl ?? name ?? "unknown",
|
||||
name: name ?? "test-component",
|
||||
purl: purl);
|
||||
|
||||
return new AggregatedComponent
|
||||
{
|
||||
Identity = identity,
|
||||
Evidence = evidence.IsDefault ? ImmutableArray<ComponentEvidence>.Empty : evidence,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user