зеркало из https://github.com/microsoft/BuildXL.git
Merged PR 643161: Remove SBOMUtilities.ComponentDetectionConverter in favor of the Microsoft.SBOM.Adapters library
- Remove ComponentDetectionConverter in favor of the Microsoft.SBOM.Adapters library - Update SBOM packages to version 2.0.99 Related work items: #1902188
This commit is contained in:
Родитель
8672977bf8
Коммит
8889e2ec89
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
import {Transformer} from "Sdk.Transformers";
|
||||
import * as Managed from "Sdk.Managed";
|
||||
|
||||
// This is an empty facade for a Microsoft internal package.
|
||||
|
||||
namespace Contents {
|
||||
export declare const qualifier: {
|
||||
};
|
||||
|
||||
@@public
|
||||
export const all: StaticDirectory = Transformer.sealPartialDirectory(d`.`, []);
|
||||
}
|
||||
|
||||
@@public
|
||||
export const pkg: Managed.ManagedNugetPackage =
|
||||
Managed.Factory.createNugetPackage(
|
||||
"Microsoft.SBOM.Adapters",
|
||||
"0.0.0",
|
||||
Contents.all,
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
);
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
module({
|
||||
name: "Microsoft.SBOM.Adapters"
|
||||
});
|
|
@ -27,6 +27,7 @@ using Microsoft.Extensions.Logging.Abstractions;
|
|||
using Microsoft.VisualStudio.Services.Common;
|
||||
using Microsoft.VisualStudio.Services.Drop.WebApi;
|
||||
using Microsoft.VisualStudio.Services.WebApi;
|
||||
using Microsoft.Sbom.Adapters;
|
||||
using Microsoft.Sbom.Contracts;
|
||||
using Microsoft.Sbom.Contracts.Entities;
|
||||
using Microsoft.Sbom.Contracts.Enums;
|
||||
|
@ -37,6 +38,7 @@ using static BuildXL.Utilities.FormattableStringEx;
|
|||
using static Tool.ServicePipDaemon.Statics;
|
||||
using BuildXL.Utilities.SBOMUtilities;
|
||||
using BuildXL.Utilities.Tracing;
|
||||
using Microsoft.Sbom.Adapters.Report;
|
||||
|
||||
namespace Tool.DropDaemon
|
||||
{
|
||||
|
@ -901,15 +903,38 @@ namespace Tool.DropDaemon
|
|||
return new List<SBOMPackage>();
|
||||
}
|
||||
|
||||
var sbomLogger = new SBOMConverterLogger(
|
||||
m => Logger.Info(m),
|
||||
m => Logger.Warning(m),
|
||||
m => Logger.Warning(m)); // TODO: Change this to an error once testing is complete
|
||||
var result = ComponentDetectionConverter.TryConvert(bcdeOutputJsonPath, sbomLogger, out var packages);
|
||||
|
||||
if (!result)
|
||||
var (adapterReport, packages) = new ComponentDetectionToSBOMPackageAdapter().TryConvert(bcdeOutputJsonPath);
|
||||
|
||||
foreach (var reportItem in adapterReport.Report)
|
||||
{
|
||||
Logger.Warning($"ComponentDetectionConverter did not complete successfully.");
|
||||
switch (reportItem.Type)
|
||||
{
|
||||
case AdapterReportItemType.Success:
|
||||
{
|
||||
if (!string.IsNullOrEmpty(reportItem.Details))
|
||||
{
|
||||
Logger.Info("[ComponentDetectionToSBOMPackageAdapter] " + reportItem.Details);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AdapterReportItemType.Warning:
|
||||
{
|
||||
if (!string.IsNullOrEmpty(reportItem.Details))
|
||||
{
|
||||
Logger.Warning("[ComponentDetectionToSBOMPackageAdapter] " + reportItem.Details);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AdapterReportItemType.Failure:
|
||||
{
|
||||
if (!string.IsNullOrEmpty(reportItem.Details))
|
||||
{
|
||||
Logger.Error("[ComponentDetectionToSBOMPackageAdapter] " + reportItem.Details);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return packages ?? new List<SBOMPackage>();
|
||||
|
|
|
@ -62,6 +62,7 @@ export namespace DropDaemon {
|
|||
BuildXLSdk.isFullFramework,
|
||||
NetFx.Netstandard.dll
|
||||
),
|
||||
importFrom("Microsoft.SBOM.Adapters").withQualifier({ targetFramework: "netstandard2.0" }).pkg,
|
||||
importFrom("System.Text.Json.v5.0.0").pkg,
|
||||
importFrom("System.Text.Encodings.Web.v5.0.1").pkg,
|
||||
],
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using BuildXL.ToolSupport;
|
||||
|
||||
namespace SBOMConverter
|
||||
{
|
||||
internal sealed class Args : CommandLineUtilities
|
||||
{
|
||||
public readonly string BcdeOutputPath = string.Empty;
|
||||
public readonly string ResultPath = string.Empty;
|
||||
|
||||
private static readonly string[] s_helpStrings = new[] { "?", "help" };
|
||||
|
||||
public Args(string[] args)
|
||||
: base(args)
|
||||
{
|
||||
foreach (Option opt in Options)
|
||||
{
|
||||
if (opt.Name.Equals("bcdeOutputPath", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
BcdeOutputPath = ParseStringOption(opt);
|
||||
}
|
||||
else if (opt.Name.Equals("resultPath", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ResultPath = ParseStringOption(opt);
|
||||
}
|
||||
else if (s_helpStrings.Any(s => opt.Name.Equals(s, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
WriteHelp();
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(BcdeOutputPath))
|
||||
{
|
||||
throw Error("bcdeOutputPath must be specified.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteHelp()
|
||||
{
|
||||
HelpWriter writer = new HelpWriter();
|
||||
writer.WriteBanner("SBOMConverter.exe - Wrapper tool to convert from the component detection package format to the SBOM package format.");
|
||||
writer.WriteOption("bcdeOutputPath", "Required. Path to the bcde-output.json file generated by the component detection tool.");
|
||||
writer.WriteOption("resultPath", "Required. Path to write the serialized results of the conversion in a JSON file.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Sbom.Contracts;
|
||||
using Microsoft.VisualStudio.Services.Governance.ComponentDetection.BcdeModels;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SBOMConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts from Component Detection BCDE to SPDX component format.
|
||||
/// </summary>
|
||||
public static class ComponentDetectionConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts from <see cref="Microsoft.VisualStudio.Services.Governance.ComponentDetection.TypedComponent"/> to <see cref="SBOMPackage"/>
|
||||
/// by reading a bcde-output.json file produced from the component detection library.
|
||||
/// </summary>
|
||||
/// <param name="bcdeOutputPath">Path to bcde-output.json file.</param>
|
||||
/// <param name="logger">Logger to log any potential warnings during conversion.</param>
|
||||
/// <param name="packages">List of <see cref="SBOMPackage"/> objects to be returned.</param>
|
||||
/// <returns>Returns false if package conversion was unsuccessful or only partially successful.</returns>
|
||||
public static bool TryConvert(string bcdeOutputPath, Action<string> logger, out IEnumerable<SBOMPackage> packages)
|
||||
{
|
||||
var result = true;
|
||||
packages = null;
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(bcdeOutputPath);
|
||||
result = ConvertInternal(json, logger, out var generatedPackages);
|
||||
packages = generatedPackages;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log(logger, $"Unable to parse bcde-output.json at path '{bcdeOutputPath}' due to the following exception: {ex}");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same method as <see cref="TryConvert(string, Action{string}, out IEnumerable{SBOMPackage})"/>, but accepts a json string directly instead of a path to read for unit testing.
|
||||
/// </summary>
|
||||
public static bool TryConvertForUnitTest(string json, Action<string> logger, out IEnumerable<SBOMPackage> packages)
|
||||
{
|
||||
var result = true;
|
||||
packages = null;
|
||||
|
||||
try
|
||||
{
|
||||
result = ConvertInternal(json, logger, out var generatedPackages);
|
||||
packages = generatedPackages;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log(logger, $"Unable to parse bcde-output.json due to the following exception: {ex}");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool ConvertInternal(string json, Action<string> logger, out IEnumerable<SBOMPackage> packages)
|
||||
{
|
||||
packages = null;
|
||||
var result = true;
|
||||
var componentDetectionScanResult = JsonConvert.DeserializeObject<ScanResult>(json);
|
||||
|
||||
if (componentDetectionScanResult == null)
|
||||
{
|
||||
Log(logger, $"Parsing bcde-output.json returns null.");
|
||||
result = false;
|
||||
}
|
||||
else if (componentDetectionScanResult.ComponentsFound != null)
|
||||
{
|
||||
packages = componentDetectionScanResult.ComponentsFound.ToList()
|
||||
.ConvertAll(component =>
|
||||
{
|
||||
if (SBOMPackageGenerator.TryConvertTypedComponent(component.Component, logger, out var package))
|
||||
{
|
||||
return package;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A warning should already be logged here.
|
||||
result = false;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
// It is acceptable to return a partial list of values with null filtered out since they should be reported as failures already
|
||||
.Where(package => package != null)
|
||||
.Select(package => package!);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static void Log(Action<string> logger, string message)
|
||||
{
|
||||
logger($"[SBOMConverter.ComponentDetectionConverter] {message}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SBOMConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// SBOMConverter to convert from TypedComponent to SBOMPackage
|
||||
/// </summary>
|
||||
public static class Program
|
||||
{
|
||||
/// <nodoc/>
|
||||
public static void Main(string[] arguments)
|
||||
{
|
||||
var args = new Args(arguments);
|
||||
|
||||
try
|
||||
{
|
||||
var result = ComponentDetectionConverter.TryConvert(args.BcdeOutputPath, m => Console.Error.Write(m), out var packages);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
Console.Error.Write($"[SBOMConverter] SBOM package conversion failed for components at path '{args.BcdeOutputPath}'.");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
// Serialize result to file
|
||||
var jsonResult = JsonConvert.SerializeObject(packages, Formatting.Indented);
|
||||
File.WriteAllText(args.ResultPath, jsonResult);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.Write($"[SBOMConverter] Failed with exception: {ex}");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,226 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Sbom.Contracts;
|
||||
using Microsoft.Sbom.Contracts.Enums;
|
||||
using Microsoft.VisualStudio.Services.Governance.ComponentDetection;
|
||||
|
||||
namespace SBOMConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Generator class for converting <see cref="SBOMPackage"/>.
|
||||
/// </summary>
|
||||
public class SBOMPackageGenerator
|
||||
{
|
||||
private static readonly Dictionary<ComponentType, Action<TypedComponent, SBOMPackage>> s_typedComponentMap = new()
|
||||
{
|
||||
{ ComponentType.Cargo, ConvertCargoComponent },
|
||||
{ ComponentType.Conda, ConvertCondaComponent },
|
||||
{ ComponentType.DockerImage, ConvertDockerImageComponent },
|
||||
{ ComponentType.Git, ConvertGitComponent },
|
||||
{ ComponentType.Go, ConvertGoComponent },
|
||||
{ ComponentType.Linux, ConvertLinuxComponent },
|
||||
{ ComponentType.Maven, ConvertMavenComponent },
|
||||
{ ComponentType.Npm, ConvertNpmComponent },
|
||||
{ ComponentType.NuGet, ConvertNuGetComponent },
|
||||
{ ComponentType.Other, ConvertOtherComponent },
|
||||
{ ComponentType.Pip, ConvertPipComponent },
|
||||
{ ComponentType.Pod, ConvertPodComponent },
|
||||
{ ComponentType.RubyGems, ConvertRubyGemsComponent },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Tries to convert from <see cref="TypedComponent"/> to <see cref="SBOMPackage"/>.
|
||||
/// </summary>
|
||||
/// <param name="component">Component to convert.</param>
|
||||
/// <param name="logger">Logger to log any issues with conversion.</param>
|
||||
/// <param name="package"><see cref="SBOMPackage"/> that was created from the <see cref="TypedComponent"/>.</param>
|
||||
/// <returns>True if conversion was successful, and false if not. Warnings will be logged if false is returned, and will return a default <see cref="SBOMPackage"/> object.</returns>
|
||||
public static bool TryConvertTypedComponent(TypedComponent component, Action<string> logger, out SBOMPackage package)
|
||||
{
|
||||
package = default;
|
||||
|
||||
if (component == null)
|
||||
{
|
||||
ComponentDetectionConverter.Log(logger, "SBOMPackageConverter received a null component.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_typedComponentMap.TryGetValue(component.Type, out var converter))
|
||||
{
|
||||
// Add generic attributes
|
||||
package = new SBOMPackage()
|
||||
{
|
||||
Id = component.Id,
|
||||
PackageUrl = component.PackageUrl?.ToString(),
|
||||
};
|
||||
|
||||
// Add component specific attributes
|
||||
converter(component, package);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the map does not contain this type, then it is most likely a new component type.
|
||||
ComponentDetectionConverter.Log(logger, $"SBOMPackageConverter could not find type mapping for TypedComponent of type '{component.Type}'.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#region Converters
|
||||
private static void ConvertCargoComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as CargoComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.PackageVersion = c.Version;
|
||||
}
|
||||
|
||||
private static void ConvertCondaComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as CondaComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.PackageVersion = c.Version;
|
||||
package.PackageSource = c.Url;
|
||||
package.Checksum = new List<Checksum>()
|
||||
{
|
||||
new Checksum()
|
||||
{
|
||||
//Algorithm = AlgorithmName.MD5, // Uncomment when MD5 is added in a future release
|
||||
ChecksumValue = c.MD5
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConvertDockerImageComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as DockerImageComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.Checksum = new List<Checksum>()
|
||||
{
|
||||
new Checksum()
|
||||
{
|
||||
Algorithm = AlgorithmName.SHA256,
|
||||
ChecksumValue = c.Digest
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConvertGitComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as GitComponent;
|
||||
|
||||
package.PackageSource = c.RepositoryUrl.ToString();
|
||||
package.Checksum = new List<Checksum>()
|
||||
{
|
||||
new Checksum()
|
||||
{
|
||||
Algorithm = AlgorithmName.SHA1,
|
||||
ChecksumValue = c.CommitHash
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConvertGoComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as GoComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.PackageVersion = c.Version;
|
||||
package.Checksum = new List<Checksum>()
|
||||
{
|
||||
new Checksum()
|
||||
{
|
||||
Algorithm = AlgorithmName.SHA256,
|
||||
ChecksumValue = c.Hash
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConvertLinuxComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as LinuxComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.PackageVersion = c.Version;
|
||||
}
|
||||
|
||||
private static void ConvertMavenComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as MavenComponent;
|
||||
|
||||
package.PackageVersion = c.Version;
|
||||
}
|
||||
|
||||
private static void ConvertNpmComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as NpmComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.PackageVersion = c.Version;
|
||||
package.Checksum = new List<Checksum>()
|
||||
{
|
||||
new Checksum()
|
||||
{
|
||||
ChecksumValue = c.Hash
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConvertNuGetComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as NuGetComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.PackageVersion = c.Version;
|
||||
}
|
||||
|
||||
private static void ConvertOtherComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as OtherComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.PackageVersion = c.Version;
|
||||
package.PackageSource = c.DownloadUrl.ToString();
|
||||
package.Checksum = new List<Checksum>()
|
||||
{
|
||||
new Checksum()
|
||||
{
|
||||
ChecksumValue = c.Hash
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConvertPipComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as PipComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.PackageVersion = c.Version;
|
||||
}
|
||||
|
||||
private static void ConvertPodComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as PodComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.PackageVersion = c.Version;
|
||||
package.PackageSource = c.SpecRepo;
|
||||
}
|
||||
|
||||
private static void ConvertRubyGemsComponent(TypedComponent component, SBOMPackage package)
|
||||
{
|
||||
var c = component as RubyGemsComponent;
|
||||
|
||||
package.PackageName = c.Name;
|
||||
package.PackageVersion = c.Version;
|
||||
package.PackageSource = c.Source;
|
||||
}
|
||||
#endregion Converters
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
import * as Managed from "Sdk.Managed";
|
||||
import * as Deployment from "Sdk.Deployment";
|
||||
|
||||
namespace SBOMConverter {
|
||||
export declare const qualifier: BuildXLSdk.DefaultQualifier;
|
||||
|
||||
@@public
|
||||
export const exe = !(BuildXLSdk.Flags.isMicrosoftInternal && BuildXLSdk.isFullFramework && Context.getCurrentHost().os === "win") ? undefined : BuildXLSdk.executable({
|
||||
assemblyName: "SBOMConverter",
|
||||
rootNamespace: "Tool.SBOMConverter",
|
||||
sources: globR(d`.`, "*.cs"),
|
||||
references: [
|
||||
importFrom("Newtonsoft.Json").pkg,
|
||||
importFrom("Microsoft.VisualStudio.Services.Governance.ComponentDetection.Contracts").withQualifier({ targetFramework: "netstandard2.1" }).pkg,
|
||||
importFrom("PackageUrl").pkg,
|
||||
importFrom("BuildXL.Utilities").ToolSupport.dll,
|
||||
importFrom("Microsoft.Sbom.Contracts").pkg,
|
||||
],
|
||||
tools: {
|
||||
csc: {
|
||||
// PackageUrl and Microsoft.VisualStudio.Services.Governance.ComponentDetection.Contracts do not have strong assembly names
|
||||
noWarnings: [8002]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@public
|
||||
export const deployment : Deployment.Definition = {
|
||||
contents: [{
|
||||
subfolder: r`tools/SBOMConverter`,
|
||||
contents: [exe]
|
||||
}]
|
||||
};
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SBOMConverter;
|
||||
using Microsoft.Sbom.Contracts;
|
||||
using Test.BuildXL.TestUtilities.Xunit;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Test.Tool.SBOMConverter
|
||||
{
|
||||
public class SBOMConverterTests : XunitBuildXLTest
|
||||
{
|
||||
public SBOMConverterTests(ITestOutputHelper output) : base(output) { }
|
||||
|
||||
[Fact]
|
||||
public void ComponentDetectionConverterTest()
|
||||
{
|
||||
var json = @"{
|
||||
""componentsFound"": [
|
||||
{
|
||||
""locationsFoundAt"": [
|
||||
""/Public/Src/Tools/JavaScript/Tool.YarnGraphBuilder/src/package.json""
|
||||
],
|
||||
""component"": {
|
||||
""name"": ""@microsoft/yarn-graph-builder"",
|
||||
""version"": ""1.0.0"",
|
||||
""hash"": null,
|
||||
""type"": ""Npm"",
|
||||
""id"": ""@microsoft/yarn-graph-builder 1.0.0 - Npm""
|
||||
},
|
||||
""detectorId"": ""Npm"",
|
||||
""isDevelopmentDependency"": null,
|
||||
""topLevelReferrers"": [],
|
||||
""containerDetailIds"": []
|
||||
}
|
||||
],
|
||||
""detectorsInScan"": [],
|
||||
""ContainerDetailsMap"": {},
|
||||
""resultCode"": ""Success""
|
||||
}";
|
||||
|
||||
var (result, packages, logMessages) = WriteJsonAndConvert(json);
|
||||
|
||||
Assert.True(result);
|
||||
Assert.NotNull(packages);
|
||||
Assert.True(logMessages.Count == 0);
|
||||
Assert.True(packages.Count == 1);
|
||||
Assert.NotNull(packages[0]);
|
||||
Assert.Equal(packages[0].PackageName, "@microsoft/yarn-graph-builder");
|
||||
Assert.Equal(packages[0].PackageVersion, "1.0.0");
|
||||
Assert.NotNull(packages[0].Checksum);
|
||||
var checksums = packages[0].Checksum?.ToList();
|
||||
Assert.True(checksums?.Count == 1);
|
||||
Assert.Null(checksums[0].ChecksumValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComponentDetectionResultWithNoComponents()
|
||||
{
|
||||
var json = @"{
|
||||
""componentsFound"": [],
|
||||
""detectorsInScan"": [],
|
||||
""ContainerDetailsMap"": {},
|
||||
""resultCode"": ""Success""
|
||||
}";
|
||||
var (result, packages, logMessages) = WriteJsonAndConvert(json);
|
||||
|
||||
Assert.NotNull(packages);
|
||||
Assert.True(packages?.Count == 0);
|
||||
Assert.True(logMessages.Count == 0);
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MalformedJsonInput()
|
||||
{
|
||||
var json = "{";
|
||||
var (result, packages, logMessages) = WriteJsonAndConvert(json);
|
||||
|
||||
Assert.False(result);
|
||||
Assert.True(logMessages.Count > 0);
|
||||
Assert.Null(packages);
|
||||
Assert.Contains("Unable to parse bcde-output.json", logMessages[0]);
|
||||
}
|
||||
|
||||
private (bool, List<SBOMPackage>, List<string>) WriteJsonAndConvert(string json)
|
||||
{
|
||||
var logMessages = new List<string>();
|
||||
var result = ComponentDetectionConverter.TryConvertForUnitTest(json, m => logMessages.Add(m), out var packages);
|
||||
|
||||
return (result, packages?.ToList(), logMessages);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Test.Tool.SBOMConverter {
|
||||
export declare const qualifier: BuildXLSdk.DefaultQualifier;
|
||||
|
||||
@@public
|
||||
export const dll = !(BuildXLSdk.Flags.isMicrosoftInternal && BuildXLSdk.isFullFramework && Context.getCurrentHost().os === "win") ? undefined : BuildXLSdk.test({
|
||||
assemblyName: "Test.Tool.SBOMConverter",
|
||||
sources: globR(d`.`, "*.cs"),
|
||||
references: [
|
||||
importFrom("Newtonsoft.Json").pkg,
|
||||
importFrom("BuildXL.Tools").SBOMConverter.exe,
|
||||
importFrom("Microsoft.Sbom.Contracts").pkg,
|
||||
]
|
||||
});
|
||||
}
|
|
@ -17,12 +17,5 @@ namespace SBOMUtilities {
|
|||
internalsVisibleTo: [
|
||||
"Test.BuildXL.Utilities",
|
||||
],
|
||||
runtimeContent: [
|
||||
importFrom("BuildXL.Tools").SBOMConverter.withQualifier({
|
||||
configuration: qualifier.configuration,
|
||||
targetFramework: "net6.0",
|
||||
targetRuntime: qualifier.targetRuntime
|
||||
}).deployment
|
||||
]
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.Sbom.Contracts;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BuildXL.Utilities.SBOMUtilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts from the component detection package format to the SBOMPackage format.
|
||||
/// </summary>
|
||||
public class ComponentDetectionConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a bcde-output.json file produced by component detection to a list of SBOMPackage objects for SPDX.
|
||||
/// </summary>
|
||||
/// <param name="bcdeOutputPath">Path to bcde-output.json file.</param>
|
||||
/// <param name="logger">Logger to log any potential warnings during conversion.</param>
|
||||
/// <param name="packages">List of <see cref="SBOMPackage"/> objects to be returned.</param>
|
||||
/// <returns>Returns false if package conversion was unsuccessful or only partially successful.</returns>
|
||||
public static bool TryConvert(string bcdeOutputPath, SBOMConverterLogger logger, out IEnumerable<SBOMPackage> packages)
|
||||
{
|
||||
packages = null;
|
||||
if (string.IsNullOrWhiteSpace(bcdeOutputPath) || !File.Exists(bcdeOutputPath))
|
||||
{
|
||||
logger.Error($"bcde-output.json file does not exist at path '{bcdeOutputPath}'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// CODESYNC: Public\Src\Tools\SBOMConverter\Tool.SBOMConverter.dsc
|
||||
// Deployment location
|
||||
var sbomConverterToolPath = Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName, "tools", "SBOMConverter", "SBOMConverter.exe");
|
||||
var resultPath = Path.Combine(Directory.GetParent(bcdeOutputPath).FullName, "conversionresult.json");
|
||||
|
||||
try
|
||||
{
|
||||
var arguments = $"/bcdeOutputPath:{bcdeOutputPath} /resultPath:{resultPath}";
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = sbomConverterToolPath,
|
||||
Arguments = arguments,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
StandardOutputEncoding = Encoding.UTF8,
|
||||
StandardErrorEncoding = Encoding.UTF8,
|
||||
ErrorDialog = false
|
||||
};
|
||||
var timeout = TimeSpan.FromMinutes(15);
|
||||
|
||||
using var process = Process.Start(startInfo);
|
||||
if (process == null)
|
||||
{
|
||||
logger.Error($"Unable to start SBOMConverter process at path '{sbomConverterToolPath}'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
process.OutputDataReceived += (o, e) => logger.Info(e.Data);
|
||||
process.ErrorDataReceived += (o, e) => logger.Error(e.Data);
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
using (CancellationToken.None.Register(() => KillProcess(process)))
|
||||
{
|
||||
if (!process.WaitForExit((int)timeout.TotalMilliseconds))
|
||||
{
|
||||
KillProcess(process);
|
||||
logger.Error($"SBOMConverter process timed out.");
|
||||
return false;
|
||||
}
|
||||
|
||||
process.WaitForExit();
|
||||
}
|
||||
|
||||
process.CancelErrorRead();
|
||||
process.CancelOutputRead();
|
||||
|
||||
if (process.ExitCode == 0)
|
||||
{
|
||||
packages = JsonConvert.DeserializeObject<IEnumerable<SBOMPackage>>(File.ReadAllText(resultPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Errors have already been logged by the SBOMConverter
|
||||
logger.Error($"SBOMConverter exited with non-zero exit code '{process.ExitCode}'.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error($"Failed to execute SBOMConverter wth exception: {ex}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <nodoc/>
|
||||
private static void KillProcess(Process process)
|
||||
{
|
||||
if (process.HasExited)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
process.Kill();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// the process may have exited,
|
||||
// in this case ignore the exception
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace BuildXL.Utilities.SBOMUtilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Logging wrapper for the SBOM converter.
|
||||
/// </summary>
|
||||
public class SBOMConverterLogger
|
||||
{
|
||||
private readonly Action<string> m_infoLogger;
|
||||
private readonly Action<string> m_warningLogger;
|
||||
private readonly Action<string> m_errorLogger;
|
||||
|
||||
/// <nodoc/>
|
||||
public SBOMConverterLogger(Action<string> infoLogger, Action<string> warningLogger, Action<string> errorLogger)
|
||||
{
|
||||
m_infoLogger = infoLogger;
|
||||
m_warningLogger = warningLogger;
|
||||
m_errorLogger = errorLogger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log informational message.
|
||||
/// </summary>
|
||||
public void Info(string message)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
m_infoLogger(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log warning.
|
||||
/// </summary>
|
||||
public void Warning(string message)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
m_warningLogger(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log error.
|
||||
/// </summary>
|
||||
public void Error(string message)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
m_errorLogger(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1333,6 +1333,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "NuGet",
|
||||
"NuGet": {
|
||||
"Name": "Microsoft.ComponentDetection.Contracts",
|
||||
"Version": "1.0.8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "NuGet",
|
||||
|
@ -1581,7 +1590,7 @@
|
|||
"Type": "NuGet",
|
||||
"NuGet": {
|
||||
"Name": "Microsoft.ManifestInterface",
|
||||
"Version": "2.0.90"
|
||||
"Version": "2.0.99"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1986,7 +1995,7 @@
|
|||
"Type": "NuGet",
|
||||
"NuGet": {
|
||||
"Name": "Microsoft.Parsers.ManifestGenerator",
|
||||
"Version": "2.0.90"
|
||||
"Version": "2.0.99"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1995,7 +2004,7 @@
|
|||
"Type": "NuGet",
|
||||
"NuGet": {
|
||||
"Name": "Microsoft.Parsers.SPDX22SBOMParser",
|
||||
"Version": "2.0.90"
|
||||
"Version": "2.0.99"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2026,12 +2035,21 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "NuGet",
|
||||
"NuGet": {
|
||||
"Name": "Microsoft.SBOM.Adapters",
|
||||
"Version": "2.0.99"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Component": {
|
||||
"Type": "NuGet",
|
||||
"NuGet": {
|
||||
"Name": "Microsoft.SBOMCore",
|
||||
"Version": "2.0.90"
|
||||
"Version": "2.0.99"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2040,7 +2058,7 @@
|
|||
"Type": "NuGet",
|
||||
"NuGet": {
|
||||
"Name": "Microsoft.Sbom.Contracts",
|
||||
"Version": "2.0.90"
|
||||
"Version": "2.0.99"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ const isMicrosoftInternal = Environment.getFlag("[Sdk.BuildXL]microsoftInternal"
|
|||
|
||||
const artifactNugetVersion = "18.194.31720-buildid16023539";
|
||||
const azureDevopsNugetVersion = "16.194.0-internal202109201";
|
||||
const sbomApiVersion = "2.0.90";
|
||||
const sbomApiVersion = "2.0.99";
|
||||
|
||||
// These packages are Microsoft internal packages.
|
||||
// These consist of internally repackaged products that we can't push to a public feed and have to rely on users installing locally.
|
||||
|
@ -76,6 +76,8 @@ export const pkgs = isMicrosoftInternal ? [
|
|||
{ id: "Microsoft.SBOMCore", version: sbomApiVersion, dependentPackageIdsToSkip: ["Microsoft.Extensions.Logging.Abstractions"] },
|
||||
{ id: "Microsoft.Parsers.ManifestGenerator", version: sbomApiVersion, dependentPackageIdsToSkip: ["Newtonsoft.Json"]},
|
||||
{ id: "Microsoft.Parsers.SPDX22SBOMParser", version: sbomApiVersion },
|
||||
{ id: "Microsoft.SBOM.Adapters", version: sbomApiVersion },
|
||||
{ id: "Microsoft.ComponentDetection.Contracts", version: "1.0.8" },
|
||||
{ id: "Microsoft.ManifestInterface", version: sbomApiVersion, dependentPackageIdsToSkip: ["System.Text.Json"] },
|
||||
{ id: "Microsoft.Sbom.Contracts", version: sbomApiVersion },
|
||||
{ id: "Microsoft.Bcl.HashCode", version: "1.1.1" },
|
||||
|
|
Загрузка…
Ссылка в новой задаче