Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API changes to support SPDX 3.0 #924

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
6 changes: 6 additions & 0 deletions Microsoft.Sbom.sln
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Sbom.Parsers.Spdx
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Sbom.Parsers.Spdx30SbomParser.Tests", "test\Microsoft.Sbom.Parsers.Spdx30SbomParser.Tests\Microsoft.Sbom.Parsers.Spdx30SbomParser.Tests.csproj", "{E3FE33BB-FAB2-4F60-B930-BEB736AACE25}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Sbom.Constants", "src\Microsoft.Sbom.Constants\Microsoft.Sbom.Constants.csproj", "{B898DBCA-E6AF-496A-A0E0-A3D159018CE4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -143,6 +145,10 @@ Global
{E3FE33BB-FAB2-4F60-B930-BEB736AACE25}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3FE33BB-FAB2-4F60-B930-BEB736AACE25}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3FE33BB-FAB2-4F60-B930-BEB736AACE25}.Release|Any CPU.Build.0 = Release|Any CPU
{B898DBCA-E6AF-496A-A0E0-A3D159018CE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B898DBCA-E6AF-496A-A0E0-A3D159018CE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B898DBCA-E6AF-496A-A0E0-A3D159018CE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B898DBCA-E6AF-496A-A0E0-A3D159018CE4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
18 changes: 10 additions & 8 deletions src/Microsoft.Sbom.Api/Config/ApiConfigurationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
using Microsoft.Sbom.Contracts.Enums;
using Microsoft.Sbom.Extensions.Entities;
using Serilog.Events;
using ApiConstants = Microsoft.Sbom.Api.Utils.Constants;
using Constants = Microsoft.Sbom.Common.Constants;
using SbomConstants = Microsoft.Sbom.Common.Constants;
using SpdxConstants = Microsoft.Sbom.Constants.SpdxConstants;

namespace Microsoft.Sbom.Api.Config;

Expand Down Expand Up @@ -123,9 +123,10 @@ public static InputConfiguration GetConfiguration(
throw new ArgumentException($"'{nameof(outputPath)}' cannot be null or whitespace.", nameof(outputPath));
}

// TODO: update to SPDX 3.0 for default.
if (specifications is null || specifications.Count == 0)
{
specifications = new List<SbomSpecification>() { ApiConstants.SPDX22Specification };
specifications = SpdxConstants.SupportedSbomSpecifications;
}

var sanitizedRuntimeConfiguration = SanitiseRuntimeConfiguration(runtimeConfiguration);
Expand All @@ -142,6 +143,7 @@ public static InputConfiguration GetConfiguration(
IgnoreMissing = GetConfigurationSetting(ignoreMissing),
Parallelism = GetConfigurationSetting(sanitizedRuntimeConfiguration.WorkflowParallelism),
ManifestInfo = ConvertSbomSpecificationToManifestInfo(specifications),
ComplianceStandard = GetConfigurationSetting(string.Empty),
};

SetVerbosity(sanitizedRuntimeConfiguration, configuration);
Expand Down Expand Up @@ -185,7 +187,7 @@ private static void SetVerbosity(RuntimeConfiguration sanitizedRuntimeConfigurat
System.Diagnostics.Tracing.EventLevel.LogAlways => GetConfigurationSetting(LogEventLevel.Verbose),
System.Diagnostics.Tracing.EventLevel.Warning => GetConfigurationSetting(LogEventLevel.Warning),
System.Diagnostics.Tracing.EventLevel.Verbose => GetConfigurationSetting(LogEventLevel.Verbose),
_ => GetConfigurationSetting(Constants.DefaultLogLevel),
_ => GetConfigurationSetting(SbomConstants.DefaultLogLevel),
};
}

Expand All @@ -204,17 +206,17 @@ private static RuntimeConfiguration SanitiseRuntimeConfiguration(RuntimeConfigur
{
runtimeConfiguration = new RuntimeConfiguration
{
WorkflowParallelism = Constants.DefaultParallelism,
WorkflowParallelism = SbomConstants.DefaultParallelism,
Verbosity = System.Diagnostics.Tracing.EventLevel.Warning,
DeleteManifestDirectoryIfPresent = false,
FollowSymlinks = true
};
}

if (runtimeConfiguration.WorkflowParallelism < Constants.MinParallelism
|| runtimeConfiguration.WorkflowParallelism > Constants.MaxParallelism)
if (runtimeConfiguration.WorkflowParallelism < SbomConstants.MinParallelism
|| runtimeConfiguration.WorkflowParallelism > SbomConstants.MaxParallelism)
{
runtimeConfiguration.WorkflowParallelism = Constants.DefaultParallelism;
runtimeConfiguration.WorkflowParallelism = SbomConstants.DefaultParallelism;
}

return runtimeConfiguration;
Expand Down
7 changes: 7 additions & 0 deletions src/Microsoft.Sbom.Api/Config/Args/ValidationArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,11 @@ public class ValidationArgs : GenerationAndValidationCommonArgs
/// </summary>
[ArgDescription("The Hash algorithm to use while verifying or generating the hash value of a file")]
public AlgorithmName HashAlgorithm { get; set; }

/// <summary>
/// The compliance standard to validate against.
/// </summary>
[ArgDescription("The compliance standard to validate against")]
[ArgShortcut("cs")]
public ComplianceStandard ComplianceStandard { get; set; }
}
25 changes: 13 additions & 12 deletions src/Microsoft.Sbom.Api/Config/ConfigSanitizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
using PowerArgs;
using Serilog;
using Serilog.Core;
using Constants = Microsoft.Sbom.Api.Utils.Constants;
using SbomConstants = Microsoft.Sbom.Common.Constants;
using SpdxConstants = Microsoft.Sbom.Constants.SpdxConstants;

namespace Microsoft.Sbom.Api.Config;

Expand Down Expand Up @@ -48,7 +49,7 @@ public IConfiguration SanitizeConfig(IConfiguration configuration)
// Create temporary logger to show logs during config sanitizing
var logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(new LoggingLevelSwitch { MinimumLevel = configuration.Verbosity.Value })
.WriteTo.Console(outputTemplate: Constants.LoggerTemplate)
.WriteTo.Console(outputTemplate: SpdxConstants.LoggerTemplate)
.CreateLogger();

// If BuildDropPath is null then run the logic to check whether it is required or not based on the current configuration.
Expand Down Expand Up @@ -82,21 +83,21 @@ public IConfiguration SanitizeConfig(IConfiguration configuration)
if (configuration2 is not null)
{
// Prevent null value for LicenseInformationTimeoutInSeconds.
// Values of (0, Constants.MaxLicenseFetchTimeoutInSeconds] are allowed. Negative values are replaced with the default, and
// the higher values are truncated to the maximum of Common.Constants.MaxLicenseFetchTimeoutInSeconds
// Values of (0, SpdxConstants.MaxLicenseFetchTimeoutInSeconds] are allowed. Negative values are replaced with the default, and
// the higher values are truncated to the maximum of Common.SpdxConstants.MaxLicenseFetchTimeoutInSeconds
if (configuration2.LicenseInformationTimeoutInSeconds is null)
{
configuration2.LicenseInformationTimeoutInSeconds = new(Common.Constants.DefaultLicenseFetchTimeoutInSeconds, SettingSource.Default);
configuration2.LicenseInformationTimeoutInSeconds = new(SbomConstants.DefaultLicenseFetchTimeoutInSeconds, SettingSource.Default);
}
else if (configuration2.LicenseInformationTimeoutInSeconds.Value <= 0)
{
logger.Warning($"Negative and Zero Values not allowed for timeout. Using the default {Common.Constants.DefaultLicenseFetchTimeoutInSeconds} seconds instead.");
configuration2.LicenseInformationTimeoutInSeconds.Value = Common.Constants.DefaultLicenseFetchTimeoutInSeconds;
logger.Warning($"Negative and Zero Values not allowed for timeout. Using the default {SbomConstants.DefaultLicenseFetchTimeoutInSeconds} seconds instead.");
configuration2.LicenseInformationTimeoutInSeconds.Value = SbomConstants.DefaultLicenseFetchTimeoutInSeconds;
}
else if (configuration2.LicenseInformationTimeoutInSeconds.Value > Common.Constants.MaxLicenseFetchTimeoutInSeconds)
else if (configuration2.LicenseInformationTimeoutInSeconds.Value > SbomConstants.MaxLicenseFetchTimeoutInSeconds)
{
logger.Warning($"Specified timeout exceeds maximum allowed. Truncating the timeout to {Common.Constants.MaxLicenseFetchTimeoutInSeconds} seconds.");
configuration2.LicenseInformationTimeoutInSeconds.Value = Common.Constants.MaxLicenseFetchTimeoutInSeconds;
logger.Warning($"Specified timeout exceeds maximum allowed. Truncating the timeout to {SbomConstants.MaxLicenseFetchTimeoutInSeconds} seconds.");
configuration2.LicenseInformationTimeoutInSeconds.Value = SbomConstants.MaxLicenseFetchTimeoutInSeconds;
}

// Check if arg -lto is specified but -li is not
Expand Down Expand Up @@ -280,7 +281,7 @@ private ConfigurationSetting<string> GetManifestDirPath(ConfigurationSetting<str
{
return new ConfigurationSetting<string>
{
Value = fileSystemUtils.JoinPaths(buildDropPath, Constants.ManifestFolder),
Value = fileSystemUtils.JoinPaths(buildDropPath, SpdxConstants.ManifestFolder),
Source = SettingSource.Default
};
}
Expand All @@ -297,7 +298,7 @@ private string EnsurePathEndsWithManifestFolderForGenerate(string value, Manifes
if (manifestToolAction == ManifestToolActions.Generate)
{
// For generate action, add the _manifest folder at the end of the path
return fileSystemUtils.JoinPaths(value, Constants.ManifestFolder);
return fileSystemUtils.JoinPaths(value, SpdxConstants.ManifestFolder);
}

return value;
Expand Down
5 changes: 3 additions & 2 deletions src/Microsoft.Sbom.Api/Config/Validator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Sbom.Api.Config.Args;
using Microsoft.Sbom.Api.Exceptions;
using Microsoft.Sbom.Api.Output.Telemetry;
using Microsoft.Sbom.Api.Utils;
using Microsoft.Sbom.Api.Workflows;
using Microsoft.Sbom.Common.Config;
using SpdxConstants = Microsoft.Sbom.Constants.SpdxConstants;

namespace Microsoft.Sbom.Api.Config;

Expand All @@ -35,7 +36,7 @@ public async Task<bool> Validate()
bool result;
try
{
if (configuration.ManifestInfo.Value.Contains(Constants.SPDX22ManifestInfo))
if (configuration.ManifestInfo.Value.Any(SpdxConstants.SupportedSpdxManifests.Contains))
{
result = await parserValidationWorkflow.RunAsync();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using Microsoft.Sbom.Api.Utils;
using Microsoft.Sbom.Common.Config.Attributes;
using Microsoft.Sbom.Common.Config.Validators;
using Microsoft.Sbom.Constants;
using Microsoft.Sbom.Extensions.Entities;
using PowerArgs;

namespace Microsoft.Sbom.Api.Config.Validators;

/// <summary>
/// Validates if manifest info is valid.
/// </summary>
public class ManifestInfoValidator : ConfigValidator
{
public ManifestInfoValidator(IAssemblyConfig assemblyConfig)
: base(typeof(ValidUriAttribute), assemblyConfig)
{
}

public ManifestInfoValidator(Type supportedAttribute, IAssemblyConfig assemblyConfig)
: base(supportedAttribute, assemblyConfig)
{
}

public override void ValidateInternal(string paramName, object paramValue, Attribute attribute)
{
if (paramValue is not null && !SpdxConstants.SupportedSpdxManifests.Contains(paramValue as ManifestInfo))
{
throw new ValidationArgException($"The value of {paramName} must be a valid ManifestInfo. Supported SPDX versions include 2.2 and 3.0.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using AutoMapper;
using Microsoft.Sbom.Api.Utils;
using Microsoft.Sbom.Common.Config;
using Microsoft.Sbom.Contracts.Enums;
using SpdxConstants = Microsoft.Sbom.Constants.SpdxConstants;

namespace Microsoft.Sbom.Api.Config.ValueConverters;

Expand All @@ -30,7 +30,7 @@ public ConfigurationSetting<AlgorithmName> Convert(AlgorithmName sourceMember, R
return new ConfigurationSetting<AlgorithmName>
{
Source = settingSource,
Value = sourceMember ?? Constants.DefaultHashAlgorithmName
Value = sourceMember ?? SpdxConstants.DefaultHashAlgorithmName
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using AutoMapper;
using Microsoft.Sbom.Common.Config;
using Serilog.Events;
using Constants = Microsoft.Sbom.Common.Constants;
using SbomConstants = Microsoft.Sbom.Common.Constants;

namespace Microsoft.Sbom.Api.Config.ValueConverters;

Expand All @@ -30,7 +30,7 @@ public ConfigurationSetting<LogEventLevel> Convert(LogEventLevel? sourceMember,
return new ConfigurationSetting<LogEventLevel>
{
Source = settingSource,
Value = sourceMember ?? Constants.DefaultLogLevel
Value = sourceMember ?? SbomConstants.DefaultLogLevel
};
}
}
3 changes: 2 additions & 1 deletion src/Microsoft.Sbom.Api/ConfigurationProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public ConfigurationProfile()
.ForMember(c => c.NamespaceUriUniquePart, o => o.Ignore())
.ForMember(c => c.NamespaceUriBase, o => o.Ignore())
.ForMember(c => c.DeleteManifestDirIfPresent, o => o.Ignore())
.ForMember(c => c.PackageSupplier, o => o.Ignore());
.ForMember(c => c.PackageSupplier, o => o.Ignore())
.ForMember(c => c.ComplianceStandard, o => o.Ignore());

CreateMap<FormatValidationArgs, InputConfiguration>()
#pragma warning disable CS0618 // 'Configuration.ManifestPath' is obsolete: 'This field is not provided by the user or configFile, set by system'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using Microsoft.Sbom.Api.Exceptions;
using Microsoft.Sbom.Common;
using Microsoft.Sbom.Common.Config;
using Constants = Microsoft.Sbom.Api.Utils.Constants;
using SpdxConstants = Microsoft.Sbom.Constants.SpdxConstants;

namespace Microsoft.Sbom.Api.Convertors;

Expand Down Expand Up @@ -53,7 +53,7 @@ public SbomToolManifestPathConverter(IConfiguration configuration, IOSUtils osUt

// Allow spdx files to be outside the root path, all externalDocumentReference must be in the file array regardless of where they are located.
// More details are in this spec: https://github.com/spdx/spdx-spec/issues/571
if (!path.EndsWith(Constants.SPDXFileExtension, osUtils.GetFileSystemStringComparisonType()))
if (!path.EndsWith(SpdxConstants.SPDXFileExtension, osUtils.GetFileSystemStringComparisonType()))
{
throw new InvalidPathException($"The file at {path} is outside the root path {buildDropPath}.");
}
Expand Down
5 changes: 4 additions & 1 deletion src/Microsoft.Sbom.Api/Entities/ErrorType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,8 @@ public enum ErrorType
ManifestFileSigningError = 12,

[EnumMember(Value = "Invalid input file")]
InvalidInputFile = 13
InvalidInputFile = 13,

[EnumMember(Value = "Invalid manifest SPDX version")]
InvalidManifestVersion = 14
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Sbom.Api.Utils;
using Microsoft.Sbom.Common.Config;
using ApiConstants = Microsoft.Sbom.Api.Utils.Constants;

namespace Microsoft.Sbom.Api.Entities.Output;

Expand Down Expand Up @@ -72,8 +72,8 @@ public ValidationResult Build()
List<FileValidationResult> validationErrors;
List<FileValidationResult> skippedErrors;

validationErrors = NodeValidationResults.Where(r => !Constants.SkipFailureReportingForErrors.Contains(r.ErrorType)).ToList();
skippedErrors = NodeValidationResults.Where(r => Constants.SkipFailureReportingForErrors.Contains(r.ErrorType)).ToList();
validationErrors = NodeValidationResults.Where(r => !ApiConstants.SkipFailureReportingForErrors.Contains(r.ErrorType)).ToList();
skippedErrors = NodeValidationResults.Where(r => ApiConstants.SkipFailureReportingForErrors.Contains(r.ErrorType)).ToList();

if (configuration.IgnoreMissing.Value)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
using Microsoft.Sbom.Common;
using Microsoft.Sbom.Common.Config;
using Microsoft.Sbom.Extensions;
using Constants = Microsoft.Sbom.Api.Utils.Constants;
using ILogger = Serilog.ILogger;
using SpdxConstants = Microsoft.Sbom.Constants.SpdxConstants;

namespace Microsoft.Sbom.Api.Executors;

Expand Down Expand Up @@ -79,13 +79,19 @@ public ComponentDetectionBaseWalker(
cliArgumentBuilder.AddDetectorArg("SPDX22SBOM", "EnableIfDefaultOff");
cliArgumentBuilder.AddDetectorArg("ConanLock", "EnableIfDefaultOff");

if (sbomConfigs.TryGet(Constants.SPDX22ManifestInfo, out var spdxSbomConfig))
// Iterate over all supported SPDX manifests and apply the necessary logic. Break after we find one match, since we can only match the sbomConfig once.
foreach (var supportedSpdxManifest in SpdxConstants.SupportedSpdxManifests)
{
var directory = Path.GetDirectoryName(spdxSbomConfig.ManifestJsonFilePath);
directory = fileSystemUtils.GetFullPath(directory);
if (!string.IsNullOrEmpty(directory))
if (sbomConfigs.TryGet(supportedSpdxManifest, out var spdxSbomConfig))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably we can only match 1 config--should we break out of the loop after the first match?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure if the customer was allowed to pass in multiple manifests. Seems like the conclusion is that there is only matching manifest based on your comment and what I've seen in the rest of the code, so I'll add a break statement after a successful match

{
cliArgumentBuilder.AddArg("DirectoryExclusionList", directory);
var directory = Path.GetDirectoryName(spdxSbomConfig.ManifestJsonFilePath);
directory = fileSystemUtils.GetFullPath(directory);
if (!string.IsNullOrEmpty(directory))
{
cliArgumentBuilder.AddArg("DirectoryExclusionList", directory);
}

break;
}
}

Expand Down
25 changes: 25 additions & 0 deletions src/Microsoft.Sbom.Api/Executors/GenerationResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using System.Text.Json;
using Microsoft.Sbom.Api.Entities;
using Microsoft.Sbom.Extensions;

namespace Microsoft.Sbom.Api.Workflows.Helpers;

/// <summary>
/// Result from GenerateAsync
/// </summary>
public class GenerationResult
{
public List<FileValidationResult> Errors { get; set; }

public Dictionary<IManifestToolJsonSerializer, List<JsonDocument>> SerializerToJsonDocuments { get; set; }

public GenerationResult(List<FileValidationResult> errors, Dictionary<IManifestToolJsonSerializer, List<JsonDocument>> serializerToJsonDocuments)
{
Errors = errors;
SerializerToJsonDocuments = serializerToJsonDocuments;
}
}
Loading