using System.Collections.Generic; using System.Collections.Immutable; using StellaOps.Scanner.Analyzers.OS.Mapping; using StellaOps.Scanner.Core.Contracts; using Xunit; namespace StellaOps.Scanner.Analyzers.OS.Tests.Mapping; public class OsComponentMapperTests { [Fact] public void ToLayerFragments_ProducesDeterministicComponents() { var package = new OSPackageRecord( analyzerId: "apk", packageUrl: "pkg:alpine/busybox@1.37.0-r0?arch=x86_64", name: "busybox", version: "1.37.0", architecture: "x86_64", evidenceSource: PackageEvidenceSource.ApkDatabase, release: "r0", sourcePackage: "busybox", license: "GPL-2.0-only", depends: new[] { "musl>=1.2.5-r0", "ssl_client" }, files: new[] { new OSPackageFileEvidence("/bin/busybox", sha256: "abc123", isConfigFile: false), new OSPackageFileEvidence("/etc/profile", isConfigFile: true, digests: new Dictionary { ["md5"] = "deadbeef" }), }, vendorMetadata: new Dictionary { ["homepage"] = "https://busybox.net/", }); var result = new OSPackageAnalyzerResult( analyzerId: "apk", packages: ImmutableArray.Create(package), telemetry: new OSAnalyzerTelemetry(System.TimeSpan.Zero, 1, 2)); var fragments = OsComponentMapper.ToLayerFragments(new[] { result }); Assert.Single(fragments); var fragment = fragments[0]; Assert.StartsWith("sha256:", fragment.LayerDigest); Assert.Single(fragment.Components); var component = fragment.Components[0]; Assert.Equal(fragment.LayerDigest, component.LayerDigest); Assert.Equal("pkg:alpine/busybox@1.37.0-r0?arch=x86_64", component.Identity.Key); Assert.Equal("busybox", component.Identity.Name); Assert.Equal("1.37.0", component.Identity.Version); Assert.Equal("pkg:alpine/busybox@1.37.0-r0?arch=x86_64", component.Identity.Purl); Assert.Equal("os-package", component.Identity.ComponentType); Assert.Equal("busybox", component.Identity.Group); Assert.Collection(component.Evidence, evidence => { Assert.Equal("file", evidence.Kind); Assert.Equal("/bin/busybox", evidence.Value); Assert.Equal("abc123", evidence.Source); }, evidence => { Assert.Equal("config-file", evidence.Kind); Assert.Equal("/etc/profile", evidence.Value); Assert.Null(evidence.Source); }); Assert.Equal(new[] { "musl>=1.2.5-r0", "ssl_client" }, component.Dependencies); Assert.False(component.Usage.UsedByEntrypoint); Assert.NotNull(component.Metadata); Assert.Equal(new[] { "GPL-2.0-only" }, component.Metadata!.Licenses); Assert.Contains("stellaops.os.analyzer", component.Metadata.Properties!.Keys); Assert.Equal("apk", component.Metadata.Properties!["stellaops.os.analyzer"]); Assert.Equal("https://busybox.net/", component.Metadata.Properties!["vendor.homepage"]); } }