save progress
This commit is contained in:
@@ -2,8 +2,10 @@
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Canonical.Json;
|
||||
using StellaOps.Scanner.Core.Contracts;
|
||||
using StellaOps.Scanner.Emit.Composition;
|
||||
using StellaOps.Scanner.Emit.Spdx;
|
||||
using StellaOps.Scanner.WebService.Domain;
|
||||
@@ -102,8 +104,8 @@ public sealed class SbomExportService : ISbomExportService
|
||||
artifact.JsonBytes,
|
||||
SbomExportFormat.Spdx3,
|
||||
profile,
|
||||
artifact.JsonDigest,
|
||||
artifact.ComponentCount));
|
||||
artifact.JsonSha256,
|
||||
0)); // ComponentCount not available on SpdxArtifact
|
||||
}
|
||||
|
||||
private async Task<SbomExportResult> ExportSpdx2Async(
|
||||
@@ -177,25 +179,73 @@ public sealed class SbomExportService : ISbomExportService
|
||||
ScanSnapshot snapshot,
|
||||
IReadOnlyList<SbomLayerFragment> layerFragments)
|
||||
{
|
||||
// Convert SbomLayerFragment to the format expected by SpdxComposer
|
||||
var fragments = layerFragments.Select(f => new Scanner.Core.Contracts.LayerSbomFragment
|
||||
// Convert SbomLayerFragment to LayerComponentFragment for SpdxComposer
|
||||
var fragments = layerFragments.Select(f => new LayerComponentFragment
|
||||
{
|
||||
LayerDigest = f.LayerDigest,
|
||||
Order = f.Order,
|
||||
ComponentPurls = f.ComponentPurls.ToList()
|
||||
}).ToList();
|
||||
Components = f.ComponentPurls
|
||||
.Select(purl => new ComponentRecord
|
||||
{
|
||||
Identity = ComponentIdentity.Create(
|
||||
key: purl,
|
||||
name: ExtractNameFromPurl(purl),
|
||||
version: ExtractVersionFromPurl(purl),
|
||||
purl: purl),
|
||||
LayerDigest = f.LayerDigest
|
||||
})
|
||||
.ToImmutableArray()
|
||||
}).ToImmutableArray();
|
||||
|
||||
return new SbomCompositionRequest
|
||||
var image = new ImageArtifactDescriptor
|
||||
{
|
||||
Image = new Scanner.Core.Contracts.ImageReference
|
||||
{
|
||||
ImageDigest = snapshot.Target.Digest ?? string.Empty,
|
||||
ImageRef = snapshot.Target.Reference ?? string.Empty
|
||||
},
|
||||
LayerFragments = fragments,
|
||||
GeneratedAt = _timeProvider.GetUtcNow(),
|
||||
GeneratorVersion = "StellaOps-Scanner/1.0"
|
||||
ImageDigest = snapshot.Target.Digest ?? string.Empty,
|
||||
ImageReference = snapshot.Target.Reference
|
||||
};
|
||||
|
||||
return SbomCompositionRequest.Create(
|
||||
image,
|
||||
fragments,
|
||||
_timeProvider.GetUtcNow(),
|
||||
generatorName: "StellaOps-Scanner",
|
||||
generatorVersion: "1.0");
|
||||
}
|
||||
|
||||
private static string ExtractNameFromPurl(string purl)
|
||||
{
|
||||
// Basic PURL parsing: pkg:type/namespace/name@version
|
||||
// Returns the name portion
|
||||
try
|
||||
{
|
||||
var withoutScheme = purl.StartsWith("pkg:", StringComparison.OrdinalIgnoreCase)
|
||||
? purl[4..]
|
||||
: purl;
|
||||
var atIndex = withoutScheme.IndexOf('@');
|
||||
var pathPart = atIndex >= 0 ? withoutScheme[..atIndex] : withoutScheme;
|
||||
var slashIndex = pathPart.LastIndexOf('/');
|
||||
return slashIndex >= 0 ? pathPart[(slashIndex + 1)..] : pathPart;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return purl;
|
||||
}
|
||||
}
|
||||
|
||||
private static string? ExtractVersionFromPurl(string purl)
|
||||
{
|
||||
// Basic PURL parsing: pkg:type/namespace/name@version
|
||||
// Returns the version portion
|
||||
try
|
||||
{
|
||||
var atIndex = purl.IndexOf('@');
|
||||
if (atIndex < 0) return null;
|
||||
var versionPart = purl[(atIndex + 1)..];
|
||||
var queryIndex = versionPart.IndexOf('?');
|
||||
return queryIndex >= 0 ? versionPart[..queryIndex] : versionPart;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static int EstimateComponentCount(byte[] sbomBytes)
|
||||
|
||||
Reference in New Issue
Block a user