more audit work
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
// <copyright file="CycloneDxPedigreeMapperTests.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using CycloneDX.Models;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Scanner.Emit.Pedigree;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Scanner.Emit.Tests.Pedigree;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="CycloneDxPedigreeMapper"/>.
|
||||
/// Sprint: SPRINT_20260107_005_002 Task PD-011
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class CycloneDxPedigreeMapperTests
|
||||
{
|
||||
private readonly CycloneDxPedigreeMapper _mapper = new();
|
||||
|
||||
[Fact]
|
||||
public void Map_NullData_ReturnsNull()
|
||||
{
|
||||
// Act
|
||||
var result = _mapper.Map(null);
|
||||
|
||||
// Assert
|
||||
result.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_EmptyData_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var data = new PedigreeData();
|
||||
|
||||
// Act
|
||||
var result = _mapper.Map(data);
|
||||
|
||||
// Assert
|
||||
result.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_WithAncestors_MapsToComponents()
|
||||
{
|
||||
// Arrange
|
||||
var data = new PedigreeData
|
||||
{
|
||||
Ancestors = ImmutableArray.Create(
|
||||
new AncestorComponent
|
||||
{
|
||||
Name = "openssl",
|
||||
Version = "1.1.1n",
|
||||
Purl = "pkg:generic/openssl@1.1.1n",
|
||||
ProjectUrl = "https://www.openssl.org",
|
||||
Level = 1
|
||||
})
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _mapper.Map(data);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
result!.Ancestors.Should().HaveCount(1);
|
||||
|
||||
var ancestor = result.Ancestors![0];
|
||||
ancestor.Name.Should().Be("openssl");
|
||||
ancestor.Version.Should().Be("1.1.1n");
|
||||
ancestor.Purl.Should().Be("pkg:generic/openssl@1.1.1n");
|
||||
ancestor.ExternalReferences.Should().Contain(r =>
|
||||
r.Type == ExternalReference.ExternalReferenceType.Website &&
|
||||
r.Url == "https://www.openssl.org");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_WithVariants_MapsToComponents()
|
||||
{
|
||||
// Arrange
|
||||
var data = new PedigreeData
|
||||
{
|
||||
Variants = ImmutableArray.Create(
|
||||
new VariantComponent
|
||||
{
|
||||
Name = "openssl",
|
||||
Version = "1.1.1n-0+deb11u5",
|
||||
Purl = "pkg:deb/debian/openssl@1.1.1n-0+deb11u5",
|
||||
Distribution = "debian",
|
||||
Release = "bullseye"
|
||||
})
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _mapper.Map(data);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
result!.Variants.Should().HaveCount(1);
|
||||
|
||||
var variant = result.Variants![0];
|
||||
variant.Name.Should().Be("openssl");
|
||||
variant.Purl.Should().Be("pkg:deb/debian/openssl@1.1.1n-0+deb11u5");
|
||||
variant.Properties.Should().Contain(p => p.Name == "stellaops:pedigree:distribution" && p.Value == "debian");
|
||||
variant.Properties.Should().Contain(p => p.Name == "stellaops:pedigree:release" && p.Value == "bullseye");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_WithCommits_MapsToCommitList()
|
||||
{
|
||||
// Arrange
|
||||
var timestamp = new DateTimeOffset(2024, 6, 15, 10, 30, 0, TimeSpan.Zero);
|
||||
var data = new PedigreeData
|
||||
{
|
||||
Commits = ImmutableArray.Create(
|
||||
new CommitInfo
|
||||
{
|
||||
Uid = "abc123def456789",
|
||||
Url = "https://github.com/openssl/openssl/commit/abc123",
|
||||
Message = "Fix CVE-2024-1234",
|
||||
Author = new CommitActor
|
||||
{
|
||||
Name = "Developer",
|
||||
Email = "dev@example.com",
|
||||
Timestamp = timestamp
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _mapper.Map(data);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
result!.Commits.Should().HaveCount(1);
|
||||
|
||||
var commit = result.Commits![0];
|
||||
commit.Uid.Should().Be("abc123def456789");
|
||||
commit.Url.Should().Be("https://github.com/openssl/openssl/commit/abc123");
|
||||
commit.Message.Should().Be("Fix CVE-2024-1234");
|
||||
commit.Author.Should().NotBeNull();
|
||||
commit.Author!.Name.Should().Be("Developer");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_WithPatches_MapsToPatchList()
|
||||
{
|
||||
// Arrange
|
||||
var data = new PedigreeData
|
||||
{
|
||||
Patches = ImmutableArray.Create(
|
||||
new PatchInfo
|
||||
{
|
||||
Type = PatchType.Backport,
|
||||
DiffUrl = "https://patch.url/fix.patch",
|
||||
DiffText = "--- a/file.c\n+++ b/file.c\n@@ -10,3 +10,4 @@",
|
||||
Resolves = ImmutableArray.Create(
|
||||
new PatchResolution
|
||||
{
|
||||
Id = "CVE-2024-1234",
|
||||
SourceName = "NVD"
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _mapper.Map(data);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
result!.Patches.Should().HaveCount(1);
|
||||
|
||||
var patch = result.Patches![0];
|
||||
patch.Type.Should().Be(Patch.PatchClassification.Backport);
|
||||
patch.Diff.Should().NotBeNull();
|
||||
patch.Diff!.Url.Should().Be("https://patch.url/fix.patch");
|
||||
patch.Resolves.Should().Contain(i => i.Id == "CVE-2024-1234");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_WithNotes_IncludesNotes()
|
||||
{
|
||||
// Arrange
|
||||
var data = new PedigreeData
|
||||
{
|
||||
Notes = "Backported security fix from upstream 1.1.1o",
|
||||
Ancestors = ImmutableArray.Create(
|
||||
new AncestorComponent { Name = "openssl", Version = "1.1.1o" })
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _mapper.Map(data);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
result!.Notes.Should().Be("Backported security fix from upstream 1.1.1o");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_MultipleAncestors_OrdersByLevel()
|
||||
{
|
||||
// Arrange
|
||||
var data = new PedigreeData
|
||||
{
|
||||
Ancestors = ImmutableArray.Create(
|
||||
new AncestorComponent { Name = "grandparent", Version = "1.0", Level = 2 },
|
||||
new AncestorComponent { Name = "parent", Version = "2.0", Level = 1 })
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _mapper.Map(data);
|
||||
|
||||
// Assert
|
||||
result!.Ancestors![0].Name.Should().Be("parent");
|
||||
result.Ancestors[1].Name.Should().Be("grandparent");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_PatchTypes_MapCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var data = new PedigreeData
|
||||
{
|
||||
Patches = ImmutableArray.Create(
|
||||
new PatchInfo { Type = PatchType.Backport },
|
||||
new PatchInfo { Type = PatchType.CherryPick },
|
||||
new PatchInfo { Type = PatchType.Unofficial },
|
||||
new PatchInfo { Type = PatchType.Monkey })
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _mapper.Map(data);
|
||||
|
||||
// Assert
|
||||
result!.Patches!.Select(p => p.Type).Should().BeEquivalentTo(new[]
|
||||
{
|
||||
Patch.PatchClassification.Backport,
|
||||
Patch.PatchClassification.Cherry_Pick,
|
||||
Patch.PatchClassification.Unofficial,
|
||||
Patch.PatchClassification.Monkey
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user