This commit is contained in:
StellaOps Bot
2025-12-26 15:19:07 +02:00
25 changed files with 3377 additions and 132 deletions

View File

@@ -0,0 +1,344 @@
// -----------------------------------------------------------------------------
// FixIndexBuilderIntegrationTests.cs
// Sprint: SPRINT_20251226_012_BINIDX_backport_handling
// Task: BACKPORT-20 — Integration tests for fix index building
// -----------------------------------------------------------------------------
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.BinaryIndex.FixIndex.Models;
using StellaOps.BinaryIndex.FixIndex.Services;
using Xunit;
namespace StellaOps.BinaryIndex.Core.Tests.FixIndex;
/// <summary>
/// Integration tests for the FixIndexBuilder covering end-to-end scenarios.
/// </summary>
public class FixIndexBuilderIntegrationTests
{
private readonly FixIndexBuilder _sut;
private readonly Guid _testSnapshotId = Guid.NewGuid();
public FixIndexBuilderIntegrationTests()
{
_sut = new FixIndexBuilder(NullLogger<FixIndexBuilder>.Instance);
}
[Fact]
public async Task BuildDebianIndexAsync_WithChangelogAndPatches_CombinesEvidence()
{
// Arrange
var changelog = """
openssl (3.0.11-1~deb12u2) bookworm-security; urgency=high
* Fix CVE-2024-0727: PKCS12 decoding crash
* Fix CVE-2024-2511: memory leak in TLSv1.3
-- Debian Security Team <security@debian.org> Mon, 15 Jan 2024 10:00:00 +0000
""";
var patches = new List<PatchFile>
{
new()
{
Path = "debian/patches/CVE-2024-3333.patch",
Content = """
Description: Fix integer overflow
CVE: CVE-2024-3333
Origin: upstream, https://github.com/openssl/commit/abc123
--- a/src/parser.c
+++ b/src/parser.c
""",
Sha256 = "abcd1234"
}
};
var request = new DebianFixIndexRequest
{
Distro = "debian",
Release = "bookworm",
SourcePkg = "openssl",
Changelog = changelog,
Patches = patches,
Version = "3.0.11-1~deb12u2",
SnapshotId = _testSnapshotId
};
// Act
var results = new List<FixEvidence>();
await foreach (var evidence in _sut.BuildDebianIndexAsync(request))
{
results.Add(evidence);
}
// Assert
results.Should().HaveCount(3);
results.Should().Contain(e => e.CveId == "CVE-2024-0727");
results.Should().Contain(e => e.CveId == "CVE-2024-2511");
results.Should().Contain(e => e.CveId == "CVE-2024-3333");
// Patch evidence should have higher confidence
var patchEvidence = results.First(e => e.CveId == "CVE-2024-3333");
patchEvidence.Method.Should().Be(FixMethod.PatchHeader);
patchEvidence.Confidence.Should().BeGreaterThan(0.85m);
// All should reference the snapshot
results.Should().AllSatisfy(e => e.SnapshotId.Should().Be(_testSnapshotId));
}
[Fact]
public async Task BuildAlpineIndexAsync_WithSecfixes_ExtractsAllCves()
{
// Arrange
var apkbuild = """
pkgname=curl
pkgver=8.5.0
pkgrel=1
# secfixes:
# 8.5.0-r0:
# - CVE-2023-46218
# - CVE-2023-46219
# 8.4.0-r0:
# - CVE-2023-38545
# - CVE-2023-38546
build() {
./configure
}
""";
var request = new AlpineFixIndexRequest
{
Release = "v3.19",
SourcePkg = "curl",
ApkBuild = apkbuild,
SnapshotId = _testSnapshotId
};
// Act
var results = new List<FixEvidence>();
await foreach (var evidence in _sut.BuildAlpineIndexAsync(request))
{
results.Add(evidence);
}
// Assert
results.Should().HaveCount(4);
results.Should().Contain(e => e.CveId == "CVE-2023-46218" && e.FixedVersion == "8.5.0-r0");
results.Should().Contain(e => e.CveId == "CVE-2023-46219" && e.FixedVersion == "8.5.0-r0");
results.Should().Contain(e => e.CveId == "CVE-2023-38545" && e.FixedVersion == "8.4.0-r0");
results.Should().Contain(e => e.CveId == "CVE-2023-38546" && e.FixedVersion == "8.4.0-r0");
results.Should().AllSatisfy(e =>
{
e.Distro.Should().Be("alpine");
e.Release.Should().Be("v3.19");
e.Method.Should().Be(FixMethod.SecurityFeed);
e.Confidence.Should().Be(0.95m);
});
}
[Fact]
public async Task BuildRpmIndexAsync_WithMultipleChangelogEntries_ExtractsAllCves()
{
// Arrange
var specContent = """
Name: kernel
Version: 6.6.0
Release: 100.el9
%description
The Linux Kernel
%changelog
* Mon Dec 15 2024 Security <security@redhat.com> - 6.6.0-100
- Fix CVE-2024-1111: stack buffer overflow
- Fix CVE-2024-2222: use-after-free in netfilter
* Mon Nov 01 2024 Security <security@redhat.com> - 6.5.0-50
- Fix CVE-2024-3333: information disclosure
""";
var request = new RpmFixIndexRequest
{
Distro = "rhel",
Release = "9",
SourcePkg = "kernel",
SpecContent = specContent,
SnapshotId = _testSnapshotId
};
// Act
var results = new List<FixEvidence>();
await foreach (var evidence in _sut.BuildRpmIndexAsync(request))
{
results.Add(evidence);
}
// Assert
results.Should().HaveCount(3);
var v100Fixes = results.Where(e => e.FixedVersion == "6.6.0-100").ToList();
v100Fixes.Should().HaveCount(2);
v100Fixes.Should().Contain(e => e.CveId == "CVE-2024-1111");
v100Fixes.Should().Contain(e => e.CveId == "CVE-2024-2222");
var v50Fixes = results.Where(e => e.FixedVersion == "6.5.0-50").ToList();
v50Fixes.Should().HaveCount(1);
v50Fixes[0].CveId.Should().Be("CVE-2024-3333");
results.Should().AllSatisfy(e =>
{
e.Distro.Should().Be("rhel");
e.Release.Should().Be("9");
e.Method.Should().Be(FixMethod.Changelog);
e.Confidence.Should().Be(0.75m);
});
}
[Fact]
public async Task BuildDebianIndexAsync_WithEmptyInputs_ReturnsEmpty()
{
// Arrange
var request = new DebianFixIndexRequest
{
Distro = "debian",
Release = "bookworm",
SourcePkg = "empty-pkg",
Changelog = "",
Patches = [],
SnapshotId = _testSnapshotId
};
// Act
var results = new List<FixEvidence>();
await foreach (var evidence in _sut.BuildDebianIndexAsync(request))
{
results.Add(evidence);
}
// Assert
results.Should().BeEmpty();
}
[Fact]
public async Task BuildAlpineIndexAsync_WithNoSecfixes_ReturnsEmpty()
{
// Arrange
var apkbuild = """
pkgname=simple
pkgver=1.0
pkgrel=0
build() {
make
}
""";
var request = new AlpineFixIndexRequest
{
Release = "v3.19",
SourcePkg = "simple",
ApkBuild = apkbuild,
SnapshotId = _testSnapshotId
};
// Act
var results = new List<FixEvidence>();
await foreach (var evidence in _sut.BuildAlpineIndexAsync(request))
{
results.Add(evidence);
}
// Assert
results.Should().BeEmpty();
}
[Fact]
public async Task BuildRpmIndexAsync_WithNoChangelog_ReturnsEmpty()
{
// Arrange
var specContent = """
Name: simple
Version: 1.0
Release: 1
%description
A simple package
""";
var request = new RpmFixIndexRequest
{
Distro = "fedora",
Release = "39",
SourcePkg = "simple",
SpecContent = specContent,
SnapshotId = _testSnapshotId
};
// Act
var results = new List<FixEvidence>();
await foreach (var evidence in _sut.BuildRpmIndexAsync(request))
{
results.Add(evidence);
}
// Assert
results.Should().BeEmpty();
}
[Fact]
public async Task BuildDebianIndexAsync_DeduplicatesCvesFromChangelogAndPatches()
{
// Arrange - Same CVE mentioned in both changelog and patch
var changelog = """
pkg (1.0-1) stable; urgency=high
* Fix CVE-2024-5555
-- Maintainer <m@x.com> Mon, 01 Jan 2024 12:00:00 +0000
""";
var patches = new List<PatchFile>
{
new()
{
Path = "debian/patches/CVE-2024-5555.patch",
Content = """
CVE: CVE-2024-5555
--- a/foo.c
+++ b/foo.c
""",
Sha256 = "hash123"
}
};
var request = new DebianFixIndexRequest
{
Distro = "debian",
Release = "stable",
SourcePkg = "pkg",
Changelog = changelog,
Patches = patches,
Version = "1.0-1",
SnapshotId = _testSnapshotId
};
// Act
var results = new List<FixEvidence>();
await foreach (var evidence in _sut.BuildDebianIndexAsync(request))
{
results.Add(evidence);
}
// Assert - Both are returned (patch with higher confidence overrides)
// The implementation allows both but prefers patch evidence
var cve5555 = results.Where(e => e.CveId == "CVE-2024-5555").ToList();
cve5555.Should().HaveCountGreaterOrEqualTo(1);
cve5555.Should().Contain(e => e.Method == FixMethod.PatchHeader);
}
}

View File

@@ -24,6 +24,7 @@
<ItemGroup>
<ProjectReference Include="..\..\__Libraries\StellaOps.BinaryIndex.Core\StellaOps.BinaryIndex.Core.csproj" />
<ProjectReference Include="..\..\__Libraries\StellaOps.BinaryIndex.FixIndex\StellaOps.BinaryIndex.FixIndex.csproj" />
</ItemGroup>
</Project>