Add comprehensive tests for Go and Python version conflict detection and licensing normalization

- Implemented GoVersionConflictDetectorTests to validate pseudo-version detection, conflict analysis, and conflict retrieval for Go modules.
- Created VersionConflictDetectorTests for Python to assess conflict detection across various version scenarios, including major, minor, and patch differences.
- Added SpdxLicenseNormalizerTests to ensure accurate normalization of SPDX license strings and classifiers.
- Developed VendoredPackageDetectorTests to identify vendored packages and extract embedded packages from Python packages, including handling of vendor directories and known vendored packages.
This commit is contained in:
StellaOps Bot
2025-12-07 01:51:37 +02:00
parent 98934170ca
commit e0f6efecce
66 changed files with 7591 additions and 451 deletions

View File

@@ -321,4 +321,106 @@ public class ElfDynamicSectionParserTests
buffer[offset + bytes.Length] = 0; // null terminator
return bytes.Length;
}
[Fact]
public void ParsesElfWithVersionNeeds()
{
// Test that version needs (GLIBC_2.17, etc.) are properly extracted
var buffer = new byte[4096];
SetupElf64Header(buffer, littleEndian: true);
// String table at offset 0x400
var strtab = 0x400;
var libcOffset = 1; // "libc.so.6"
var glibc217Offset = libcOffset + WriteString(buffer, strtab + libcOffset, "libc.so.6") + 1;
var glibc228Offset = glibc217Offset + WriteString(buffer, strtab + glibc217Offset, "GLIBC_2.17") + 1;
var strtabSize = glibc228Offset + WriteString(buffer, strtab + glibc228Offset, "GLIBC_2.28") + 1;
// Section headers at offset 0x800
var shoff = 0x800;
var shentsize = 64;
var shnum = 3; // null + .dynstr + .gnu.version_r
BitConverter.GetBytes((ulong)shoff).CopyTo(buffer, 40);
BitConverter.GetBytes((ushort)shentsize).CopyTo(buffer, 58);
BitConverter.GetBytes((ushort)shnum).CopyTo(buffer, 60);
// Section header 0: null
// Section header 1: .dynstr
var sh1 = shoff + shentsize;
BitConverter.GetBytes((uint)3).CopyTo(buffer, sh1 + 4); // sh_type = SHT_STRTAB
BitConverter.GetBytes((ulong)0x400).CopyTo(buffer, sh1 + 16); // sh_addr
BitConverter.GetBytes((ulong)strtab).CopyTo(buffer, sh1 + 24); // sh_offset
BitConverter.GetBytes((ulong)strtabSize).CopyTo(buffer, sh1 + 32); // sh_size
// Section header 2: .gnu.version_r (SHT_GNU_verneed = 0x6ffffffe)
var verneedFileOffset = 0x600;
var sh2 = shoff + shentsize * 2;
BitConverter.GetBytes((uint)0x6ffffffe).CopyTo(buffer, sh2 + 4); // sh_type = SHT_GNU_verneed
BitConverter.GetBytes((ulong)0x600).CopyTo(buffer, sh2 + 16); // sh_addr (vaddr)
BitConverter.GetBytes((ulong)verneedFileOffset).CopyTo(buffer, sh2 + 24); // sh_offset
// Version needs section at offset 0x600
// Verneed entry for libc.so.6 with two version requirements
// Elf64_Verneed: vn_version(2), vn_cnt(2), vn_file(4), vn_aux(4), vn_next(4)
var verneedOffset = verneedFileOffset;
BitConverter.GetBytes((ushort)1).CopyTo(buffer, verneedOffset); // vn_version = 1
BitConverter.GetBytes((ushort)2).CopyTo(buffer, verneedOffset + 2); // vn_cnt = 2 aux entries
BitConverter.GetBytes((uint)libcOffset).CopyTo(buffer, verneedOffset + 4); // vn_file -> "libc.so.6"
BitConverter.GetBytes((uint)16).CopyTo(buffer, verneedOffset + 8); // vn_aux = 16 (offset to first aux)
BitConverter.GetBytes((uint)0).CopyTo(buffer, verneedOffset + 12); // vn_next = 0 (last entry)
// Vernaux entries
// Elf64_Vernaux: vna_hash(4), vna_flags(2), vna_other(2), vna_name(4), vna_next(4)
var aux1Offset = verneedOffset + 16;
BitConverter.GetBytes((uint)0x0d696910).CopyTo(buffer, aux1Offset); // vna_hash for GLIBC_2.17
BitConverter.GetBytes((ushort)0).CopyTo(buffer, aux1Offset + 4); // vna_flags
BitConverter.GetBytes((ushort)2).CopyTo(buffer, aux1Offset + 6); // vna_other
BitConverter.GetBytes((uint)glibc217Offset).CopyTo(buffer, aux1Offset + 8); // vna_name -> "GLIBC_2.17"
BitConverter.GetBytes((uint)16).CopyTo(buffer, aux1Offset + 12); // vna_next = 16 (offset to next aux)
var aux2Offset = aux1Offset + 16;
BitConverter.GetBytes((uint)0x09691974).CopyTo(buffer, aux2Offset); // vna_hash for GLIBC_2.28
BitConverter.GetBytes((ushort)0).CopyTo(buffer, aux2Offset + 4);
BitConverter.GetBytes((ushort)3).CopyTo(buffer, aux2Offset + 6);
BitConverter.GetBytes((uint)glibc228Offset).CopyTo(buffer, aux2Offset + 8); // vna_name -> "GLIBC_2.28"
BitConverter.GetBytes((uint)0).CopyTo(buffer, aux2Offset + 12); // vna_next = 0 (last aux)
// Dynamic section at offset 0x200
var dynOffset = 0x200;
var dynEntrySize = 16;
var dynIndex = 0;
WriteDynEntry64(buffer, dynOffset + dynEntrySize * dynIndex++, 5, 0x400); // DT_STRTAB
WriteDynEntry64(buffer, dynOffset + dynEntrySize * dynIndex++, 10, (ulong)strtabSize); // DT_STRSZ
WriteDynEntry64(buffer, dynOffset + dynEntrySize * dynIndex++, 1, (ulong)libcOffset); // DT_NEEDED -> libc.so.6
WriteDynEntry64(buffer, dynOffset + dynEntrySize * dynIndex++, 0x6ffffffe, 0x600); // DT_VERNEED (vaddr)
WriteDynEntry64(buffer, dynOffset + dynEntrySize * dynIndex++, 0x6fffffff, 1); // DT_VERNEEDNUM = 1
WriteDynEntry64(buffer, dynOffset + dynEntrySize * dynIndex, 0, 0); // DT_NULL
var dynSize = dynEntrySize * (dynIndex + 1);
// Program header
var phoff = 0x40;
var phentsize = 56;
var phnum = 1;
BitConverter.GetBytes((ulong)phoff).CopyTo(buffer, 32);
BitConverter.GetBytes((ushort)phentsize).CopyTo(buffer, 54);
BitConverter.GetBytes((ushort)phnum).CopyTo(buffer, 56);
BitConverter.GetBytes((uint)2).CopyTo(buffer, phoff); // PT_DYNAMIC
BitConverter.GetBytes((ulong)dynOffset).CopyTo(buffer, phoff + 8);
BitConverter.GetBytes((ulong)dynSize).CopyTo(buffer, phoff + 32);
using var stream = new MemoryStream(buffer);
var result = ElfDynamicSectionParser.TryParse(stream, out var info);
result.Should().BeTrue();
info.Dependencies.Should().HaveCount(1);
info.Dependencies[0].Soname.Should().Be("libc.so.6");
info.Dependencies[0].VersionNeeds.Should().HaveCount(2);
info.Dependencies[0].VersionNeeds.Should().Contain(v => v.Version == "GLIBC_2.17");
info.Dependencies[0].VersionNeeds.Should().Contain(v => v.Version == "GLIBC_2.28");
}
}