149 lines
4.3 KiB
C#
149 lines
4.3 KiB
C#
using System.Collections.Immutable;
|
|
using StellaOps.Concelier.SbomIntegration.Models;
|
|
using StellaOps.Scanner.BuildProvenance.Models;
|
|
|
|
namespace StellaOps.Scanner.BuildProvenance.Analyzers;
|
|
|
|
public sealed class BuildProvenanceChainBuilder
|
|
{
|
|
private static readonly string[] BuilderIdKeys =
|
|
{
|
|
"builderId",
|
|
"builder",
|
|
"builder_id",
|
|
"buildService",
|
|
"build.service"
|
|
};
|
|
|
|
private static readonly string[] SourceRepoKeys =
|
|
{
|
|
"sourceRepository",
|
|
"sourceRepo",
|
|
"repository",
|
|
"repo",
|
|
"gitUrl",
|
|
"git.url"
|
|
};
|
|
|
|
private static readonly string[] SourceCommitKeys =
|
|
{
|
|
"sourceCommit",
|
|
"commit",
|
|
"gitCommit",
|
|
"git.commit",
|
|
"revision"
|
|
};
|
|
|
|
public BuildProvenanceChain Build(ParsedSbom sbom)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(sbom);
|
|
|
|
var buildInfo = sbom.BuildInfo;
|
|
var formulation = sbom.Formulation;
|
|
var environment = buildInfo?.Environment ?? ImmutableDictionary<string, string>.Empty;
|
|
|
|
var builderId = FindParameter(buildInfo, BuilderIdKeys)
|
|
?? buildInfo?.BuildType;
|
|
var sourceRepo = FindParameter(buildInfo, SourceRepoKeys);
|
|
var sourceCommit = FindParameter(buildInfo, SourceCommitKeys);
|
|
|
|
var configUri = buildInfo?.ConfigSourceUri ?? buildInfo?.ConfigSourceEntrypoint;
|
|
var configDigest = buildInfo?.ConfigSourceDigest;
|
|
|
|
var inputs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
var outputs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
if (formulation is not null)
|
|
{
|
|
foreach (var component in formulation.Components)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(component.BomRef))
|
|
{
|
|
inputs.Add(component.BomRef!);
|
|
}
|
|
|
|
foreach (var reference in component.ComponentRefs)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(reference))
|
|
{
|
|
inputs.Add(reference);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var workflow in formulation.Workflows)
|
|
{
|
|
foreach (var input in workflow.InputRefs)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(input))
|
|
{
|
|
inputs.Add(input);
|
|
}
|
|
}
|
|
|
|
foreach (var output in workflow.OutputRefs)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(output))
|
|
{
|
|
outputs.Add(output);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var task in formulation.Tasks)
|
|
{
|
|
foreach (var input in task.InputRefs)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(input))
|
|
{
|
|
inputs.Add(input);
|
|
}
|
|
}
|
|
|
|
foreach (var output in task.OutputRefs)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(output))
|
|
{
|
|
outputs.Add(output);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return new BuildProvenanceChain
|
|
{
|
|
BuilderId = builderId,
|
|
SourceRepository = sourceRepo,
|
|
SourceCommit = sourceCommit,
|
|
BuildConfigUri = configUri,
|
|
BuildConfigDigest = configDigest,
|
|
Environment = environment,
|
|
Inputs = inputs.Select(reference => new BuildInput { Reference = reference }).ToImmutableArray(),
|
|
Outputs = outputs.Select(reference => new BuildOutput { Reference = reference }).ToImmutableArray()
|
|
};
|
|
}
|
|
|
|
private static string? FindParameter(ParsedBuildInfo? buildInfo, IEnumerable<string> keys)
|
|
{
|
|
if (buildInfo?.Parameters is null || buildInfo.Parameters.IsEmpty)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
foreach (var key in keys)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(key))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (buildInfo.Parameters.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return value.Trim();
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|