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 BREAKING CHANGE: Remove back-compat interface shims #952

Merged
merged 4 commits into from
Mar 3, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 20 additions & 24 deletions src/Microsoft.Sbom.Api/Config/ConfigSanitizer.cs
Original file line number Diff line number Diff line change
@@ -78,32 +78,28 @@ public IConfiguration SanitizeConfig(IConfiguration configuration)
// Set default package supplier if not provided in configuration.
configuration.PackageSupplier = GetPackageSupplierFromAssembly(configuration, logger);

var configuration2 = configuration as IConfiguration2;
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
if (configuration.LicenseInformationTimeoutInSeconds is 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
if (configuration2.LicenseInformationTimeoutInSeconds is null)
{
configuration2.LicenseInformationTimeoutInSeconds = new(Common.Constants.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;
}
else if (configuration2.LicenseInformationTimeoutInSeconds.Value > Common.Constants.MaxLicenseFetchTimeoutInSeconds)
{
logger.Warning($"Specified timeout exceeds maximum allowed. Truncating the timeout to {Common.Constants.MaxLicenseFetchTimeoutInSeconds} seconds.");
configuration2.LicenseInformationTimeoutInSeconds.Value = Common.Constants.MaxLicenseFetchTimeoutInSeconds;
}
configuration.LicenseInformationTimeoutInSeconds = new(Common.Constants.DefaultLicenseFetchTimeoutInSeconds, SettingSource.Default);
}
else if (configuration.LicenseInformationTimeoutInSeconds.Value <= 0)
{
logger.Warning($"Negative and Zero Values not allowed for timeout. Using the default {Common.Constants.DefaultLicenseFetchTimeoutInSeconds} seconds instead.");
configuration.LicenseInformationTimeoutInSeconds.Value = Common.Constants.DefaultLicenseFetchTimeoutInSeconds;
}
else if (configuration.LicenseInformationTimeoutInSeconds.Value > Common.Constants.MaxLicenseFetchTimeoutInSeconds)
{
logger.Warning($"Specified timeout exceeds maximum allowed. Truncating the timeout to {Common.Constants.MaxLicenseFetchTimeoutInSeconds} seconds.");
configuration.LicenseInformationTimeoutInSeconds.Value = Common.Constants.MaxLicenseFetchTimeoutInSeconds;
}

// Check if arg -lto is specified but -li is not
if (configuration.FetchLicenseInformation?.Value != true && !configuration2.LicenseInformationTimeoutInSeconds.IsDefaultSource)
{
logger.Warning("A license fetching timeout is specified (argument -lto), but this has no effect when FetchLicenseInfo is unspecified or false (argument -li)");
}
// Check if arg -lto is specified but -li is not
if (configuration.FetchLicenseInformation?.Value != true && !configuration.LicenseInformationTimeoutInSeconds.IsDefaultSource)
{
logger.Warning("A license fetching timeout is specified (argument -lto), but this has no effect when FetchLicenseInfo is unspecified or false (argument -li)");
}

// Replace backslashes in directory paths with the OS-sepcific directory separator character.
Original file line number Diff line number Diff line change
@@ -144,22 +144,8 @@ async Task Scan(string path)
licenseInformationRetrieved = true;

List<string> apiResponses;
var licenseInformationFetcher2 = licenseInformationFetcher as ILicenseInformationFetcher2;
var licenseInformationTimeoutInSecondsConfigSetting = GetLicenseInformationTimeoutInSecondsSetting(configuration);

if (licenseInformationFetcher2 is null && (bool)!licenseInformationTimeoutInSecondsConfigSetting?.IsDefaultSource)
{
log.Warning("Timeout value is specified, but ILicenseInformationFetcher2 is not implemented for the licenseInformationFetcher");
}

if (licenseInformationFetcher2 is null || licenseInformationTimeoutInSecondsConfigSetting is null)
{
apiResponses = await licenseInformationFetcher.FetchLicenseInformationAsync(listOfComponentsForApi);
}
else
{
apiResponses = await licenseInformationFetcher2.FetchLicenseInformationAsync(listOfComponentsForApi, licenseInformationTimeoutInSecondsConfigSetting.Value);
}
apiResponses = await licenseInformationFetcher.FetchLicenseInformationAsync(listOfComponentsForApi, configuration.LicenseInformationTimeoutInSeconds.Value);

foreach (var response in apiResponses)
{
@@ -233,15 +219,4 @@ async Task Scan(string path)
}

protected abstract IEnumerable<ScannedComponent> FilterScannedComponents(ScanResult result);

private ConfigurationSetting<int>? GetLicenseInformationTimeoutInSecondsSetting(IConfiguration configuration)
{
var configuration2 = configuration as IConfiguration2;
if (configuration2 is not null)
{
return configuration2.LicenseInformationTimeoutInSeconds;
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -18,11 +18,12 @@ public interface ILicenseInformationFetcher
List<string> ConvertComponentsToListForApi(IEnumerable<ScannedComponent> scannedComponents);

/// <summary>
/// Calls the ClearlyDefined API to get the license information for the list of components. Uses a default timeout specified in implementation
/// Calls the ClearlyDefined API to get the license information for the list of components.
/// </summary>
/// <param name="listOfComponentsForApi"> A list of strings formatted into a list of strings that can be used to call the batch ClearlyDefined API.</param>
/// <param name="timeoutInSeconds">Timeout in seconds to use when making web requests. Caller owns sanitizing this value</param>
/// <returns></returns>
Task<List<string>> FetchLicenseInformationAsync(List<string> listOfComponentsForApi);
Task<List<string>> FetchLicenseInformationAsync(List<string> listOfComponentsForApi, int timeoutInSeconds);

/// <summary>
/// Gets the dictionary of licenses that were fetched from the ClearlyDefined API.
18 changes: 0 additions & 18 deletions src/Microsoft.Sbom.Api/Executors/ILicenseInformationFetcher2.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -8,5 +8,5 @@ namespace Microsoft.Sbom.Api.Executors;

public interface ILicenseInformationService
{
public Task<List<string>> FetchLicenseInformationFromAPI(List<string> listOfComponentsForApi);
public Task<List<string>> FetchLicenseInformationFromAPI(List<string> listOfComponentsForApi, int timeoutInSeconds);
}
12 changes: 0 additions & 12 deletions src/Microsoft.Sbom.Api/Executors/ILicenseInformationService2.cs

This file was deleted.

18 changes: 2 additions & 16 deletions src/Microsoft.Sbom.Api/Executors/LicenseInformationFetcher.cs
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@

namespace Microsoft.Sbom.Api.Executors;

public class LicenseInformationFetcher : ILicenseInformationFetcher2
public class LicenseInformationFetcher : ILicenseInformationFetcher
{
private readonly ILogger log;
private readonly IRecorder recorder;
@@ -82,23 +82,9 @@ public List<string> ConvertComponentsToListForApi(IEnumerable<ScannedComponent>
return listOfComponentsForApi;
}

public async Task<List<string>> FetchLicenseInformationAsync(List<string> listOfComponentsForApi)
{
return await licenseInformationService.FetchLicenseInformationFromAPI(listOfComponentsForApi);
}

public async Task<List<string>> FetchLicenseInformationAsync(List<string> listOfComponentsForApi, int timeoutInSeconds)
{
var licenseInformationService2 = licenseInformationService as ILicenseInformationService2;
if (licenseInformationService2 is null)
{
log.Warning("Timeout is specified in License Fetcher, but licenseInformationService does not implement ILicenseInformationService2");
return await licenseInformationService.FetchLicenseInformationFromAPI(listOfComponentsForApi);
}
else
{
return await licenseInformationService2.FetchLicenseInformationFromAPI(listOfComponentsForApi, timeoutInSeconds);
}
return await licenseInformationService.FetchLicenseInformationFromAPI(listOfComponentsForApi, timeoutInSeconds);
}

// Will attempt to extract license information from a clearlyDefined batch API response. Will always return a dictionary which may be empty depending on the response.
12 changes: 2 additions & 10 deletions src/Microsoft.Sbom.Api/Executors/LicenseInformationService.cs
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@

namespace Microsoft.Sbom.Api.Executors;

public class LicenseInformationService : ILicenseInformationService2
public class LicenseInformationService : ILicenseInformationService
{
private readonly ILogger log;
private readonly IRecorder recorder;
@@ -28,11 +28,6 @@ public LicenseInformationService(ILogger log, IRecorder recorder, HttpClient htt
this.httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
}

public async Task<List<string>> FetchLicenseInformationFromAPI(List<string> listOfComponentsForApi)
{
return await FetchLicenseInformationFromAPI(listOfComponentsForApi, Common.Constants.MaxLicenseFetchTimeoutInSeconds);
}

public async Task<List<string>> FetchLicenseInformationFromAPI(List<string> listOfComponentsForApi, int timeoutInSeconds)
{
var batchSize = 500;
@@ -42,10 +37,7 @@ public async Task<List<string>> FetchLicenseInformationFromAPI(List<string> list
var uri = new Uri("https://api.clearlydefined.io/definitions?expand=-files");

httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
if (timeoutInSeconds > 0)
{
httpClient.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
} // The else cases should be sanitized in Config Sanitizer, and even if not, it'll just use httpClient's default timeout
httpClient.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);

for (var i = 0; i < listOfComponentsForApi.Count; i += batchSize)
{
6 changes: 3 additions & 3 deletions src/Microsoft.Sbom.Common/Config/Configuration.cs
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ namespace Microsoft.Sbom.Common.Config;

[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1311:Static readonly fields should begin with upper-case letter", Justification = "Private fields with the same name as public properties.")]
[SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "This is the configuration class")]
public class Configuration : IConfiguration2
public class Configuration : IConfiguration
{
private static readonly AsyncLocal<ConfigurationSetting<string>> buildDropPath = new();
private static readonly AsyncLocal<ConfigurationSetting<string>> buildComponentPath = new();
@@ -47,7 +47,7 @@ public class Configuration : IConfiguration2
private static readonly AsyncLocal<ConfigurationSetting<string>> generationTimestamp = new();
private static readonly AsyncLocal<ConfigurationSetting<bool>> followSymlinks = new();
private static readonly AsyncLocal<ConfigurationSetting<bool>> fetchLicenseInformation = new();
private static readonly AsyncLocal<ConfigurationSetting<int>> licenseInformationTimeout = new(); // IConfiguration2
private static readonly AsyncLocal<ConfigurationSetting<int>> licenseInformationTimeout = new();
private static readonly AsyncLocal<ConfigurationSetting<bool>> enablePackageMetadataParsing = new();
private static readonly AsyncLocal<ConfigurationSetting<bool>> deleteManifestDirIfPresent = new();
private static readonly AsyncLocal<ConfigurationSetting<bool>> failIfNoPackages = new();
@@ -311,7 +311,7 @@ public ConfigurationSetting<bool> FetchLicenseInformation
set => fetchLicenseInformation.Value = value;
}

/// <inheritdoc cref="IConfiguration2.LicenseInformationTimeoutInSeconds" />
/// <inheritdoc cref="IConfiguration.LicenseInformationTimeoutInSeconds" />
[DefaultValue(Constants.DefaultLicenseFetchTimeoutInSeconds)]
public ConfigurationSetting<int> LicenseInformationTimeoutInSeconds
{
6 changes: 6 additions & 0 deletions src/Microsoft.Sbom.Common/Config/IConfiguration.cs
Original file line number Diff line number Diff line change
@@ -212,4 +212,10 @@ public interface IConfiguration
/// The compliance standard to validate against.
/// </summary>
ConfigurationSetting<string> ComplianceStandard { get; set; }

/// Specifies the timeout in seconds for fetching the license information. Defaults to <see cref="Constants.DefaultLicenseFetchTimeoutInSeconds"/>.
/// Has no effect if FetchLicenseInformation (li) argument is false or not provided. Negative values are set to the default and values exceeding the
/// maximum are truncated to <see cref="Constants.MaxLicenseFetchTimeoutInSeconds"/>
/// </summary>
ConfigurationSetting<int> LicenseInformationTimeoutInSeconds { get; set; }
}
19 changes: 0 additions & 19 deletions src/Microsoft.Sbom.Common/Config/IConfiguration2.cs

This file was deleted.

4 changes: 2 additions & 2 deletions src/Microsoft.Sbom.Common/Config/InputConfiguration.cs
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
namespace Microsoft.Sbom.Common.Config;

[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1311:Static readonly fields should begin with upper-case letter", Justification = "Private fields with the same name as public properties.")]
public class InputConfiguration : IConfiguration2
public class InputConfiguration : IConfiguration
{
/// <inheritdoc cref="IConfiguration.BuildDropPath" />
[DirectoryExists]
@@ -141,7 +141,7 @@ public class InputConfiguration : IConfiguration2
[DefaultValue(false)]
public ConfigurationSetting<bool> FetchLicenseInformation { get; set; }

/// <inheritdoc cref="IConfiguration2.LicenseInformationTimeoutInSeconds" />
/// <inheritdoc cref="IConfiguration.LicenseInformationTimeoutInSeconds" />
[DefaultValue(Constants.DefaultLicenseFetchTimeoutInSeconds)]
public ConfigurationSetting<int> LicenseInformationTimeoutInSeconds { get; set; }

Original file line number Diff line number Diff line change
@@ -75,14 +75,14 @@ private class PinnedILicenseInformationFetcher : ILicenseInformationFetcher
public void AppendLicensesToDictionary(Dictionary<string, string> partialLicenseDictionary) => throw new NotImplementedException();
public Dictionary<string, string> ConvertClearlyDefinedApiResponseToList(string httpResponseContent) => throw new NotImplementedException();
public List<string> ConvertComponentsToListForApi(IEnumerable<ScannedComponent> scannedComponents) => throw new NotImplementedException();
public Task<List<string>> FetchLicenseInformationAsync(List<string> listOfComponentsForApi) => throw new NotImplementedException();
public Task<List<string>> FetchLicenseInformationAsync(List<string> listOfComponentsForApi, int timeoutInSeconds) => throw new NotImplementedException();
public string GetFromLicenseDictionary(string key) => throw new NotImplementedException();
public ConcurrentDictionary<string, string> GetLicenseDictionary() => throw new NotImplementedException();
}

private class PinnedILicenstInformationSErvice : ILicenseInformationService
private class PinnedILicenstInformationService : ILicenseInformationService
{
public Task<List<string>> FetchLicenseInformationFromAPI(List<string> listOfComponentsForApi) => throw new NotImplementedException();
public Task<List<string>> FetchLicenseInformationFromAPI(List<string> listOfComponentsForApi, int timeoutInSeconds) => throw new NotImplementedException();
}

private class Pinned_SBOMReaderForExternalDocumentReference : ISbomReaderForExternalDocumentReference
@@ -330,6 +330,7 @@ private class PinnedIConfiguration : IConfiguration
public ConfigurationSetting<string> SbomPath { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public ConfigurationSetting<string> SbomDir { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public ConfigurationSetting<string> ComplianceStandard { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public ConfigurationSetting<int> LicenseInformationTimeoutInSeconds { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
}

private class PinnedISettingSourceable : ISettingSourceable