diff --git a/src/Microsoft.Sbom.Targets/GenerateSbom.cs b/src/Microsoft.Sbom.Targets/GenerateSbom.cs new file mode 100644 index 000000000..18e6fa623 --- /dev/null +++ b/src/Microsoft.Sbom.Targets/GenerateSbom.cs @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Sbom.Targets; + +using System; +using System.Collections.Generic; +using System.Diagnostics.Tracing; +using Microsoft.Build.Framework; + +/// +/// This partial class defines and sanitizes the arguments that will be passed +/// into the SBOM API and CLI tool for generation. +/// +public partial class GenerateSbom +{ + /// + /// Gets or sets the path to the drop directory for which the SBOM will be generated. + /// + [Required] + public string BuildDropPath { get; set; } + + /// + /// Gets or sets the supplier of the package the SBOM represents. + /// + [Required] + public string PackageSupplier { get; set; } + + /// + /// Gets or sets the name of the package the SBOM represents. + /// + [Required] + public string PackageName { get; set; } + + /// + /// Gets or sets the version of the package the SBOM represents. + /// + [Required] + public string PackageVersion { get; set; } + + /// + /// Gets or sets the base path of the SBOM namespace uri. + /// + [Required] + public string NamespaceBaseUri { get; set; } + + /// + /// Gets or sets the path to the directory containing build components and package information. + /// For example, path to a .csproj or packages.config file. + /// + public string BuildComponentPath { get; set; } + + /// + /// Gets or sets a unique URI part that will be appended to NamespaceBaseUri. + /// + public string NamespaceUriUniquePart { get; set; } + + /// + /// Gets or sets the path to a file containing a list of external SBOMs that will be appended to the + /// SBOM that is being generated. + /// + public string ExternalDocumentListFile { get; set; } + + /// + /// Indicates whether licensing information will be fetched for detected packages. + /// + public bool FetchLicenseInformation { get; set; } + + /// + /// Indicates whether to parse licensing and supplier information from a packages metadata file. + /// + public bool EnablePackageMetadataParsing { get; set; } + + /// + /// Gets or sets the verbosity level for logging output. + /// + public string Verbosity { get; set; } + + /// + /// Gets or sets a list of names and versions of the manifest format being used. + /// + public string ManifestInfo { get; set; } + + /// + /// Indicates whether the previously generated SBOM manifest directory should be deleted + /// before generating a new SBOM in the directory specified by ManifestDirPath. + /// Defaults to true. + /// + public bool DeleteManifestDirIfPresent { get; set; } = true; + + /// + /// Gets or sets the path where the SBOM will be generated. + /// + public string ManifestDirPath { get; set; } + + /// + /// Gets or sets the path to the SBOM CLI tool + /// + public string SbomToolPath { get; set; } + + /// + /// Gets or sets the path to the generated SBOM directory. + /// + [Output] + public string SbomPath { get; set; } +} diff --git a/src/Microsoft.Sbom.Targets/GenerateSbomTask.cs b/src/Microsoft.Sbom.Targets/GenerateSbomTask.cs index 6225a0370..09bf332d0 100644 --- a/src/Microsoft.Sbom.Targets/GenerateSbomTask.cs +++ b/src/Microsoft.Sbom.Targets/GenerateSbomTask.cs @@ -27,98 +27,14 @@ namespace Microsoft.Sbom.Targets; /// /// MSBuild task for generating SBOMs from build output. /// -public class GenerateSbomTask : Task +public partial class GenerateSbom : Task { - /// - /// The path to the drop directory for which the SBOM will be generated. - /// - [Required] - public string BuildDropPath { get; set; } - - /// - /// Supplier of the package the SBOM represents. - /// - [Required] - public string PackageSupplier { get; set; } - - /// - /// Name of the package the SBOM represents. - /// - [Required] - public string PackageName { get; set; } - - /// - /// Version of the package the SBOM represents. - /// - [Required] - public string PackageVersion { get; set; } - - /// - /// The base path of the SBOM namespace uri. - /// - [Required] - public string NamespaceBaseUri { get; set; } - - /// - /// The path to the directory containing build components and package information. - /// For example, path to a .csproj or packages.config file. - /// - public string BuildComponentPath { get; set; } - - /// - /// A unique URI part that will be appended to NamespaceBaseUri. - /// - public string NamespaceUriUniquePart { get; set; } - - /// - /// The path to a file containing a list of external SBOMs that will be appended to the - /// SBOM that is being generated. - /// - public string ExternalDocumentListFile { get; set; } - - /// - /// If true, it will fetch licensing information for detected packages. - /// - public bool FetchLicenseInformation { get; set; } - - /// - /// If true, it will parse licensing and supplier information from a packages metadata file. - /// - public bool EnablePackageMetadataParsing { get; set; } - - /// - /// Determines how detailed the outputed logging will be. - /// - public string Verbosity { get; set; } - - /// - /// A list of the name and version of the manifest format being used. - /// - public string ManifestInfo { get; set; } - - /// - /// If true, it will delete the previously generated SBOM manifest directory before - /// generating a new SBOM in ManifestDirPath. - /// - public bool DeleteManifestDirIfPresent { get; set; } = true; - - /// - /// The path where the SBOM will be generated. - /// - public string ManifestDirPath { get; set; } - - /// - /// The path to the generated SBOM directory. - /// - [Output] - public string SbomPath { get; set; } - private ISBOMGenerator Generator { get; set; } /// /// Constructor for the GenerateSbomTask. /// - public GenerateSbomTask() + public GenerateSbom() { var host = Host.CreateDefaultBuilder() .ConfigureServices((host, services) => diff --git a/src/Microsoft.Sbom.Targets/Microsoft.Sbom.Targets.csproj b/src/Microsoft.Sbom.Targets/Microsoft.Sbom.Targets.csproj index e2f4729bb..a2c94d9ec 100644 --- a/src/Microsoft.Sbom.Targets/Microsoft.Sbom.Targets.csproj +++ b/src/Microsoft.Sbom.Targets/Microsoft.Sbom.Targets.csproj @@ -2,6 +2,7 @@ Microsoft.Sbom.Targets + net8.0;net472 win-x64;osx-x64;linux-x64 true true @@ -10,6 +11,7 @@ GenerateSbomTask Tasks and targets for running the SBOM tool. true + net8.0 @@ -17,6 +19,7 @@ tasks + true NU5100 @@ -39,6 +42,19 @@ + + + + + + Always + true + \tasks\net472\sbom-tool\ + true + + + + + - - net6.0 - net8.0 + net472 + net8.0 + + + $(MSBuildThisFileDirectory)\..\tasks\$(GenerateSbom_TFM)\sbom-tool - + + + + - - + + - - + ManifestDirPath="$(SbomGenerationManifestDirPath)" + SbomToolPath="$(SbomToolPath)"> + + diff --git a/src/Microsoft.Sbom.Targets/SbomCLIToolTask.cs b/src/Microsoft.Sbom.Targets/SbomCLIToolTask.cs new file mode 100644 index 000000000..94e8f4759 --- /dev/null +++ b/src/Microsoft.Sbom.Targets/SbomCLIToolTask.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Sbom.Targets; + +using System.IO; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +/// +/// MSBuild ToolTask for generating an SBOM using the SBOM CLI tool +/// +public partial class GenerateSbom : ToolTask +{ + protected override string ToolName => "Microsoft.Sbom.Tool"; + + /// + /// Get full path to SBOM CLI tool. + /// + /// + protected override string GenerateFullPathToTool() + { + return Path.Combine(this.SbomToolPath, $"{this.ToolName}.exe"); + } + + /// + /// Return a formatted list of arguments for the SBOM CLI tool. + /// + /// string list of args + protected override string GenerateCommandLineCommands() + { + return "Command"; + } + + /// + /// Validates the SBOM CLI tool parameters + /// + /// + protected override bool ValidateParameters() + { + return true; + } +} diff --git a/test/Microsoft.Sbom.Targets.Tests/AbstractGenerateSBomTaskInputTests.cs b/test/Microsoft.Sbom.Targets.Tests/AbstractGenerateSBomTaskInputTests.cs index a91dbaa99..84ae06889 100644 --- a/test/Microsoft.Sbom.Targets.Tests/AbstractGenerateSBomTaskInputTests.cs +++ b/test/Microsoft.Sbom.Targets.Tests/AbstractGenerateSBomTaskInputTests.cs @@ -55,7 +55,7 @@ public void Cleanup() { } /// - /// Test for ensuring the GenerateSbomTask fails for null or empty inputs for + /// Test for ensuring the GenerateSbom fails for null or empty inputs for /// required params, which includes BuildDropPath, PackageSupplier, PackageName, /// PackageVersion, and NamespaceBaseUri. /// @@ -71,7 +71,7 @@ public void Sbom_Fails_With_Null_Empty_And_WhiteSpace_Required_Params( string namespaceBaseUri) { // Arrange. - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = buildDropPath, PackageSupplier = packageSupplier, @@ -117,7 +117,7 @@ private static IEnumerable GetWhiteSpace_Tabs_NewLineParamsData() } /// - /// Test for ensuring the GenerateSbomTask fails when user provides an + /// Test for ensuring the GenerateSbom fails when user provides an /// invalid URI format. /// [TestMethod] @@ -130,7 +130,7 @@ private static IEnumerable GetWhiteSpace_Tabs_NewLineParamsData() public void Sbom_Fails_With_Invalid_NamespaceBaseUri(string namespaceBaseUri) { // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, PackageSupplier = PackageSupplier, @@ -149,7 +149,7 @@ public void Sbom_Fails_With_Invalid_NamespaceBaseUri(string namespaceBaseUri) } /// - /// Test for ensuring the GenerateSbomTask fails when user provides + /// Test for ensuring the GenerateSbom fails when user provides /// an invalid GUID for NamespaceUriUniquePart. /// [TestMethod] @@ -165,7 +165,7 @@ public void Sbom_Fails_With_Invalid_NamespaceBaseUri(string namespaceBaseUri) public void Sbom_Generation_Fails_For_Invalid_NamespaceUriUniquePart(string namespaceUriUniquePart) { // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, PackageSupplier = PackageSupplier, @@ -185,7 +185,7 @@ public void Sbom_Generation_Fails_For_Invalid_NamespaceUriUniquePart(string name } /// - /// Test for ensuring GenerateSbomTask assigns a defualt Verbosity + /// Test for ensuring GenerateSbom assigns a defualt Verbosity /// level when null input is provided. /// [TestMethod] @@ -197,7 +197,7 @@ public void Sbom_Generation_Succeeds_For_Null_Verbosity() var pattern = new Regex("Verbosity=.*Value=Verbose"); var stringWriter = new StringWriter(); Console.SetOut(stringWriter); - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, PackageSupplier = PackageSupplier, @@ -219,7 +219,7 @@ public void Sbom_Generation_Succeeds_For_Null_Verbosity() } /// - /// Test for ensuring GenerateSbomTask assigns a default Verbosity for + /// Test for ensuring GenerateSbom assigns a default Verbosity for /// unrecognized input. /// [TestMethod] @@ -231,7 +231,7 @@ public void Sbom_Generation_Succeeds_For_Invalid_Verbosity() var pattern = new Regex("Verbosity=.*Value=Verbose"); var stringWriter = new StringWriter(); Console.SetOut(stringWriter); - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, PackageSupplier = PackageSupplier, @@ -253,7 +253,7 @@ public void Sbom_Generation_Succeeds_For_Invalid_Verbosity() } /// - /// Test to ensure GenerateSbomTask correctly parses and provides each EventLevel verbosity + /// Test to ensure GenerateSbom correctly parses and provides each EventLevel verbosity /// values to the SBOM API. /// [TestMethod] @@ -269,7 +269,7 @@ public void Sbom_Generation_Assigns_Correct_Verbosity_IgnoreCase(string inputVer var pattern = new Regex($"Verbosity=.*Value={mappedVerbosity}"); var stringWriter = new StringWriter(); Console.SetOut(stringWriter); - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, PackageSupplier = PackageSupplier, diff --git a/test/Microsoft.Sbom.Targets.Tests/AbstractGenerateSbomTaskTests.cs b/test/Microsoft.Sbom.Targets.Tests/AbstractGenerateSbomTaskTests.cs index aa054b484..c43d072db 100644 --- a/test/Microsoft.Sbom.Targets.Tests/AbstractGenerateSbomTaskTests.cs +++ b/test/Microsoft.Sbom.Targets.Tests/AbstractGenerateSbomTaskTests.cs @@ -12,7 +12,7 @@ namespace Microsoft.Sbom.Targets.Tests; /// -/// Base class for testing SBOM generation through the GenerateSbomTask. +/// Base class for testing SBOM generation through the GenerateSbom. /// [TestClass] public abstract class AbstractGenerateSbomTaskTests @@ -62,7 +62,7 @@ public void Startup() public void Sbom_Is_Successfully_Generated() { // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, PackageSupplier = PackageSupplier, @@ -92,7 +92,7 @@ public void Sbom_Is_Successfully_Generated() public void Sbom_Is_Successfully_Generated_Valid_URI(string namespaceBaseUri) { // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, PackageSupplier = PackageSupplier, @@ -118,7 +118,7 @@ public void Sbom_Is_Successfully_Generated_Valid_URI(string namespaceBaseUri) public void Sbom_Is_Successfully_Generated_Valid_RequiredParams(string packageSupplier, string packageName, string packageVersion) { // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, PackageSupplier = packageSupplier, @@ -167,7 +167,7 @@ public void Sbom_Is_Successfully_Generated_In_Specified_Location() var manifestDirPath = Path.Combine(TemporaryDirectory, "sub-directory"); Directory.CreateDirectory(manifestDirPath); // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, ManifestDirPath = manifestDirPath, @@ -193,7 +193,7 @@ public void Sbom_Is_Successfully_Generated_In_Specified_Location() public void Sbom_Generation_Fails_With_NotFound_BuildDropPath() { // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = ".\\non-existent\\path", PackageSupplier = PackageSupplier, @@ -215,7 +215,7 @@ public void Sbom_Generation_Fails_With_NotFound_BuildDropPath() public void Sbom_Generation_Fails_With_NotFound_BuildComponentPath() { // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, BuildComponentPath = ".\\non-existent\\path", @@ -239,7 +239,7 @@ public void Sbom_Generation_Fails_With_NotFound_BuildComponentPath() public void Sbom_Generation_Fails_With_NotFound_ExternalDocumentListFile() { // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, ExternalDocumentListFile = ".\\non-existent\\path", @@ -263,7 +263,7 @@ public void Sbom_Generation_Fails_With_NotFound_ExternalDocumentListFile() public void Sbom_Generation_Fails_With_NotFound_ManifestDirPath() { // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, ManifestDirPath = ".\\non-existent\\path", @@ -290,7 +290,7 @@ public void Sbom_Is_Successfully_Generated_With_Component_Path() var sourceDirectory = Path.Combine(CurrentDirectory, "..", "..", ".."); // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, BuildComponentPath = sourceDirectory, @@ -318,7 +318,7 @@ public void Sbom_Is_Successfully_Generated_With_Component_Path() public void Sbom_Is_Successfully_Generated_With_Unique_Namespace_Part_Defined(string uniqueNamespacePart) { // Arrange - var task = new GenerateSbomTask + var task = new GenerateSbom { BuildDropPath = CurrentDirectory, PackageSupplier = PackageSupplier, diff --git a/test/Microsoft.Sbom.Targets.Tests/Microsoft.Sbom.Targets.Tests.csproj b/test/Microsoft.Sbom.Targets.Tests/Microsoft.Sbom.Targets.Tests.csproj index 09913734f..4278eba17 100644 --- a/test/Microsoft.Sbom.Targets.Tests/Microsoft.Sbom.Targets.Tests.csproj +++ b/test/Microsoft.Sbom.Targets.Tests/Microsoft.Sbom.Targets.Tests.csproj @@ -17,6 +17,8 @@ + +