Skip to content

Commit d6b3d56

Browse files
authored
Merge branch 'main' into copilot/fix-1040
2 parents e4896c8 + aea1c1f commit d6b3d56

25 files changed

Lines changed: 904 additions & 145 deletions

File tree

src/Microsoft.Sbom.Api/Executors/FileHasher.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public FileHasher(
9090
var output = Channel.CreateUnbounded<InternalSbomFileInfo>();
9191
var errors = Channel.CreateUnbounded<FileValidationResult>();
9292

93+
#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits
9394
Task.Run(async () =>
9495
{
9596
await foreach (var file in fileInfo.ReadAllAsync())
@@ -99,7 +100,8 @@ public FileHasher(
99100

100101
output.Writer.Complete();
101102
errors.Writer.Complete();
102-
});
103+
}).ConfigureAwait(false).GetAwaiter().GetResult();
104+
#pragma warning restore VSTHRD002 // Avoid problematic synchronous waits
103105

104106
return (output, errors);
105107
}

src/Microsoft.Sbom.Api/Executors/PackageInfoJsonWriter.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ namespace Microsoft.Sbom.Api.Executors;
1919
/// </summary>
2020
public class PackageInfoJsonWriter
2121
{
22-
private readonly ManifestGeneratorProvider manifestGeneratorProvider;
22+
private readonly IManifestGeneratorProvider manifestGeneratorProvider;
2323
private readonly ILogger log;
2424

2525
public PackageInfoJsonWriter(
26-
ManifestGeneratorProvider manifestGeneratorProvider,
26+
IManifestGeneratorProvider manifestGeneratorProvider,
2727
ILogger log)
2828
{
2929
if (manifestGeneratorProvider is null)
@@ -54,7 +54,7 @@ public PackageInfoJsonWriter(
5454
return (result, errors);
5555
}
5656

57-
private async Task GenerateJson(
57+
internal async Task GenerateJson(
5858
IList<ISbomConfig> packagesArraySupportingConfigs,
5959
SbomPackage packageInfo,
6060
Channel<JsonDocWithSerializer> result,
@@ -67,14 +67,22 @@ private async Task GenerateJson(
6767
var generationResult =
6868
manifestGeneratorProvider.Get(sbomConfig.ManifestInfo).GenerateJsonDocument(packageInfo);
6969

70+
var recordedAnyDependencies = false;
71+
7072
if (generationResult?.ResultMetadata?.DependOn != null)
7173
{
7274
foreach (var dependency in generationResult?.ResultMetadata?.DependOn)
7375
{
7476
sbomConfig.Recorder.RecordPackageId(generationResult?.ResultMetadata?.EntityId, dependency);
77+
recordedAnyDependencies = true;
7578
}
7679
}
7780

81+
if (!recordedAnyDependencies)
82+
{
83+
sbomConfig.Recorder.RecordPackageId(generationResult?.ResultMetadata?.EntityId, null);
84+
}
85+
7886
await result.Writer.WriteAsync((generationResult?.Document, sbomConfig.JsonSerializer));
7987
}
8088
}

src/Microsoft.Sbom.Api/Hashing/Algorithms/Sha1HashAlgorithm.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ namespace Microsoft.Sbom.Api.Hashing.Algorithms;
1212
#pragma warning disable CA5350 // Suppress Do Not Use Weak Cryptographic Algorithms as we use SHA1 intentionally
1313
public class Sha1HashAlgorithm : IHashAlgorithm
1414
{
15-
public byte[] ComputeHash(Stream stream) => SHA1.Create().ComputeHash(stream);
15+
public byte[] ComputeHash(Stream stream) => SHA1.Create().ComputeHash(stream); // CodeQL [SM02196] Sha1 is required per the SPDX spec.
1616
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Collections.Generic;
5+
using Microsoft.Sbom.Extensions;
6+
using Microsoft.Sbom.Extensions.Entities;
7+
8+
namespace Microsoft.Sbom.Api.Manifest;
9+
10+
public interface IManifestGeneratorProvider
11+
{
12+
public IManifestGenerator Get(ManifestInfo manifestInfo);
13+
14+
public IEnumerable<ManifestInfo> GetSupportedManifestInfos();
15+
16+
public ManifestGeneratorProvider Init();
17+
}

src/Microsoft.Sbom.Api/Manifest/ManifestGeneratorProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Microsoft.Sbom.Api.Manifest;
1313
/// Factory class that returns the correct implementation of the <see cref="IManifestGenerator"/>
1414
/// at runtime based on the 'ManifestInfo' parameter.
1515
/// </summary>
16-
public class ManifestGeneratorProvider
16+
public class ManifestGeneratorProvider : IManifestGeneratorProvider
1717
{
1818
private readonly IEnumerable<IManifestGenerator> manifestGenerators;
1919
private readonly IDictionary<string, IManifestGenerator> manifestMap = new Dictionary<string, IManifestGenerator>(StringComparer.OrdinalIgnoreCase);

src/Microsoft.Sbom.Api/Providers/FilesProviders/CGScannedExternalDocumentReferenceFileProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public CGScannedExternalDocumentReferenceFileProvider(
5151

5252
public override bool IsSupported(ProviderType providerType)
5353
{
54-
if (providerType == ProviderType.Files)
54+
if (providerType == ProviderType.Files && Configuration.ManifestToolAction == ManifestToolActions.Generate)
5555
{
5656
Log.Debug($"Using the {nameof(CGScannedExternalDocumentReferenceFileProvider)} provider for the files workflow.");
5757
return true;

src/Microsoft.Sbom.Api/Workflows/SbomAggregationWorkflow.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ private IEnumerable<AggregationSource> GetSbomsToAggregate(string artifactPath,
127127
var isValidSpdxFormat = spdxFormatDetector.TryGetSbomsWithVersion(manifestDirPath, out var detectedSboms);
128128
if (!isValidSpdxFormat)
129129
{
130-
logger.Information($"No SBOMs located in {manifestDirPath} of a recognized SPDX format.");
130+
logger.Warning($"No SBOMs located in {manifestDirPath} of a recognized SPDX format.");
131131
return null;
132132
}
133133

@@ -148,6 +148,7 @@ private async Task<bool> ValidateSourceSbomsAsync(IEnumerable<AggregationSource>
148148
configuration.IgnoreMissing = new ConfigurationSetting<bool>(source.ArtifactInfo.IgnoreMissingFiles ?? false);
149149
configuration.BuildDropPath = new ConfigurationSetting<string>(source.BuildDropPath);
150150
configuration.OutputPath = new ConfigurationSetting<string>(fileSystemUtils.JoinPaths(workingDir, $"validation-results-{identifier}.json"));
151+
configuration.ManifestInfo = new ConfigurationSetting<IList<ManifestInfo>>(new List<ManifestInfo>() { source.SbomConfig.ManifestInfo });
151152
configuration.ManifestDirPath = BuildManifestDirPathForSource(source);
152153

153154
Console.WriteLine($"Running validation for {source.SbomConfig.ManifestJsonFilePath} with identifier {identifier}. Writing output results to {configuration.OutputPath.Value}.");

src/Microsoft.Sbom.Api/Workflows/SbomGenerationWorkflow.cs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,8 @@ private async Task<IEnumerable<FileValidationResult>> CallGeneratorsAync(IEnumer
186186
// Write all the JSON documents from the generationResults to the manifest based on the manifestInfo.
187187
// When aggregating, only call the packages generator. A helper method might make this more compact,
188188
// but it would be less readable.
189-
if (configuration.ManifestToolAction == ManifestToolActions.Generate)
190-
{
191-
var fileGeneratorResult = await fileArrayGenerator.GenerateAsync(targetConfigs, elementsSpdxIdList);
192-
validErrors.AddRange(fileGeneratorResult.Errors);
193-
}
189+
var fileGeneratorResult = await fileArrayGenerator.GenerateAsync(targetConfigs, elementsSpdxIdList);
190+
validErrors.AddRange(fileGeneratorResult.Errors);
194191

195192
var packageGeneratorResult = await packageArrayGenerator.GenerateAsync(targetConfigs, elementsSpdxIdList);
196193
validErrors.AddRange(packageGeneratorResult.Errors);
@@ -201,11 +198,8 @@ private async Task<IEnumerable<FileValidationResult>> CallGeneratorsAync(IEnumer
201198
validErrors.AddRange(externalDocumentReferenceGeneratorResult.Errors);
202199
}
203200

204-
if (configuration.ManifestToolAction == ManifestToolActions.Generate)
205-
{
206-
var relationshipGeneratorResult = await relationshipsArrayGenerator.GenerateAsync(targetConfigs, elementsSpdxIdList);
207-
validErrors.AddRange(relationshipGeneratorResult.Errors);
208-
}
201+
var relationshipGeneratorResult = await relationshipsArrayGenerator.GenerateAsync(targetConfigs, elementsSpdxIdList);
202+
validErrors.AddRange(relationshipGeneratorResult.Errors);
209203

210204
return validErrors;
211205
}

src/Microsoft.Sbom.Common/Config/IConfiguration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ public interface IConfiguration
127127

128128
/// <summary>
129129
/// Gets or sets a list of <see cref="SbomFile"/> files provided to us from the API.
130-
/// We won't traverse the build root path to get a list of files if this is set, and
131-
/// use the list provided here instead.
130+
/// We will use the list provided here to populate the files section in addition to
131+
/// select file providers.
132132
/// </summary>
133133
public ConfigurationSetting<IEnumerable<SbomFile>> FilesList { get; set; }
134134

src/Microsoft.Sbom.Common/Utils/CommonSPDXUtils.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Security.Cryptography;
66
using System.Text;
77
using System.Text.RegularExpressions;
8+
using Microsoft.Sbom.Contracts;
89

910
namespace Microsoft.Sbom.Common.Utils;
1011

@@ -23,6 +24,32 @@ public static class CommonSPDXUtils
2324
/// </summary>
2425
public static string GenerateSpdxPackageId(string id) => $"{Constants.SPDXRefPackage}-{GetStringHash(id)}";
2526

27+
/// <summary>
28+
/// Returns the SPDX-compliant package ID from an SbomPackage object.
29+
/// </summary>
30+
public static string GenerateSpdxPackageId(SbomPackage packageInfo)
31+
{
32+
if (packageInfo is null)
33+
{
34+
throw new ArgumentNullException(nameof(packageInfo));
35+
}
36+
37+
// Special case to preserve incoming SPDX ID's during aggregation
38+
if (packageInfo.Id is not null && packageInfo.Id.StartsWith(Constants.SPDXRefPackage, StringComparison.OrdinalIgnoreCase))
39+
{
40+
return packageInfo.Id;
41+
}
42+
43+
// Get package identity as package name and package version. If version is empty, just use package name
44+
var packageIdentity = $"{packageInfo.Type}-{packageInfo.PackageName}";
45+
if (!string.IsNullOrWhiteSpace(packageInfo.PackageVersion))
46+
{
47+
packageIdentity = string.Join("-", packageInfo.Type, packageInfo.PackageName, packageInfo.PackageVersion);
48+
}
49+
50+
return GenerateSpdxPackageId(packageInfo.Id ?? packageIdentity);
51+
}
52+
2653
/// <summary>
2754
/// Returns the SPDX-compliant file ID.
2855
/// </summary>

0 commit comments

Comments
 (0)