up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-01 21:16:22 +02:00
parent c11d87d252
commit 909d9b6220
208 changed files with 860954 additions and 832 deletions

View File

@@ -35,14 +35,14 @@ public sealed class CycloneDxComposer
var graph = ComponentGraphBuilder.Build(request.LayerFragments);
var generatedAt = ScannerTimestamps.Normalize(request.GeneratedAt);
var inventoryArtifact = BuildArtifact(
request,
graph,
SbomView.Inventory,
graph.Components,
generatedAt,
InventoryMediaTypeJson,
InventoryMediaTypeProtobuf);
var inventoryArtifact = BuildArtifact(
request,
graph,
SbomView.Inventory,
graph.Components,
generatedAt,
InventoryMediaTypeJson,
InventoryMediaTypeProtobuf);
var usageComponents = graph.Components
.Where(static component => component.Usage.UsedByEntrypoint)
@@ -51,14 +51,14 @@ public sealed class CycloneDxComposer
CycloneDxArtifact? usageArtifact = null;
if (!usageComponents.IsEmpty)
{
usageArtifact = BuildArtifact(
request,
graph,
SbomView.Usage,
usageComponents,
generatedAt,
UsageMediaTypeJson,
UsageMediaTypeProtobuf);
usageArtifact = BuildArtifact(
request,
graph,
SbomView.Usage,
usageComponents,
generatedAt,
UsageMediaTypeJson,
UsageMediaTypeProtobuf);
}
return new SbomCompositionResult
@@ -69,37 +69,47 @@ public sealed class CycloneDxComposer
};
}
private CycloneDxArtifact BuildArtifact(
SbomCompositionRequest request,
ComponentGraph graph,
SbomView view,
ImmutableArray<AggregatedComponent> components,
DateTimeOffset generatedAt,
string jsonMediaType,
string protobufMediaType)
{
private CycloneDxArtifact BuildArtifact(
SbomCompositionRequest request,
ComponentGraph graph,
SbomView view,
ImmutableArray<AggregatedComponent> components,
DateTimeOffset generatedAt,
string jsonMediaType,
string protobufMediaType)
{
var bom = BuildBom(request, graph, view, components, generatedAt);
var json = JsonSerializer.Serialize(bom);
var jsonBytes = Encoding.UTF8.GetBytes(json);
var protobufBytes = ProtoSerializer.Serialize(bom);
var json = JsonSerializer.Serialize(bom);
var jsonBytes = Encoding.UTF8.GetBytes(json);
var protobufBytes = ProtoSerializer.Serialize(bom);
var jsonHash = ComputeSha256(jsonBytes);
var protobufHash = ComputeSha256(protobufBytes);
var merkleRoot = request.AdditionalProperties is not null
&& request.AdditionalProperties.TryGetValue("stellaops:merkle.root", out var root)
? root
: null;
request.AdditionalProperties?.TryGetValue("stellaops:composition.manifest", out var compositionUri);
var jsonHash = ComputeSha256(jsonBytes);
var protobufHash = ComputeSha256(protobufBytes);
return new CycloneDxArtifact
{
View = view,
SerialNumber = bom.SerialNumber ?? string.Empty,
GeneratedAt = generatedAt,
Components = components,
JsonBytes = jsonBytes,
JsonSha256 = jsonHash,
JsonMediaType = jsonMediaType,
ProtobufBytes = protobufBytes,
ProtobufSha256 = protobufHash,
ProtobufMediaType = protobufMediaType,
};
}
return new CycloneDxArtifact
{
View = view,
SerialNumber = bom.SerialNumber ?? string.Empty,
GeneratedAt = generatedAt,
Components = components,
JsonBytes = jsonBytes,
JsonSha256 = jsonHash,
ContentHash = jsonHash,
MerkleRoot = merkleRoot,
CompositionUri = compositionUri,
JsonMediaType = jsonMediaType,
ProtobufBytes = protobufBytes,
ProtobufSha256 = protobufHash,
ProtobufMediaType = protobufMediaType,
};
}
private Bom BuildBom(
SbomCompositionRequest request,

View File

@@ -4,25 +4,40 @@ using StellaOps.Scanner.Core.Contracts;
namespace StellaOps.Scanner.Emit.Composition;
public sealed record CycloneDxArtifact
{
public required SbomView View { get; init; }
public required string SerialNumber { get; init; }
public sealed record CycloneDxArtifact
{
public required SbomView View { get; init; }
public required string SerialNumber { get; init; }
public required DateTimeOffset GeneratedAt { get; init; }
public required ImmutableArray<AggregatedComponent> Components { get; init; }
public required byte[] JsonBytes { get; init; }
public required string JsonSha256 { get; init; }
public required string JsonMediaType { get; init; }
public required byte[] ProtobufBytes { get; init; }
public required string ProtobufSha256 { get; init; }
public required byte[] JsonBytes { get; init; }
public required string JsonSha256 { get; init; }
/// <summary>
/// Canonical content hash (sha256, hex) of the CycloneDX JSON payload.
/// </summary>
public required string ContentHash { get; init; }
/// <summary>
/// Merkle root over fragments (hex). Present when composition metadata is provided.
/// </summary>
public string? MerkleRoot { get; init; }
/// <summary>
/// CAS URI of the composition recipe (_composition.json) if emitted.
/// </summary>
public string? CompositionUri { get; init; }
public required string JsonMediaType { get; init; }
public required byte[] ProtobufBytes { get; init; }
public required string ProtobufSha256 { get; init; }
public required string ProtobufMediaType { get; init; }
}