Add unit tests for SBOM ingestion and transformation
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Implement `SbomIngestServiceCollectionExtensionsTests` to verify the SBOM ingestion pipeline exports snapshots correctly.
- Create `SbomIngestTransformerTests` to ensure the transformation produces expected nodes and edges, including deduplication of license nodes and normalization of timestamps.
- Add `SbomSnapshotExporterTests` to test the export functionality for manifest, adjacency, nodes, and edges.
- Introduce `VexOverlayTransformerTests` to validate the transformation of VEX nodes and edges.
- Set up project file for the test project with necessary dependencies and configurations.
- Include JSON fixture files for testing purposes.
This commit is contained in:
master
2025-11-04 07:49:39 +02:00
parent f72c5c513a
commit 2eb6852d34
491 changed files with 39445 additions and 3917 deletions

View File

@@ -0,0 +1,231 @@
using System.Text.Json.Serialization;
namespace StellaOps.Graph.Indexer.Ingestion.Sbom;
public sealed class SbomSnapshot
{
[JsonPropertyName("tenant")]
public string Tenant { get; init; } = string.Empty;
[JsonPropertyName("source")]
public string Source { get; init; } = string.Empty;
[JsonPropertyName("artifactDigest")]
public string ArtifactDigest { get; init; } = string.Empty;
[JsonPropertyName("sbomDigest")]
public string SbomDigest { get; init; } = string.Empty;
[JsonPropertyName("collectedAt")]
public DateTimeOffset CollectedAt { get; init; } = DateTimeOffset.UnixEpoch;
[JsonPropertyName("eventOffset")]
public long EventOffset { get; init; }
[JsonPropertyName("artifact")]
public SbomArtifactMetadata Artifact { get; init; } = new();
[JsonPropertyName("build")]
public SbomBuildMetadata Build { get; init; } = new();
[JsonPropertyName("components")]
public IReadOnlyList<SbomComponent> Components { get; init; } = Array.Empty<SbomComponent>();
[JsonPropertyName("baseArtifacts")]
public IReadOnlyList<SbomBaseArtifact> BaseArtifacts { get; init; } = Array.Empty<SbomBaseArtifact>();
}
public sealed class SbomArtifactMetadata
{
[JsonPropertyName("displayName")]
public string DisplayName { get; init; } = string.Empty;
[JsonPropertyName("environment")]
public string Environment { get; init; } = string.Empty;
[JsonPropertyName("labels")]
public IReadOnlyList<string> Labels { get; init; } = Array.Empty<string>();
[JsonPropertyName("originRegistry")]
public string OriginRegistry { get; init; } = string.Empty;
[JsonPropertyName("supplyChainStage")]
public string SupplyChainStage { get; init; } = string.Empty;
}
public sealed class SbomBuildMetadata
{
[JsonPropertyName("builderId")]
public string BuilderId { get; init; } = string.Empty;
[JsonPropertyName("buildType")]
public string BuildType { get; init; } = string.Empty;
[JsonPropertyName("attestationDigest")]
public string AttestationDigest { get; init; } = string.Empty;
[JsonPropertyName("source")]
public string Source { get; init; } = string.Empty;
[JsonPropertyName("collectedAt")]
public DateTimeOffset CollectedAt { get; init; } = DateTimeOffset.UnixEpoch;
[JsonPropertyName("eventOffset")]
public long EventOffset { get; init; }
}
public sealed class SbomComponent
{
[JsonPropertyName("purl")]
public string Purl { get; init; } = string.Empty;
[JsonPropertyName("version")]
public string Version { get; init; } = string.Empty;
[JsonPropertyName("ecosystem")]
public string Ecosystem { get; init; } = string.Empty;
[JsonPropertyName("scope")]
public string Scope { get; init; } = string.Empty;
[JsonPropertyName("license")]
public SbomLicense License { get; init; } = new();
[JsonPropertyName("usage")]
public string Usage { get; init; } = string.Empty;
[JsonPropertyName("detectedBy")]
public string DetectedBy { get; init; } = string.Empty;
[JsonPropertyName("layerDigest")]
public string LayerDigest { get; init; } = string.Empty;
[JsonPropertyName("evidenceDigest")]
public string EvidenceDigest { get; init; } = string.Empty;
[JsonPropertyName("collectedAt")]
public DateTimeOffset CollectedAt { get; init; } = DateTimeOffset.UnixEpoch;
[JsonPropertyName("eventOffset")]
public long EventOffset { get; init; }
[JsonPropertyName("source")]
public string Source { get; init; } = string.Empty;
[JsonPropertyName("files")]
public IReadOnlyList<SbomComponentFile> Files { get; init; } = Array.Empty<SbomComponentFile>();
[JsonPropertyName("dependencies")]
public IReadOnlyList<SbomDependency> Dependencies { get; init; } = Array.Empty<SbomDependency>();
[JsonPropertyName("sourceType")]
public string SourceType { get; init; } = "inventory";
}
public sealed class SbomLicense
{
[JsonPropertyName("spdx")]
public string Spdx { get; init; } = string.Empty;
[JsonPropertyName("name")]
public string Name { get; init; } = string.Empty;
[JsonPropertyName("classification")]
public string Classification { get; init; } = string.Empty;
[JsonPropertyName("noticeUri")]
public string? NoticeUri { get; init; }
[JsonPropertyName("sourceDigest")]
public string SourceDigest { get; init; } = string.Empty;
}
public sealed class SbomComponentFile
{
[JsonPropertyName("path")]
public string Path { get; init; } = string.Empty;
[JsonPropertyName("contentSha256")]
public string ContentSha256 { get; init; } = string.Empty;
[JsonPropertyName("languageHint")]
public string LanguageHint { get; init; } = string.Empty;
[JsonPropertyName("sizeBytes")]
public long SizeBytes { get; init; }
[JsonPropertyName("scope")]
public string Scope { get; init; } = string.Empty;
[JsonPropertyName("detectedBy")]
public string DetectedBy { get; init; } = string.Empty;
[JsonPropertyName("evidenceDigest")]
public string EvidenceDigest { get; init; } = string.Empty;
[JsonPropertyName("collectedAt")]
public DateTimeOffset CollectedAt { get; init; } = DateTimeOffset.UnixEpoch;
[JsonPropertyName("eventOffset")]
public long EventOffset { get; init; }
[JsonPropertyName("source")]
public string Source { get; init; } = string.Empty;
}
public sealed class SbomDependency
{
[JsonPropertyName("purl")]
public string Purl { get; init; } = string.Empty;
[JsonPropertyName("version")]
public string Version { get; init; } = string.Empty;
[JsonPropertyName("relationship")]
public string Relationship { get; init; } = string.Empty;
[JsonPropertyName("evidenceDigest")]
public string EvidenceDigest { get; init; } = string.Empty;
[JsonPropertyName("collectedAt")]
public DateTimeOffset CollectedAt { get; init; } = DateTimeOffset.UnixEpoch;
[JsonPropertyName("eventOffset")]
public long EventOffset { get; init; }
[JsonPropertyName("source")]
public string Source { get; init; } = string.Empty;
}
public sealed class SbomBaseArtifact
{
[JsonPropertyName("artifactDigest")]
public string ArtifactDigest { get; init; } = string.Empty;
[JsonPropertyName("sbomDigest")]
public string SbomDigest { get; init; } = string.Empty;
[JsonPropertyName("displayName")]
public string DisplayName { get; init; } = string.Empty;
[JsonPropertyName("environment")]
public string Environment { get; init; } = string.Empty;
[JsonPropertyName("labels")]
public IReadOnlyList<string> Labels { get; init; } = Array.Empty<string>();
[JsonPropertyName("originRegistry")]
public string OriginRegistry { get; init; } = string.Empty;
[JsonPropertyName("supplyChainStage")]
public string SupplyChainStage { get; init; } = string.Empty;
[JsonPropertyName("collectedAt")]
public DateTimeOffset CollectedAt { get; init; } = DateTimeOffset.UnixEpoch;
[JsonPropertyName("eventOffset")]
public long EventOffset { get; init; }
[JsonPropertyName("source")]
public string Source { get; init; } = string.Empty;
}