using System.Reflection; namespace StellaOps.BinaryIndex.GroundTruth.SecDb.Tests.Fixtures; /// /// Provides access to deterministic test fixtures for offline testing. /// public static class FixtureProvider { private static readonly string FixturesPath; static FixtureProvider() { var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!; FixturesPath = Path.Combine(assemblyDir, "Fixtures"); // Also try the source directory for development if (!Directory.Exists(FixturesPath)) { var sourceDir = FindSourceFixturesDirectory(); if (sourceDir is not null) { FixturesPath = sourceDir; } } } /// /// Get sample SecDB YAML content for main repository. /// public static string GetSampleSecDbMain() { var path = Path.Combine(FixturesPath, "main.yaml"); if (!File.Exists(path)) { // Return inline fixture if file doesn't exist return SampleSecDbMainContent; } return File.ReadAllText(path); } /// /// Get sample SecDB YAML content for community repository. /// public static string GetSampleSecDbCommunity() { var path = Path.Combine(FixturesPath, "community.yaml"); if (!File.Exists(path)) { return SampleSecDbCommunityContent; } return File.ReadAllText(path); } /// /// Get a fixture file as a stream. /// public static Stream GetFixtureStream(string name) { var path = Path.Combine(FixturesPath, name); if (!File.Exists(path)) { throw new FileNotFoundException($"Fixture not found: {path}"); } return File.OpenRead(path); } /// /// Check if a fixture exists. /// public static bool FixtureExists(string name) { var path = Path.Combine(FixturesPath, name); return File.Exists(path); } private static string? FindSourceFixturesDirectory() { var dir = Directory.GetCurrentDirectory(); while (dir is not null) { var candidate = Path.Combine(dir, "src", "BinaryIndex", "__Tests", "StellaOps.BinaryIndex.GroundTruth.SecDb.Tests", "Fixtures"); if (Directory.Exists(candidate)) { return candidate; } dir = Directory.GetParent(dir)?.FullName; } return null; } /// /// Inline sample SecDB main.yaml content for deterministic testing. /// Based on Alpine SecDB format. /// private const string SampleSecDbMainContent = """ distroversion: v3.19 reponame: main urlprefix: https://dl-cdn.alpinelinux.org/alpine/v3.19/main packages: - pkg: curl secfixes: 8.5.0-r0: - CVE-2023-46218 Improper validation of HTTP headers - CVE-2023-46219 Double free in async URL resolver 8.4.0-r0: - CVE-2023-38545 SOCKS5 heap buffer overflow 8.1.2-r0: - CVE-2023-27535 FTP injection vulnerability - pkg: openssl secfixes: 3.1.4-r3: - CVE-2024-0727 PKCS12 decoding crash 3.1.4-r0: - CVE-2023-5678 Denial of service 3.1.2-r0: - CVE-2023-3817 Excessive time checking DH parameters - pkg: linux-lts secfixes: 6.1.67-r0: - CVE-2023-6817 Use-after-free in netfilter - CVE-2023-6606 Out-of-bounds read in SMB 6.1.64-r0: - CVE-2023-5717 User-mode root exploit via perf """; /// /// Inline sample SecDB community.yaml content. /// private const string SampleSecDbCommunityContent = """ distroversion: v3.19 reponame: community urlprefix: https://dl-cdn.alpinelinux.org/alpine/v3.19/community packages: - pkg: go secfixes: 1.21.5-r0: - CVE-2023-45283 Path traversal on Windows - CVE-2023-45284 Runtime panic in crypto/tls 1.21.4-r0: - CVE-2023-44487 HTTP/2 rapid reset attack - pkg: nodejs secfixes: 20.10.0-r0: - CVE-2023-46809 Permissions policy bypass 20.9.0-r0: - CVE-2023-38552 Integrity bypass via TLS/HTTPS - pkg: chromium secfixes: 120.0.6099.71-r0: - CVE-2023-6702 Type confusion in V8 119.0.6045.199-r0: - CVE-2023-6345 Integer overflow in Skia - pkg: unfixed-example secfixes: "0": - CVE-2023-99999 Example unfixed vulnerability """; } /// /// Test fixture constants for SecDB tests. /// public static class FixtureConstants { // Sample package info public const string SamplePackageCurl = "curl"; public const string SamplePackageOpenssl = "openssl"; public const string SamplePackageGo = "go"; public const string SamplePackageNodejs = "nodejs"; // Sample branches public const string SampleBranchV319 = "v3.19"; public const string SampleBranchEdge = "edge"; // Sample repositories public const string SampleRepoMain = "main"; public const string SampleRepoCommunity = "community"; // Expected CVE counts public const int ExpectedCurlCveCount = 4; public const int ExpectedOpensslCveCount = 3; // Sample CVEs public const string SampleCveCurl = "CVE-2023-46218"; public const string SampleCveOpenssl = "CVE-2024-0727"; public const string SampleCveUnfixed = "CVE-2023-99999"; }