refactor: migrate away from MEF to Dependency Injection (#412)

This commit is contained in:
Jamie Magee 2023-02-14 09:33:07 -08:00 коммит произвёл GitHub
Родитель 80318142b0
Коммит f6912c0258
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
119 изменённых файлов: 1559 добавлений и 2080 удалений

Просмотреть файл

@ -671,3 +671,7 @@ dotnet_diagnostic.CA1854.severity = suggestion
# JSON002: Probable JSON string detected
dotnet_diagnostic.JSON002.severity = suggestion
# Workaround for https://github.com/dotnet/roslyn-analyzers/issues/5628
[Program.cs]
dotnet_diagnostic.ca1812.severity = none

Просмотреть файл

@ -32,11 +32,6 @@
<PackageVersion Include="Polly" Version="7.2.3"/>
<PackageVersion Include="Semver" Version="2.2.0"/>
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.435"/>
<PackageVersion Include="System.Composition.AttributedModel" Version="7.0.0"/>
<PackageVersion Include="System.Composition.Convention" Version="7.0.0"/>
<PackageVersion Include="System.Composition.Hosting" Version="7.0.0"/>
<PackageVersion Include="System.Composition.Runtime" Version="7.0.0"/>
<PackageVersion Include="System.Composition.TypedParts" Version="7.0.0"/>
<PackageVersion Include="System.Memory" Version="4.5.5"/>
<PackageVersion Include="System.Reactive" Version="5.0.0"/>
<PackageVersion Include="System.Runtime.Loader" Version="4.3.0"/>

Просмотреть файл

@ -3,7 +3,6 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Composition;
using System.Diagnostics;
using System.IO;
using System.Linq;
@ -11,7 +10,6 @@ using System.Threading.Tasks;
using Microsoft.ComponentDetection.Common.Telemetry.Records;
using Microsoft.ComponentDetection.Contracts;
[Export(typeof(ICommandLineInvocationService))]
public class CommandLineInvocationService : ICommandLineInvocationService
{
private readonly IDictionary<string, string> commandLocatableCache = new ConcurrentDictionary<string, string>();

Просмотреть файл

@ -1,29 +1,29 @@
namespace Microsoft.ComponentDetection.Common;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using Microsoft.ComponentDetection.Contracts;
[Export(typeof(IComponentStreamEnumerableFactory))]
[Shared]
public class ComponentStreamEnumerableFactory : IComponentStreamEnumerableFactory
{
[Import]
public ILogger Logger { get; set; }
private readonly IPathUtilityService pathUtilityService;
private readonly ILogger logger;
[Import]
public IPathUtilityService PathUtilityService { get; set; }
public ComponentStreamEnumerableFactory(IPathUtilityService pathUtilityService, ILogger logger)
{
this.pathUtilityService = pathUtilityService;
this.logger = logger;
}
public IEnumerable<IComponentStream> GetComponentStreams(DirectoryInfo directory, IEnumerable<string> searchPatterns, ExcludeDirectoryPredicate directoryExclusionPredicate, bool recursivelyScanDirectories = true)
{
var enumerable = new SafeFileEnumerable(directory, searchPatterns, this.Logger, this.PathUtilityService, directoryExclusionPredicate, recursivelyScanDirectories);
return new ComponentStreamEnumerable(enumerable, this.Logger);
var enumerable = new SafeFileEnumerable(directory, searchPatterns, this.logger, this.pathUtilityService, directoryExclusionPredicate, recursivelyScanDirectories);
return new ComponentStreamEnumerable(enumerable, this.logger);
}
public IEnumerable<IComponentStream> GetComponentStreams(DirectoryInfo directory, Func<FileInfo, bool> fileMatchingPredicate, ExcludeDirectoryPredicate directoryExclusionPredicate, bool recursivelyScanDirectories = true)
{
var enumerable = new SafeFileEnumerable(directory, fileMatchingPredicate, this.Logger, this.PathUtilityService, directoryExclusionPredicate, recursivelyScanDirectories);
return new ComponentStreamEnumerable(enumerable, this.Logger);
var enumerable = new SafeFileEnumerable(directory, fileMatchingPredicate, this.logger, this.pathUtilityService, directoryExclusionPredicate, recursivelyScanDirectories);
return new ComponentStreamEnumerable(enumerable, this.logger);
}
}

Просмотреть файл

@ -1,8 +1,6 @@
namespace Microsoft.ComponentDetection.Common;
namespace Microsoft.ComponentDetection.Common;
using System;
using System.Composition;
[Export(typeof(IConsoleWritingService))]
public class ConsoleWritingService : IConsoleWritingService
{
public void Write(string content)

Просмотреть файл

@ -1,31 +0,0 @@
namespace Microsoft.ComponentDetection.Common;
using System.Composition;
using Microsoft.ComponentDetection.Contracts;
[Export(typeof(IDetectorDependencies))]
public class DetectorDependencies : IDetectorDependencies
{
[Import]
public ILogger Logger { get; set; }
[Import]
public IComponentStreamEnumerableFactory ComponentStreamEnumerableFactory { get; set; }
[Import]
public IPathUtilityService PathUtilityService { get; set; }
[Import]
public ICommandLineInvocationService CommandLineInvocationService { get; set; }
[Import]
public IFileUtilityService FileUtilityService { get; set; }
[Import]
public IObservableDirectoryWalkerFactory DirectoryWalkerFactory { get; set; }
[Import]
public IDockerService DockerService { get; set; }
[Import]
public IEnvironmentVariableService EnvironmentVariableService { get; set; }
}

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Common;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Threading;
@ -13,7 +12,6 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.BcdeModels;
using Newtonsoft.Json;
[Export(typeof(IDockerService))]
public class DockerService : IDockerService
{
// Base image annotations from ADO dockerTask
@ -23,8 +21,9 @@ public class DockerService : IDockerService
private static readonly DockerClient Client = new DockerClientConfiguration().CreateClient();
private static int incrementingContainerId;
[Import]
public ILogger Logger { get; set; }
private readonly ILogger logger;
public DockerService(ILogger logger) => this.logger = logger;
public async Task<bool> CanPingDockerAsync(CancellationToken cancellationToken = default)
{
@ -35,7 +34,7 @@ public class DockerService : IDockerService
}
catch (Exception e)
{
this.Logger.LogException(e, false);
this.logger.LogException(e, false);
return false;
}
}

Просмотреть файл

@ -1,10 +1,8 @@
namespace Microsoft.ComponentDetection.Common;
using System;
using System.Composition;
using System.Linq;
using Microsoft.ComponentDetection.Contracts;
[Export(typeof(IEnvironmentVariableService))]
public class EnvironmentVariableService : IEnvironmentVariableService
{
public bool DoesEnvironmentVariableExist(string name)

Просмотреть файл

@ -2,7 +2,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Composition;
using System.Diagnostics;
using System.IO;
using System.IO.Enumeration;
@ -14,18 +13,17 @@ using System.Threading.Tasks.Dataflow;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
[Export(typeof(IObservableDirectoryWalkerFactory))]
[Export(typeof(FastDirectoryWalkerFactory))]
[Shared]
public class FastDirectoryWalkerFactory : IObservableDirectoryWalkerFactory
{
private readonly ConcurrentDictionary<DirectoryInfo, Lazy<IObservable<FileSystemInfo>>> pendingScans = new ConcurrentDictionary<DirectoryInfo, Lazy<IObservable<FileSystemInfo>>>();
private readonly IPathUtilityService pathUtilityService;
private readonly ILogger logger;
[Import]
public ILogger Logger { get; set; }
[Import]
public IPathUtilityService PathUtilityService { get; set; }
public FastDirectoryWalkerFactory(IPathUtilityService pathUtilityService, ILogger logger)
{
this.pathUtilityService = pathUtilityService;
this.logger = logger;
}
public IObservable<FileSystemInfo> GetDirectoryScanner(DirectoryInfo root, ConcurrentDictionary<string, bool> scannedDirectories, ExcludeDirectoryPredicate directoryExclusionPredicate, IEnumerable<string> filePatterns = null, bool recurse = true)
{
@ -33,7 +31,7 @@ public class FastDirectoryWalkerFactory : IObservableDirectoryWalkerFactory
{
if (!root.Exists)
{
this.Logger?.LogError($"Root directory doesn't exist: {root.FullName}");
this.logger?.LogError($"Root directory doesn't exist: {root.FullName}");
s.OnCompleted();
return Task.CompletedTask;
}
@ -51,7 +49,7 @@ public class FastDirectoryWalkerFactory : IObservableDirectoryWalkerFactory
var sw = Stopwatch.StartNew();
this.Logger?.LogInfo($"Starting enumeration of {root.FullName}");
this.logger?.LogInfo($"Starting enumeration of {root.FullName}");
var fileCount = 0;
var directoryCount = 0;
@ -72,7 +70,7 @@ public class FastDirectoryWalkerFactory : IObservableDirectoryWalkerFactory
if (di.Attributes.HasFlag(FileAttributes.ReparsePoint))
{
var realPath = this.PathUtilityService.ResolvePhysicalPath(di.FullName);
var realPath = this.pathUtilityService.ResolvePhysicalPath(di.FullName);
realDirectory = new DirectoryInfo(realPath);
}
@ -189,7 +187,7 @@ public class FastDirectoryWalkerFactory : IObservableDirectoryWalkerFactory
() =>
{
sw.Stop();
this.Logger?.LogInfo($"Enumerated {fileCount} files and {directoryCount} directories in {sw.Elapsed}");
this.logger?.LogInfo($"Enumerated {fileCount} files and {directoryCount} directories in {sw.Elapsed}");
s.OnCompleted();
});
});
@ -213,7 +211,7 @@ public class FastDirectoryWalkerFactory : IObservableDirectoryWalkerFactory
if (this.pendingScans.TryGetValue(root, out var scannerObservable))
{
this.Logger.LogVerbose(string.Join(":", patterns));
this.logger.LogVerbose(string.Join(":", patterns));
var inner = scannerObservable.Value.Where(fsi =>
{
@ -244,11 +242,11 @@ public class FastDirectoryWalkerFactory : IObservableDirectoryWalkerFactory
var searchPattern = x.SearchPattern;
var fileName = x.File.Name;
return this.PathUtilityService.MatchesPattern(searchPattern, fileName);
return this.pathUtilityService.MatchesPattern(searchPattern, fileName);
}).Where(x => x.File.Exists)
.Select(x =>
{
var lazyComponentStream = new LazyComponentStream(x.File, x.SearchPattern, this.Logger);
var lazyComponentStream = new LazyComponentStream(x.File, x.SearchPattern, this.logger);
return new ProcessRequest
{
ComponentStream = lazyComponentStream,
@ -287,6 +285,6 @@ public class FastDirectoryWalkerFactory : IObservableDirectoryWalkerFactory
private bool MatchesAnyPattern(FileInfo fi, params string[] searchPatterns)
{
return searchPatterns != null && searchPatterns.Any(sp => this.PathUtilityService.MatchesPattern(sp, fi.Name));
return searchPatterns != null && searchPatterns.Any(sp => this.pathUtilityService.MatchesPattern(sp, fi.Name));
}
}

Просмотреть файл

@ -1,14 +1,10 @@
namespace Microsoft.ComponentDetection.Common;
using System.Composition;
namespace Microsoft.ComponentDetection.Common;
using System.IO;
using Microsoft.ComponentDetection.Contracts;
/// <summary>
/// Wraps some common file operations for easier testability. This interface is *only used by the command line driven app*.
/// </summary>
[Export(typeof(IFileUtilityService))]
[Export(typeof(FileUtilityService))]
[Shared]
public class FileUtilityService : IFileUtilityService
{
public string ReadAllText(string filePath)

Просмотреть файл

@ -1,12 +1,8 @@
namespace Microsoft.ComponentDetection.Common;
namespace Microsoft.ComponentDetection.Common;
using System;
using System.Composition;
using System.IO;
using Microsoft.ComponentDetection.Common.Exceptions;
[Export(typeof(IFileWritingService))]
[Export(typeof(FileWritingService))]
[Shared]
public class FileWritingService : IFileWritingService
{
public const string TimestampFormatString = "yyyyMMddHHmmssfff";

Просмотреть файл

@ -4,6 +4,8 @@ using System.IO;
// All file paths are relative and will replace occurrences of {timestamp} with the shared file timestamp.
public interface IFileWritingService
{
void Init(string basePath);
void AppendToFile(string relativeFilePath, string text);
void WriteFile(string relativeFilePath, string text);

Просмотреть файл

@ -1,24 +1,23 @@
namespace Microsoft.ComponentDetection.Common;
namespace Microsoft.ComponentDetection.Common;
using System;
using System.Composition;
using System.Runtime.CompilerServices;
using Microsoft.ComponentDetection.Common.Telemetry.Records;
using Microsoft.ComponentDetection.Contracts;
using static System.Environment;
[Export(typeof(ILogger))]
[Export(typeof(Logger))]
[Shared]
public class Logger : ILogger
{
public const string LogRelativePath = "GovCompDisc_Log_{timestamp}.log";
[Import]
public IFileWritingService FileWritingService { get; set; }
private readonly IConsoleWritingService consoleWriter;
private readonly IFileWritingService fileWritingService;
[Import]
public IConsoleWritingService ConsoleWriter { get; set; }
public Logger(IConsoleWritingService consoleWriter, IFileWritingService fileWritingService)
{
this.consoleWriter = consoleWriter;
this.fileWritingService = fileWritingService;
}
private VerbosityMode Verbosity { get; set; }
@ -33,8 +32,8 @@ public class Logger : ILogger
this.WriteLinePrefix = writeLinePrefix;
try
{
this.FileWritingService.WriteFile(LogRelativePath, string.Empty);
this.LogInfo($"Log file: {this.FileWritingService.ResolveFilePath(LogRelativePath)}");
this.fileWritingService.WriteFile(LogRelativePath, string.Empty);
this.LogInfo($"Log file: {this.fileWritingService.ResolveFilePath(LogRelativePath)}");
}
catch (Exception)
{
@ -132,7 +131,7 @@ public class Logger : ILogger
{
if (this.WriteToFile)
{
this.FileWritingService.AppendToFile(LogRelativePath, text);
this.fileWritingService.AppendToFile(LogRelativePath, text);
}
}
@ -140,7 +139,7 @@ public class Logger : ILogger
{
if (this.Verbosity >= minVerbosity)
{
this.ConsoleWriter.Write(text);
this.consoleWriter.Write(text);
}
}

Просмотреть файл

@ -5,11 +5,6 @@
<PackageReference Include="Microsoft.AspNet.WebApi.Client" />
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="Semver" />
<PackageReference Include="System.Composition.AttributedModel" />
<PackageReference Include="System.Composition.Convention" />
<PackageReference Include="System.Composition.Hosting" />
<PackageReference Include="System.Composition.Runtime" />
<PackageReference Include="System.Composition.TypedParts" />
<PackageReference Include="System.Reactive" />
<PackageReference Include="System.Threading.Tasks.Dataflow" />
</ItemGroup>

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Common;
using System;
using System.Collections.Concurrent;
using System.Composition;
using System.Diagnostics;
using System.IO;
using System.IO.Enumeration;
@ -11,9 +10,6 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.Win32.SafeHandles;
// We may want to consider breaking this class into Win/Mac/Linux variants if it gets bigger
[Export(typeof(IPathUtilityService))]
[Export(typeof(PathUtilityService))]
[Shared]
public class PathUtilityService : IPathUtilityService
{
public const uint CreationDispositionRead = 0x3;
@ -30,9 +26,17 @@ public class PathUtilityService : IPathUtilityService
private readonly ConcurrentDictionary<string, string> resolvedPaths = new ConcurrentDictionary<string, string>();
private readonly ILogger logger;
private readonly object isRunningOnWindowsContainerLock = new object();
private bool? isRunningOnWindowsContainer;
public PathUtilityService()
{
}
public PathUtilityService(ILogger logger) => this.logger = logger;
public bool IsRunningOnWindowsContainer
{
get
@ -52,9 +56,6 @@ public class PathUtilityService : IPathUtilityService
}
}
[Import]
public ILogger Logger { get; set; }
/// <summary>
/// This call can be made on a linux system to get the absolute path of a file. It will resolve nested layers.
/// Note: You may pass IntPtr.Zero to the output parameter. You MUST then free the IntPtr that RealPathLinux returns
@ -221,7 +222,7 @@ public class PathUtilityService : IPathUtilityService
}
catch (Exception ex)
{
this.Logger.LogException(ex, isError: false, printException: true);
this.logger.LogException(ex, isError: false, printException: true);
return path;
}
finally
@ -283,7 +284,7 @@ public class PathUtilityService : IPathUtilityService
if (sb.ToString().Contains("Container Execution Agent"))
{
this.Logger.LogWarning("Detected execution in a Windows container. Currently windows containers < 1809 do not support symlinks well, so disabling symlink resolution/dedupe behavior");
this.logger.LogWarning("Detected execution in a Windows container. Currently windows containers < 1809 do not support symlinks well, so disabling symlink resolution/dedupe behavior");
return true;
}
else

Просмотреть файл

@ -1,21 +1,25 @@
namespace Microsoft.ComponentDetection.Common;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using Microsoft.ComponentDetection.Contracts;
[Export(typeof(ISafeFileEnumerableFactory))]
[Shared]
public class SafeFileEnumerableFactory : ISafeFileEnumerableFactory
{
[Import]
public ILogger Logger { get; set; }
private readonly IPathUtilityService pathUtilityService;
private readonly ILogger logger;
[Import]
public IPathUtilityService PathUtilityService { get; set; }
public SafeFileEnumerableFactory()
{
}
public SafeFileEnumerableFactory(IPathUtilityService pathUtilityService, ILogger logger)
{
this.pathUtilityService = pathUtilityService;
this.logger = logger;
}
public IEnumerable<MatchedFile> CreateSafeFileEnumerable(DirectoryInfo directory, IEnumerable<string> searchPatterns, ExcludeDirectoryPredicate directoryExclusionPredicate)
{
return new SafeFileEnumerable(directory, searchPatterns, this.Logger, this.PathUtilityService, directoryExclusionPredicate);
return new SafeFileEnumerable(directory, searchPatterns, this.logger, this.pathUtilityService, directoryExclusionPredicate);
}
}

Просмотреть файл

@ -1,10 +0,0 @@
namespace Microsoft.ComponentDetection.Common.Telemetry.Attributes;
using System;
[AttributeUsage(AttributeTargets.Class)]
public sealed class TelemetryServiceAttribute : Attribute
{
public TelemetryServiceAttribute(string serviceType) => this.ServiceType = serviceType;
public string ServiceType { get; }
}

Просмотреть файл

@ -1,32 +1,31 @@
namespace Microsoft.ComponentDetection.Common.Telemetry;
using System;
using System.Collections.Concurrent;
using System.Composition;
using Microsoft.ComponentDetection.Common.Telemetry.Attributes;
using Microsoft.ComponentDetection.Common.Telemetry.Records;
using Microsoft.ComponentDetection.Contracts;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
[Export(typeof(ITelemetryService))]
[TelemetryService(nameof(CommandLineTelemetryService))]
internal class CommandLineTelemetryService : ITelemetryService
{
private static readonly ConcurrentQueue<JObject> Records = new ConcurrentQueue<JObject>();
public const string TelemetryRelativePath = "ScanTelemetry_{timestamp}.json";
private readonly IFileWritingService fileWritingService;
private readonly ILogger logger;
private TelemetryMode telemetryMode = TelemetryMode.Production;
[Import]
public ILogger Logger { get; set; }
[Import]
public IFileWritingService FileWritingService { get; set; }
public CommandLineTelemetryService(ILogger logger, IFileWritingService fileWritingService)
{
this.logger = logger;
this.fileWritingService = fileWritingService;
}
public void Flush()
{
this.FileWritingService.WriteFile(TelemetryRelativePath, JsonConvert.SerializeObject(Records));
this.fileWritingService.WriteFile(TelemetryRelativePath, JsonConvert.SerializeObject(Records));
}
public void PostRecord(IDetectionTelemetryRecord record)
@ -41,7 +40,7 @@ internal class CommandLineTelemetryService : ITelemetryService
if (this.telemetryMode == TelemetryMode.Debug)
{
this.Logger.LogInfo(jsonRecord.ToString());
this.logger.LogInfo(jsonRecord.ToString());
}
}
}

Просмотреть файл

@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -13,12 +12,11 @@ using Microsoft.ComponentDetection.Common.Telemetry.Records;
/// </summary>
public sealed class TelemetryRelay
{
private IEnumerable<ITelemetryService> telemetryServices;
// For things not populating the telemetry services collection, let's not throw.
private TelemetryRelay() =>
TelemetryServices = Enumerable.Empty<ITelemetryService>();
[ImportMany]
public static IEnumerable<ITelemetryService> TelemetryServices { get; set; }
this.telemetryServices = Enumerable.Empty<ITelemetryService>();
/// <summary>
/// Gets a value indicating whether or not the telemetry relay has been shutdown.
@ -30,13 +28,15 @@ public sealed class TelemetryRelay
/// </summary>
public static TelemetryRelay Instance { get; } = new TelemetryRelay();
public void Init(IEnumerable<ITelemetryService> telemetryServices) => this.telemetryServices = telemetryServices;
/// <summary>
/// Post a given telemetry record to all telemetry services.
/// </summary>
/// <param name="record">Record to post. </param>
public void PostTelemetryRecord(IDetectionTelemetryRecord record)
{
foreach (var service in TelemetryServices)
foreach (var service in this.telemetryServices)
{
try
{
@ -57,7 +57,7 @@ public sealed class TelemetryRelay
{
Active = false;
foreach (var service in TelemetryServices)
foreach (var service in this.telemetryServices)
{
try
{
@ -76,7 +76,7 @@ public sealed class TelemetryRelay
public void SetTelemetryMode(TelemetryMode mode)
{
foreach (var telemetryService in TelemetryServices ?? Enumerable.Empty<ITelemetryService>())
foreach (var telemetryService in this.telemetryServices ?? Enumerable.Empty<ITelemetryService>())
{
telemetryService.SetMode(mode);
}

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Contracts;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Reactive.Linq;
using System.Threading.Tasks;
@ -13,14 +12,16 @@ using Microsoft.ComponentDetection.Contracts.TypedComponent;
public abstract class FileComponentDetector : IComponentDetector
{
/// <summary>
/// Gets or sets the factory for handing back component streams to File detectors. Injected automatically by MEF composition.
/// Gets or sets the factory for handing back component streams to File detectors.
/// </summary>
[Import]
public IComponentStreamEnumerableFactory ComponentStreamEnumerableFactory { get; set; }
protected IComponentStreamEnumerableFactory ComponentStreamEnumerableFactory { get; set; }
/// <summary>Gets or sets the logger for writing basic logging message to both console and file. Injected automatically by MEF composition.</summary>
[Import]
public ILogger Logger { get; set; }
protected IObservableDirectoryWalkerFactory Scanner { get; set; }
/// <summary>
/// Gets or sets the logger for writing basic logging message to both console and file.
/// </summary>
protected ILogger Logger { get; set; }
public IComponentRecorder ComponentRecorder { get; private set; }
@ -50,9 +51,6 @@ public abstract class FileComponentDetector : IComponentDetector
/// </summary>
protected ScanRequest CurrentScanRequest { get; set; }
[Import]
public IObservableDirectoryWalkerFactory Scanner { get; set; }
public bool NeedsAutomaticRootDependencyCalculation { get; protected set; }
protected Dictionary<string, string> Telemetry { get; set; } = new Dictionary<string, string>();

Просмотреть файл

@ -1,20 +0,0 @@
namespace Microsoft.ComponentDetection.Contracts;
public interface IDetectorDependencies
{
ILogger Logger { get; set; }
IComponentStreamEnumerableFactory ComponentStreamEnumerableFactory { get; set; }
IPathUtilityService PathUtilityService { get; set; }
ICommandLineInvocationService CommandLineInvocationService { get; set; }
IFileUtilityService FileUtilityService { get; set; }
IObservableDirectoryWalkerFactory DirectoryWalkerFactory { get; set; }
IDockerService DockerService { get; set; }
IEnvironmentVariableService EnvironmentVariableService { get; set; }
}

Просмотреть файл

@ -5,6 +5,8 @@ using System.Runtime.CompilerServices;
/// <summary>Simple abstraction around console/output file logging for component detection.</summary>
public interface ILogger
{
void Init(VerbosityMode verbosity, bool writeLinePrefix = true);
/// <summary>Creates a logical separation (e.g. newline) between different log messages.</summary>
void LogCreateLoggingGroup();

Просмотреть файл

@ -1,64 +0,0 @@
using System.Composition;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.ComponentDetection.Orchestrator")]
namespace Microsoft.ComponentDetection.Contracts.Internal;
// Why do we have this weird garbage code?
// Because https://github.com/dotnet/corefx/issues/11856
// This ugly file is here mostly because we don't have a way to easily expose instances to our composed detectors (NetStandard MEF hasn't received the love).
// It needs to live in the Contracts project to isolate part discovery to a different assembly.
// It also makes a little bit of sense because everything that IComponentDetectors can inject is in this file :).
internal class InjectionParameters
{
private static ILogger loggerStatic;
private static IComponentStreamEnumerableFactory factoryStatic;
private static IPathUtilityService pathUtilityServiceStatic;
private static ICommandLineInvocationService commandLineInvocationServiceStatic;
private static IFileUtilityService fileUtilityServiceStatic;
private static IObservableDirectoryWalkerFactory observableDirectoryWalkerFactoryServiceStatic;
private static IDockerService dockerServiceStatic;
private static IEnvironmentVariableService environmentVariableServiceStatic;
public InjectionParameters()
{
}
internal InjectionParameters(IDetectorDependencies detectorDependencies)
{
loggerStatic = detectorDependencies.Logger;
factoryStatic = detectorDependencies.ComponentStreamEnumerableFactory;
pathUtilityServiceStatic = detectorDependencies.PathUtilityService;
commandLineInvocationServiceStatic = detectorDependencies.CommandLineInvocationService;
fileUtilityServiceStatic = detectorDependencies.FileUtilityService;
observableDirectoryWalkerFactoryServiceStatic = detectorDependencies.DirectoryWalkerFactory;
dockerServiceStatic = detectorDependencies.DockerService;
environmentVariableServiceStatic = detectorDependencies.EnvironmentVariableService;
}
[Export(typeof(ILogger))]
public ILogger Logger => loggerStatic;
[Export(typeof(IComponentStreamEnumerableFactory))]
public IComponentStreamEnumerableFactory Factory => factoryStatic;
[Export(typeof(IPathUtilityService))]
public IPathUtilityService PathUtilityService => pathUtilityServiceStatic;
[Export(typeof(ICommandLineInvocationService))]
public ICommandLineInvocationService CommandLineInvocationService => commandLineInvocationServiceStatic;
[Export(typeof(IFileUtilityService))]
public IFileUtilityService FileUtilityService => fileUtilityServiceStatic;
[Export(typeof(IObservableDirectoryWalkerFactory))]
public IObservableDirectoryWalkerFactory ObservableDirectoryWalkerFactory => observableDirectoryWalkerFactoryServiceStatic;
[Export(typeof(IDockerService))]
public IDockerService DockerService => dockerServiceStatic;
[Export(typeof(IEnvironmentVariableService))]
public IEnvironmentVariableService EnvironmentVariableService => environmentVariableServiceStatic;
}

Просмотреть файл

@ -7,7 +7,6 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json"/>
<PackageReference Include="packageurl-dotnet"/>
<PackageReference Include="System.Composition.AttributedModel"/>
<PackageReference Include="System.Memory"/>
<PackageReference Include="System.Reactive"/>
<PackageReference Include="System.Threading.Tasks.Dataflow"/>

Просмотреть файл

@ -1,4 +1,4 @@
namespace Microsoft.ComponentDetection.Common;
namespace Microsoft.ComponentDetection.Contracts;
public enum VerbosityMode
{

Просмотреть файл

@ -1,9 +0,0 @@
namespace Microsoft.ComponentDetection.Detectors;
/// <summary>
/// This type is used to find this assembly.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1040:Avoid empty interfaces", Justification = "This type is used to find this assembly.")]
public interface IComponentGovernanceOwnedDetectors
{
}

Просмотреть файл

@ -10,11 +10,6 @@
<PackageReference Include="yamldotnet" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" />
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="System.Composition.AttributedModel" />
<PackageReference Include="System.Composition.Convention" />
<PackageReference Include="System.Composition.Hosting" />
<PackageReference Include="System.Composition.Runtime" />
<PackageReference Include="System.Composition.TypedParts" />
<PackageReference Include="System.Reactive" />
<PackageReference Include="System.Threading.Tasks.Dataflow" />
<PackageReference Include="Tomlyn"/>

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.CocoaPods;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -13,9 +12,18 @@ using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
[Export(typeof(IComponentDetector))]
public class PodComponentDetector : FileComponentDetector
{
public PodComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.Logger = logger;
}
public override string Id { get; } = "CocoaPods";
public override IEnumerable<string> Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.CocoaPods) };

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Dockerfile;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -12,14 +11,24 @@ using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Valleysoft.DockerfileModel;
[Export(typeof(IComponentDetector))]
public class DockerfileComponentDetector : FileComponentDetector, IDefaultOffComponentDetector
{
[Import]
public ICommandLineInvocationService CommandLineInvocationService { get; set; }
private readonly ICommandLineInvocationService commandLineInvocationService;
private readonly IEnvironmentVariableService envVarService;
[Import]
public IEnvironmentVariableService EnvVarService { get; set; }
public DockerfileComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ICommandLineInvocationService commandLineInvocationService,
IEnvironmentVariableService envVarService,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.commandLineInvocationService = commandLineInvocationService;
this.envVarService = envVarService;
this.Logger = logger;
}
public override string Id { get; } = "DockerReference";

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Go;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -12,7 +11,6 @@ using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Newtonsoft.Json;
[Export(typeof(IComponentDetector))]
public class GoComponentDetector : FileComponentDetector
{
private static readonly Regex GoSumRegex = new Regex(
@ -21,11 +19,22 @@ public class GoComponentDetector : FileComponentDetector
private readonly HashSet<string> projectRoots = new HashSet<string>();
[Import]
public ICommandLineInvocationService CommandLineInvocationService { get; set; }
private readonly ICommandLineInvocationService commandLineInvocationService;
private readonly IEnvironmentVariableService envVarService;
[Import]
public IEnvironmentVariableService EnvVarService { get; set; }
public GoComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ICommandLineInvocationService commandLineInvocationService,
IEnvironmentVariableService envVarService,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.commandLineInvocationService = commandLineInvocationService;
this.envVarService = envVarService;
this.Logger = logger;
}
public override string Id { get; } = "Go";
@ -108,7 +117,7 @@ public class GoComponentDetector : FileComponentDetector
var projectRootDirectory = Directory.GetParent(location);
record.ProjectRoot = projectRootDirectory.FullName;
var isGoAvailable = await this.CommandLineInvocationService.CanCommandBeLocatedAsync("go", null, workingDirectory: projectRootDirectory, new[] { "version" });
var isGoAvailable = await this.commandLineInvocationService.CanCommandBeLocatedAsync("go", null, workingDirectory: projectRootDirectory, new[] { "version" });
record.IsGoAvailable = isGoAvailable;
if (!isGoAvailable)
@ -120,7 +129,7 @@ public class GoComponentDetector : FileComponentDetector
this.Logger.LogInfo("Go CLI was found in system and will be used to generate dependency graph. " +
"Detection time may be improved by activating fallback strategy (https://github.com/microsoft/component-detection/blob/main/docs/detectors/go.md#fallback-detection-strategy). " +
"But, it will introduce noise into the detected components.");
var goDependenciesProcess = await this.CommandLineInvocationService.ExecuteCommandAsync("go", null, workingDirectory: projectRootDirectory, new[] { "list", "-mod=readonly", "-m", "-json", "all" });
var goDependenciesProcess = await this.commandLineInvocationService.ExecuteCommandAsync("go", null, workingDirectory: projectRootDirectory, new[] { "list", "-mod=readonly", "-m", "-json", "all" });
if (goDependenciesProcess.ExitCode != 0)
{
this.Logger.LogError($"Go CLI command \"go list -m -json all\" failed with error:\n {goDependenciesProcess.StdErr}");
@ -130,7 +139,7 @@ public class GoComponentDetector : FileComponentDetector
this.RecordBuildDependencies(goDependenciesProcess.StdOut, singleFileComponentRecorder);
var generateGraphProcess = await this.CommandLineInvocationService.ExecuteCommandAsync("go", null, workingDirectory: projectRootDirectory, new List<string> { "mod", "graph" }.ToArray());
var generateGraphProcess = await this.commandLineInvocationService.ExecuteCommandAsync("go", null, workingDirectory: projectRootDirectory, new List<string> { "mod", "graph" }.ToArray());
if (generateGraphProcess.ExitCode == 0)
{
this.PopulateDependencyGraph(generateGraphProcess.StdOut, singleFileComponentRecorder);
@ -322,7 +331,7 @@ public class GoComponentDetector : FileComponentDetector
private bool IsGoCliManuallyDisabled()
{
return this.EnvVarService.IsEnvironmentVariableValueTrue("DisableGoCliScan");
return this.envVarService.IsEnvironmentVariableValueTrue("DisableGoCliScan");
}
private class GoBuildModule

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Gradle;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@ -9,11 +8,20 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
[Export(typeof(IComponentDetector))]
public class GradleComponentDetector : FileComponentDetector, IComponentDetector
{
private static readonly Regex StartsWithLetterRegex = new Regex("^[A-Za-z]", RegexOptions.Compiled);
public GradleComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.Logger = logger;
}
public override string Id { get; } = "Gradle";
public override IEnumerable<string> Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Maven) };

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Ivy;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
@ -35,7 +34,6 @@ using Newtonsoft.Json.Linq;
/// The file written out by the custom Ant task is a simple JSON file representing a series of calls to be made to
/// the <see cref="ISingleFileComponentRecorder.RegisterUsage(DetectedComponent, bool, string, bool?, DependencyScope?)"/> method.
/// </remarks>
[Export(typeof(IComponentDetector))]
public class IvyDetector : FileComponentDetector, IExperimentalDetector
{
internal const string PrimaryCommand = "ant.bat";
@ -44,6 +42,20 @@ public class IvyDetector : FileComponentDetector, IExperimentalDetector
internal static readonly string[] AdditionalValidCommands = { "ant" };
private readonly ICommandLineInvocationService commandLineInvocationService;
public IvyDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ICommandLineInvocationService commandLineInvocationService,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.commandLineInvocationService = commandLineInvocationService;
this.Logger = logger;
}
public override string Id => "Ivy";
public override IList<string> SearchPatterns => new List<string> { "ivy.xml" };
@ -54,9 +66,6 @@ public class IvyDetector : FileComponentDetector, IExperimentalDetector
public override IEnumerable<string> Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Maven) };
[Import]
public ICommandLineInvocationService CommandLineInvocationService { get; set; }
protected override async Task<IObservable<ProcessRequest>> OnPrepareDetectionAsync(IObservable<ProcessRequest> processRequests, IDictionary<string, string> detectorArgs)
{
if (await this.IsAntLocallyAvailableAsync())
@ -168,14 +177,14 @@ public class IvyDetector : FileComponentDetector, IExperimentalDetector
{
// Note: calling CanCommandBeLocated populates a cache of valid commands. If it is not called before ExecuteCommand,
// ExecuteCommand calls CanCommandBeLocated with no arguments, which fails.
return await this.CommandLineInvocationService.CanCommandBeLocatedAsync(PrimaryCommand, AdditionalValidCommands, AntVersionArgument);
return await this.commandLineInvocationService.CanCommandBeLocatedAsync(PrimaryCommand, AdditionalValidCommands, AntVersionArgument);
}
private async Task<bool> RunAntToDetectDependenciesAsync(string workingDirectory)
{
var ret = false;
this.Logger.LogVerbose($"Executing command `ant resolve-dependencies` in directory {workingDirectory}");
var result = await this.CommandLineInvocationService.ExecuteCommandAsync(PrimaryCommand, additionalCandidateCommands: AdditionalValidCommands, "-buildfile", workingDirectory, "resolve-dependencies");
var result = await this.commandLineInvocationService.ExecuteCommandAsync(PrimaryCommand, additionalCandidateCommands: AdditionalValidCommands, "-buildfile", workingDirectory, "resolve-dependencies");
if (result.ExitCode == 0)
{
this.Logger.LogVerbose("Ant command succeeded");

Просмотреть файл

@ -2,7 +2,6 @@ namespace Microsoft.ComponentDetection.Detectors.Linux;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
@ -15,17 +14,18 @@ using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Linux.Contracts;
using Microsoft.ComponentDetection.Detectors.Linux.Exceptions;
[Export(typeof(IComponentDetector))]
public class LinuxContainerDetector : IComponentDetector
{
[Import]
public ILogger Logger { get; set; }
private readonly ILinuxScanner linuxScanner;
private readonly IDockerService dockerService;
private readonly ILogger logger;
[Import]
public ILinuxScanner LinuxScanner { get; set; }
[Import]
public IDockerService DockerService { get; set; }
public LinuxContainerDetector(ILinuxScanner linuxScanner, IDockerService dockerService, ILogger logger)
{
this.linuxScanner = linuxScanner;
this.dockerService = dockerService;
this.logger = logger;
}
public string Id => "Linux";
@ -47,19 +47,19 @@ public class LinuxContainerDetector : IComponentDetector
if (imagesToProcess == null || !imagesToProcess.Any())
{
this.Logger.LogInfo("No instructions received to scan docker images.");
this.logger.LogInfo("No instructions received to scan docker images.");
return EmptySuccessfulScan();
}
var cancellationTokenSource = new CancellationTokenSource(GetTimeout(request.DetectorArgs));
if (!await this.DockerService.CanRunLinuxContainersAsync(cancellationTokenSource.Token))
if (!await this.dockerService.CanRunLinuxContainersAsync(cancellationTokenSource.Token))
{
using var record = new LinuxContainerDetectorUnsupportedOs
{
Os = RuntimeInformation.OSDescription,
};
this.Logger.LogInfo("Linux containers are not available on this host.");
this.logger.LogInfo("Linux containers are not available on this host.");
return EmptySuccessfulScan();
}
@ -125,15 +125,15 @@ public class LinuxContainerDetector : IComponentDetector
try
{
// Check image exists locally. Try docker pull if not
if (!(await this.DockerService.ImageExistsLocallyAsync(image, cancellationToken) ||
await this.DockerService.TryPullImageAsync(image, cancellationToken)))
if (!(await this.dockerService.ImageExistsLocallyAsync(image, cancellationToken) ||
await this.dockerService.TryPullImageAsync(image, cancellationToken)))
{
throw new InvalidUserInputException(
$"Docker image {image} could not be found locally and could not be pulled. Verify the image is either available locally or through docker pull.",
null);
}
var imageDetails = await this.DockerService.InspectImageAsync(image, cancellationToken);
var imageDetails = await this.dockerService.InspectImageAsync(image, cancellationToken);
// Unable to fetch image details
if (imageDetails == null)
@ -145,7 +145,7 @@ public class LinuxContainerDetector : IComponentDetector
}
catch (Exception e)
{
this.Logger.LogWarning($"Processing of image {image} failed with exception: {e.Message}");
this.logger.LogWarning($"Processing of image {image} failed with exception: {e.Message}");
using var record = new LinuxContainerDetectorImageDetectionFailed
{
ExceptionType = e.GetType().ToString(),
@ -174,7 +174,7 @@ public class LinuxContainerDetector : IComponentDetector
IsBaseImage = layer.LayerIndex < baseImageLayerCount,
});
var layers = await this.LinuxScanner.ScanLinuxAsync(kvp.Value.ImageId, internalContainerDetails.Layers, baseImageLayerCount, cancellationToken);
var layers = await this.linuxScanner.ScanLinuxAsync(kvp.Value.ImageId, internalContainerDetails.Layers, baseImageLayerCount, cancellationToken);
var components = layers.SelectMany(layer => layer.LinuxComponents.Select(linuxComponent => new DetectedComponent(linuxComponent, null, internalContainerDetails.Id, layer.DockerLayer.LayerIndex)));
internalContainerDetails.Layers = layers.Select(layer => layer.DockerLayer);
@ -188,7 +188,7 @@ public class LinuxContainerDetector : IComponentDetector
}
catch (Exception e)
{
this.Logger.LogWarning($"Scanning of image {kvp.Key} failed with exception: {e.Message}");
this.logger.LogWarning($"Scanning of image {kvp.Key} failed with exception: {e.Message}");
using var record = new LinuxContainerDetectorImageDetectionFailed
{
ExceptionType = e.GetType().ToString(),
@ -214,14 +214,14 @@ public class LinuxContainerDetector : IComponentDetector
if (string.IsNullOrEmpty(scannedImageDetails.BaseImageRef))
{
record.BaseImageLayerMessage = $"Base image annotations not found on image {image}, Results will not be mapped to base image layers";
this.Logger.LogInfo(record.BaseImageLayerMessage);
this.logger.LogInfo(record.BaseImageLayerMessage);
return 0;
}
if (scannedImageDetails.BaseImageRef == "scratch")
{
record.BaseImageLayerMessage = $"{image} has no base image";
this.Logger.LogInfo(record.BaseImageLayerMessage);
this.logger.LogInfo(record.BaseImageLayerMessage);
return 0;
}
@ -230,19 +230,19 @@ public class LinuxContainerDetector : IComponentDetector
record.BaseImageDigest = baseImageDigest;
record.BaseImageRef = scannedImageDetails.BaseImageRef;
if (!(await this.DockerService.ImageExistsLocallyAsync(refWithDigest, cancellationToken) ||
await this.DockerService.TryPullImageAsync(refWithDigest, cancellationToken)))
if (!(await this.dockerService.ImageExistsLocallyAsync(refWithDigest, cancellationToken) ||
await this.dockerService.TryPullImageAsync(refWithDigest, cancellationToken)))
{
record.BaseImageLayerMessage = $"Base image {refWithDigest} could not be found locally and could not be pulled. Results will not be mapped to base image layers";
this.Logger.LogInfo(record.BaseImageLayerMessage);
this.logger.LogInfo(record.BaseImageLayerMessage);
return 0;
}
var baseImageDetails = await this.DockerService.InspectImageAsync(refWithDigest, cancellationToken);
var baseImageDetails = await this.dockerService.InspectImageAsync(refWithDigest, cancellationToken);
if (!this.ValidateBaseImageLayers(scannedImageDetails, baseImageDetails))
{
record.BaseImageLayerMessage = $"Docker image {image} was set to have base image {refWithDigest} but is not built off of it. Results will not be mapped to base image layers";
this.Logger.LogInfo(record.BaseImageLayerMessage);
this.logger.LogInfo(record.BaseImageLayerMessage);
return 0;
}

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Linux;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -12,7 +11,6 @@ using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Linux.Contracts;
using Newtonsoft.Json;
[Export(typeof(ILinuxScanner))]
public class LinuxScanner : ILinuxScanner
{
private const string ScannerImage = "governancecontainerregistry.azurecr.io/syft:v0.53.4@sha256:04ed9c717a814fdccf52758b67333632a0ff16840fc393f5fba5864285eaebbe";
@ -28,11 +26,14 @@ public class LinuxScanner : ILinuxScanner
private static readonly int SemaphoreTimeout = Convert.ToInt32(TimeSpan.FromHours(1).TotalMilliseconds);
[Import]
public ILogger Logger { get; set; }
private readonly IDockerService dockerService;
private readonly ILogger logger;
[Import]
public IDockerService DockerService { get; set; }
public LinuxScanner(IDockerService dockerService, ILogger logger)
{
this.dockerService = dockerService;
this.logger = logger;
}
public async Task<IEnumerable<LayerMappedLinuxComponents>> ScanLinuxAsync(string imageHash, IEnumerable<DockerLayer> dockerLayers, int baseImageLayerCount, CancellationToken cancellationToken = default)
{
@ -56,19 +57,19 @@ public class LinuxScanner : ILinuxScanner
try
{
var command = new List<string> { imageHash }.Concat(CmdParameters).ToList();
(stdout, stderr) = await this.DockerService.CreateAndRunContainerAsync(ScannerImage, command, cancellationToken);
(stdout, stderr) = await this.dockerService.CreateAndRunContainerAsync(ScannerImage, command, cancellationToken);
}
catch (Exception e)
{
syftTelemetryRecord.Exception = JsonConvert.SerializeObject(e);
this.Logger.LogException(e, false);
this.logger.LogException(e, false);
throw;
}
}
else
{
record.SemaphoreFailure = true;
this.Logger.LogWarning($"Failed to enter the docker semaphore for image {imageHash}");
this.logger.LogWarning($"Failed to enter the docker semaphore for image {imageHash}");
}
}
finally

Просмотреть файл

@ -1,12 +1,10 @@
namespace Microsoft.ComponentDetection.Detectors.Maven;
namespace Microsoft.ComponentDetection.Detectors.Maven;
using System;
using System.Composition;
using System.IO;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
[Export(typeof(IMavenCommandService))]
public class MavenCommandService : IMavenCommandService
{
internal const string PrimaryCommand = "mvn";
@ -15,31 +13,36 @@ public class MavenCommandService : IMavenCommandService
internal static readonly string[] AdditionalValidCommands = new[] { "mvn.cmd" };
[Import]
public ICommandLineInvocationService CommandLineInvocationService { get; set; }
private readonly ICommandLineInvocationService commandLineInvocationService;
private readonly IMavenStyleDependencyGraphParserService parserService;
private readonly ILogger logger;
[Import]
public IMavenStyleDependencyGraphParserService ParserService { get; set; }
[Import]
public ILogger Logger { get; set; }
public MavenCommandService(
ICommandLineInvocationService commandLineInvocationService,
IMavenStyleDependencyGraphParserService parserService,
ILogger logger)
{
this.commandLineInvocationService = commandLineInvocationService;
this.parserService = parserService;
this.logger = logger;
}
public string BcdeMvnDependencyFileName => "bcde.mvndeps";
public async Task<bool> MavenCLIExistsAsync()
{
return await this.CommandLineInvocationService.CanCommandBeLocatedAsync(PrimaryCommand, AdditionalValidCommands, MvnVersionArgument);
return await this.commandLineInvocationService.CanCommandBeLocatedAsync(PrimaryCommand, AdditionalValidCommands, MvnVersionArgument);
}
public async Task GenerateDependenciesFileAsync(ProcessRequest processRequest)
{
var pomFile = processRequest.ComponentStream;
var cliParameters = new[] { "dependency:tree", "-B", $"-DoutputFile={this.BcdeMvnDependencyFileName}", "-DoutputType=text", $"-f{pomFile.Location}" };
var result = await this.CommandLineInvocationService.ExecuteCommandAsync(PrimaryCommand, AdditionalValidCommands, cliParameters);
var result = await this.commandLineInvocationService.ExecuteCommandAsync(PrimaryCommand, AdditionalValidCommands, cliParameters);
if (result.ExitCode != 0)
{
this.Logger.LogVerbose($"Mvn execution failed for pom file: {pomFile.Location}");
this.Logger.LogError(string.IsNullOrEmpty(result.StdErr) ? result.StdOut : result.StdErr);
this.logger.LogVerbose($"Mvn execution failed for pom file: {pomFile.Location}");
this.logger.LogError(string.IsNullOrEmpty(result.StdErr) ? result.StdOut : result.StdErr);
}
}
@ -48,6 +51,6 @@ public class MavenCommandService : IMavenCommandService
using var sr = new StreamReader(processRequest.ComponentStream.Stream);
var lines = sr.ReadToEnd().Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
this.ParserService.Parse(lines, processRequest.SingleFileComponentRecorder);
this.parserService.Parse(lines, processRequest.SingleFileComponentRecorder);
}
}

Просмотреть файл

@ -1,8 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Maven;
using System.Composition;
namespace Microsoft.ComponentDetection.Detectors.Maven;
using Microsoft.ComponentDetection.Contracts;
[Export(typeof(IMavenStyleDependencyGraphParserService))]
public class MavenStyleDependencyGraphParserService : IMavenStyleDependencyGraphParserService
{
public void Parse(string[] lines, ISingleFileComponentRecorder singleFileComponentRecorder)

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Maven;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
@ -13,9 +12,22 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
[Export(typeof(IComponentDetector))]
public class MvnCliComponentDetector : FileComponentDetector
{
private readonly IMavenCommandService mavenCommandService;
public MvnCliComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
IMavenCommandService mavenCommandService,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.mavenCommandService = mavenCommandService;
this.Logger = logger;
}
public override string Id => "MvnCli";
public override IList<string> SearchPatterns => new List<string> { "pom.xml" };
@ -26,18 +38,15 @@ public class MvnCliComponentDetector : FileComponentDetector
public override IEnumerable<string> Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Maven) };
[Import]
public IMavenCommandService MavenCommandService { get; set; }
protected override async Task<IObservable<ProcessRequest>> OnPrepareDetectionAsync(IObservable<ProcessRequest> processRequests, IDictionary<string, string> detectorArgs)
{
if (!await this.MavenCommandService.MavenCLIExistsAsync())
if (!await this.mavenCommandService.MavenCLIExistsAsync())
{
this.Logger.LogVerbose("Skipping maven detection as maven is not available in the local PATH.");
return Enumerable.Empty<ProcessRequest>().ToObservable();
}
var processPomFile = new ActionBlock<ProcessRequest>(this.MavenCommandService.GenerateDependenciesFileAsync);
var processPomFile = new ActionBlock<ProcessRequest>(this.mavenCommandService.GenerateDependenciesFileAsync);
await this.RemoveNestedPomXmls(processRequests).ForEachAsync(processRequest =>
{
@ -48,7 +57,7 @@ public class MvnCliComponentDetector : FileComponentDetector
await processPomFile.Completion;
return this.ComponentStreamEnumerableFactory.GetComponentStreams(this.CurrentScanRequest.SourceDirectory, new[] { this.MavenCommandService.BcdeMvnDependencyFileName }, this.CurrentScanRequest.DirectoryExclusionPredicate)
return this.ComponentStreamEnumerableFactory.GetComponentStreams(this.CurrentScanRequest.SourceDirectory, new[] { this.mavenCommandService.BcdeMvnDependencyFileName }, this.CurrentScanRequest.DirectoryExclusionPredicate)
.Select(componentStream =>
{
// The file stream is going to be disposed after the iteration is finished
@ -72,7 +81,7 @@ public class MvnCliComponentDetector : FileComponentDetector
protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary<string, string> detectorArgs)
{
this.MavenCommandService.ParseDependenciesFile(processRequest);
this.mavenCommandService.ParseDependenciesFile(processRequest);
File.Delete(processRequest.ComponentStream.Location);

Просмотреть файл

@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@ -12,9 +11,18 @@ using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Newtonsoft.Json.Linq;
[Export(typeof(IComponentDetector))]
public class NpmComponentDetector : FileComponentDetector
{
public NpmComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.Logger = logger;
}
/// <summary>Common delegate for Package.json JToken processing.</summary>
/// <param name="token">A JToken, usually corresponding to a package.json file.</param>
/// <returns>Used in scenarios where one file path creates multiple JTokens, a false value indicates processing additional JTokens should be halted, proceed otherwise.</returns>

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Npm;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
@ -13,7 +12,6 @@ using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
[Export(typeof(IComponentDetector))]
public class NpmComponentDetectorWithRoots : FileComponentDetector
{
private const string NpmRegistryHost = "registry.npmjs.org";
@ -22,15 +20,30 @@ public class NpmComponentDetectorWithRoots : FileComponentDetector
public const string LernaSearchPattern = "lerna.json";
/// <summary>
/// Gets or sets the logger for writing basic logging message to both console and file.
/// </summary>
private readonly IPathUtilityService pathUtilityService;
public NpmComponentDetectorWithRoots(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
IPathUtilityService pathUtilityService,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.pathUtilityService = pathUtilityService;
this.Logger = logger;
}
public NpmComponentDetectorWithRoots(IPathUtilityService pathUtilityService) => this.pathUtilityService = pathUtilityService;
/// <summary>Common delegate for Package.json JToken processing.</summary>
/// <param name="token">A JToken, usually corresponding to a package.json file.</param>
/// <returns>Used in scenarios where one file path creates multiple JTokens, a false value indicates processing additional JTokens should be halted, proceed otherwise.</returns>
protected delegate bool JTokenProcessingDelegate(JToken token);
/// <summary>Gets or sets the logger for writing basic logging message to both console and file. Injected automatically by MEF composition.</summary>
[Import]
public IPathUtilityService PathUtilityService { get; set; }
public override string Id { get; } = "NpmWithRoots";
public override IEnumerable<string> Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Npm) };
@ -87,7 +100,7 @@ public class NpmComponentDetectorWithRoots : FileComponentDetector
var lernaFile = lernaProcessRequest.ComponentStream;
// We have extra validation on lock files not found below a lerna.json
if (this.PathUtilityService.IsFileBelowAnother(lernaFile.Location, file.Location))
if (this.pathUtilityService.IsFileBelowAnother(lernaFile.Location, file.Location))
{
foundUnderLerna = true;
break;
@ -177,7 +190,7 @@ public class NpmComponentDetectorWithRoots : FileComponentDetector
DirectoryItemFacade last = null;
do
{
currentDir = this.PathUtilityService.GetParentDirectory(currentDir);
currentDir = this.pathUtilityService.GetParentDirectory(currentDir);
// We've reached the top / root
if (currentDir == null)

Просмотреть файл

@ -2,7 +2,6 @@ namespace Microsoft.ComponentDetection.Detectors.NuGet;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
@ -15,7 +14,6 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
[Export(typeof(IComponentDetector))]
public class NuGetComponentDetector : FileComponentDetector
{
private static readonly IEnumerable<string> LowConfidencePackages = new[] { "Newtonsoft.Json" };
@ -24,6 +22,16 @@ public class NuGetComponentDetector : FileComponentDetector
private readonly IList<string> repositoryPathKeyNames = new List<string> { "repositorypath", "globalpackagesfolder" };
public NuGetComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.Logger = logger;
}
public override string Id { get; } = "NuGet";
public override IEnumerable<string> Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.NuGet) };

Просмотреть файл

@ -2,7 +2,6 @@ namespace Microsoft.ComponentDetection.Detectors.NuGet;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Threading.Tasks;
using System.Xml;
using global::NuGet.Packaging;
@ -10,9 +9,18 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
[Export(typeof(IComponentDetector))]
public class NuGetPackagesConfigDetector : FileComponentDetector
{
public NuGetPackagesConfigDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.Logger = logger;
}
public override IList<string> SearchPatterns => new[] { "packages.config" };
public override string Id => "NuGetPackagesConfig";

Просмотреть файл

@ -3,7 +3,6 @@ namespace Microsoft.ComponentDetection.Detectors.NuGet;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -15,7 +14,6 @@ using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Newtonsoft.Json;
[Export(typeof(IComponentDetector))]
public class NuGetProjectModelProjectCentricComponentDetector : FileComponentDetector
{
public const string OmittedFrameworkComponentsTelemetryKey = "OmittedFrameworkComponents";
@ -187,6 +185,20 @@ public class NuGetProjectModelProjectCentricComponentDetector : FileComponentDet
"System.Xml.XPath.XDocument",
};
private readonly IFileUtilityService fileUtilityService;
public NuGetProjectModelProjectCentricComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
IFileUtilityService fileUtilityService,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.fileUtilityService = fileUtilityService;
this.Logger = logger;
}
public override string Id { get; } = "NuGetProjectCentric";
public override IEnumerable<string> Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.NuGet) };
@ -197,9 +209,6 @@ public class NuGetProjectModelProjectCentricComponentDetector : FileComponentDet
public override int Version { get; } = 1;
[Import]
public IFileUtilityService FileUtilityService { get; set; }
protected override Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary<string, string> detectorArgs)
{
try

Просмотреть файл

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.IO.Compression;
using System.Linq;
@ -25,7 +24,6 @@ public interface IPyPiClient
Task<SortedDictionary<string, IList<PythonProjectRelease>>> GetReleasesAsync(PipDependencySpecification spec);
}
[Export(typeof(IPyPiClient))]
public class PyPiClient : IPyPiClient
{
// Values used for cache creation
@ -44,6 +42,9 @@ public class PyPiClient : IPyPiClient
// Keep telemetry on how the cache is being used for future refinements
private readonly PypiCacheTelemetryRecord cacheTelemetry;
private readonly IEnvironmentVariableService environmentVariableService;
private readonly ILogger logger;
private bool checkedMaxEntriesVariable;
// retries used so far for calls to pypi.org
@ -61,6 +62,17 @@ public class PyPiClient : IPyPiClient
FinalCacheSize = 0,
};
public PyPiClient(IEnvironmentVariableService environmentVariableService, ILogger logger)
{
this.environmentVariableService = environmentVariableService;
this.cacheTelemetry = new PypiCacheTelemetryRecord
{
NumCacheHits = 0,
FinalCacheSize = 0,
};
this.logger = logger;
}
~PyPiClient()
{
this.cacheTelemetry.FinalCacheSize = this.cachedResponses.Count;
@ -69,12 +81,6 @@ public class PyPiClient : IPyPiClient
public static HttpClient HttpClient { get; internal set; } = new HttpClient(HttpClientHandler);
[Import]
public ILogger Logger { get; set; }
[Import]
public IEnvironmentVariableService EnvironmentVariableService { get; set; }
public async Task<IList<PipDependencySpecification>> FetchPackageDependenciesAsync(string name, string version, PythonProjectRelease release)
{
var dependencies = new List<PipDependencySpecification>();
@ -84,7 +90,7 @@ public class PyPiClient : IPyPiClient
if (!response.IsSuccessStatusCode)
{
this.Logger.LogWarning($"Http GET at {release.Url} failed with status code {response.StatusCode}");
this.logger.LogWarning($"Http GET at {release.Url} failed with status code {response.StatusCode}");
return dependencies;
}
@ -148,7 +154,7 @@ public class PyPiClient : IPyPiClient
{
using var r = new PypiRetryTelemetryRecord { Name = spec.Name, DependencySpecifiers = spec.DependencySpecifiers?.ToArray(), StatusCode = result.Result.StatusCode };
this.Logger.LogWarning($"Received {(int)result.Result.StatusCode} {result.Result.ReasonPhrase} from {requestUri}. Waiting {timeSpan} before retry attempt {retryCount}");
this.logger.LogWarning($"Received {(int)result.Result.StatusCode} {result.Result.ReasonPhrase} from {requestUri}. Waiting {timeSpan} before retry attempt {retryCount}");
Interlocked.Increment(ref this.retries);
})
@ -166,7 +172,7 @@ public class PyPiClient : IPyPiClient
{
using var r = new PypiMaxRetriesReachedTelemetryRecord { Name = spec.Name, DependencySpecifiers = spec.DependencySpecifiers?.ToArray() };
this.Logger.LogWarning($"Call to pypi.org failed, but no more retries allowed!");
this.logger.LogWarning($"Call to pypi.org failed, but no more retries allowed!");
return new SortedDictionary<string, IList<PythonProjectRelease>>();
}
@ -175,7 +181,7 @@ public class PyPiClient : IPyPiClient
{
using var r = new PypiFailureTelemetryRecord { Name = spec.Name, DependencySpecifiers = spec.DependencySpecifiers?.ToArray(), StatusCode = request.StatusCode };
this.Logger.LogWarning($"Received {(int)request.StatusCode} {request.ReasonPhrase} from {requestUri}");
this.logger.LogWarning($"Received {(int)request.StatusCode} {request.ReasonPhrase} from {requestUri}");
return new SortedDictionary<string, IList<PythonProjectRelease>>();
}
@ -198,8 +204,8 @@ public class PyPiClient : IPyPiClient
}
catch (ArgumentException ae)
{
this.Logger.LogError($"Component {release.Key} : {JsonConvert.SerializeObject(release.Value)} could not be added to the sorted list of pip components for spec={spec.Name}. Usually this happens with unexpected PyPi version formats (e.g. prerelease/dev versions). Error details follow:");
this.Logger.LogException(ae, true);
this.logger.LogError($"Component {release.Key} : {JsonConvert.SerializeObject(release.Value)} could not be added to the sorted list of pip components for spec={spec.Name}. Usually this happens with unexpected PyPi version formats (e.g. prerelease/dev versions). Error details follow:");
this.logger.LogException(ae, true);
continue;
}
}
@ -223,11 +229,11 @@ public class PyPiClient : IPyPiClient
if (this.cachedResponses.TryGetValue(uri, out HttpResponseMessage result))
{
this.cacheTelemetry.NumCacheHits++;
this.Logger.LogVerbose("Retrieved cached Python data from " + uri);
this.logger.LogVerbose("Retrieved cached Python data from " + uri);
return result;
}
this.Logger.LogInfo("Getting Python data from " + uri);
this.logger.LogInfo("Getting Python data from " + uri);
var response = await HttpClient.GetAsync(uri);
// The `first - wins` response accepted into the cache. This might be different from the input if another caller wins the race.
@ -245,10 +251,10 @@ public class PyPiClient : IPyPiClient
/// </summary>
private void InitializeNonDefaultMemoryCache()
{
var maxEntriesVariable = this.EnvironmentVariableService.GetEnvironmentVariable("PyPiMaxCacheEntries");
var maxEntriesVariable = this.environmentVariableService.GetEnvironmentVariable("PyPiMaxCacheEntries");
if (!string.IsNullOrEmpty(maxEntriesVariable) && long.TryParse(maxEntriesVariable, out var maxEntries))
{
this.Logger.LogInfo($"Setting IPyPiClient max cache entries to {maxEntries}");
this.logger.LogInfo($"Setting IPyPiClient max cache entries to {maxEntries}");
this.cachedResponses = new MemoryCache(new MemoryCacheOptions { SizeLimit = maxEntries });
}

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Pip;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
@ -9,9 +8,25 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
[Export(typeof(IComponentDetector))]
public class PipComponentDetector : FileComponentDetector
{
private readonly IPythonCommandService pythonCommandService;
private readonly IPythonResolver pythonResolver;
public PipComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
IPythonCommandService pythonCommandService,
IPythonResolver pythonResolver,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.pythonCommandService = pythonCommandService;
this.pythonResolver = pythonResolver;
this.Logger = logger;
}
public override string Id => "Pip";
public override IList<string> SearchPatterns => new List<string> { "setup.py", "requirements.txt" };
@ -22,16 +37,10 @@ public class PipComponentDetector : FileComponentDetector
public override int Version { get; } = 6;
[Import]
public IPythonCommandService PythonCommandService { get; set; }
[Import]
public IPythonResolver PythonResolver { get; set; }
protected override async Task<IObservable<ProcessRequest>> OnPrepareDetectionAsync(IObservable<ProcessRequest> processRequests, IDictionary<string, string> detectorArgs)
{
this.CurrentScanRequest.DetectorArgs.TryGetValue("Pip.PythonExePath", out var pythonExePath);
if (!await this.PythonCommandService.PythonExistsAsync(pythonExePath))
if (!await this.pythonCommandService.PythonExistsAsync(pythonExePath))
{
this.Logger.LogInfo($"No python found on system. Python detection will not run.");
@ -49,7 +58,7 @@ public class PipComponentDetector : FileComponentDetector
try
{
var initialPackages = await this.PythonCommandService.ParseFileAsync(file.Location, pythonExePath);
var initialPackages = await this.pythonCommandService.ParseFileAsync(file.Location, pythonExePath);
var listedPackage = initialPackages.Where(tuple => tuple.PackageString != null)
.Select(tuple => tuple.PackageString)
.Where(x => !string.IsNullOrWhiteSpace(x))
@ -57,7 +66,7 @@ public class PipComponentDetector : FileComponentDetector
.Where(x => !x.PackageIsUnsafe())
.ToList();
var roots = await this.PythonResolver.ResolveRootsAsync(listedPackage);
var roots = await this.pythonResolver.ResolveRootsAsync(listedPackage);
RecordComponents(
singleFileComponentRecorder,

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Pip;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -9,11 +8,16 @@ using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
[Export(typeof(IPythonCommandService))]
public class PythonCommandService : IPythonCommandService
{
[Import]
public ICommandLineInvocationService CommandLineInvocationService { get; set; }
private readonly ICommandLineInvocationService commandLineInvocationService;
public PythonCommandService()
{
}
public PythonCommandService(ICommandLineInvocationService commandLineInvocationService) =>
this.commandLineInvocationService = commandLineInvocationService;
public async Task<bool> PythonExistsAsync(string pythonPath = null)
{
@ -54,7 +58,7 @@ public class PythonCommandService : IPythonCommandService
// This calls out to python and prints out an array like: [ packageA, packageB, packageC ]
// We need to have python interpret this file because install_requires can be composed at runtime
var command = await this.CommandLineInvocationService.ExecuteCommandAsync(pythonExecutable, null, $"-c \"import distutils.core; setup=distutils.core.run_setup('{filePath.Replace('\\', '/')}'); print(setup.install_requires)\"");
var command = await this.commandLineInvocationService.ExecuteCommandAsync(pythonExecutable, null, $"-c \"import distutils.core; setup=distutils.core.run_setup('{filePath.Replace('\\', '/')}'); print(setup.install_requires)\"");
if (command.ExitCode != 0)
{
@ -145,6 +149,6 @@ public class PythonCommandService : IPythonCommandService
private async Task<bool> CanCommandBeLocatedAsync(string pythonPath)
{
return await this.CommandLineInvocationService.CanCommandBeLocatedAsync(pythonPath, new List<string> { "python3", "python2" }, "--version");
return await this.commandLineInvocationService.CanCommandBeLocatedAsync(pythonPath, new List<string> { "python3", "python2" }, "--version");
}
}

Просмотреть файл

@ -1,20 +1,21 @@
namespace Microsoft.ComponentDetection.Detectors.Pip;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
[Export(typeof(IPythonResolver))]
public class PythonResolver : IPythonResolver
{
[Import]
public IPyPiClient PypiClient { get; set; }
private readonly IPyPiClient pypiClient;
private readonly ILogger logger;
[Import]
public ILogger Logger { get; set; }
public PythonResolver(IPyPiClient pypiClient, ILogger logger)
{
this.pypiClient = pypiClient;
this.logger = logger;
}
/// <summary>
/// Resolves the root Python packages from the initial list of packages.
@ -31,7 +32,7 @@ public class PythonResolver : IPythonResolver
// If we have it, we probably just want to skip at this phase as this indicates duplicates
if (!state.ValidVersionMap.TryGetValue(rootPackage.Name, out _))
{
var result = await this.PypiClient.GetReleasesAsync(rootPackage);
var result = await this.pypiClient.GetReleasesAsync(rootPackage);
if (result.Keys.Any())
{
@ -51,7 +52,7 @@ public class PythonResolver : IPythonResolver
}
else
{
this.Logger.LogWarning($"Root dependency {rootPackage.Name} not found on pypi. Skipping package.");
this.logger.LogWarning($"Root dependency {rootPackage.Name} not found on pypi. Skipping package.");
}
}
}
@ -80,13 +81,13 @@ public class PythonResolver : IPythonResolver
}
else if (node != null)
{
this.Logger.LogWarning($"Candidate version ({node.Value.Id}) for {dependencyNode.Name} already exists in map and the version is NOT valid.");
this.Logger.LogWarning($"Specifiers: {string.Join(',', dependencyNode.DependencySpecifiers)} for package {currentNode.Name} caused this.");
this.logger.LogWarning($"Candidate version ({node.Value.Id}) for {dependencyNode.Name} already exists in map and the version is NOT valid.");
this.logger.LogWarning($"Specifiers: {string.Join(',', dependencyNode.DependencySpecifiers)} for package {currentNode.Name} caused this.");
// The currently selected version is invalid, try to see if there is another valid version available
if (!await this.InvalidateAndReprocessAsync(state, node, dependencyNode))
{
this.Logger.LogWarning($"Version Resolution for {dependencyNode.Name} failed, assuming last valid version is used.");
this.logger.LogWarning($"Version Resolution for {dependencyNode.Name} failed, assuming last valid version is used.");
// there is no valid version available for the node, dependencies are incompatible,
}
@ -94,7 +95,7 @@ public class PythonResolver : IPythonResolver
else
{
// We haven't encountered this package before, so let's fetch it and find a candidate
var result = await this.PypiClient.GetReleasesAsync(dependencyNode);
var result = await this.pypiClient.GetReleasesAsync(dependencyNode);
if (result.Keys.Any())
{
@ -108,7 +109,7 @@ public class PythonResolver : IPythonResolver
}
else
{
this.Logger.LogWarning($"Dependency Package {dependencyNode.Name} not found in Pypi. Skipping package");
this.logger.LogWarning($"Dependency Package {dependencyNode.Name} not found in Pypi. Skipping package");
}
}
}
@ -186,7 +187,7 @@ public class PythonResolver : IPythonResolver
return new List<PipDependencySpecification>();
}
return await this.PypiClient.FetchPackageDependenciesAsync(spec.Name, candidateVersion, packageToFetch);
return await this.pypiClient.FetchPackageDependenciesAsync(spec.Name, candidateVersion, packageToFetch);
}
private void AddGraphNode(PythonResolverState state, PipGraphNode parent, string name, string version)

Просмотреть файл

@ -1,17 +1,24 @@
namespace Microsoft.ComponentDetection.Detectors.Pnpm;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
[Export(typeof(IComponentDetector))]
public class PnpmComponentDetector : FileComponentDetector
{
public PnpmComponentDetector() => this.NeedsAutomaticRootDependencyCalculation = true;
public PnpmComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.NeedsAutomaticRootDependencyCalculation = true;
this.Logger = logger;
}
public override string Id { get; } = "Pnpm";

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Poetry;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -11,9 +10,18 @@ using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Poetry.Contracts;
using Tomlyn;
[Export(typeof(IComponentDetector))]
public class PoetryComponentDetector : FileComponentDetector, IExperimentalDetector
{
public PoetryComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.Logger = logger;
}
public override string Id => "Poetry";
public override IList<string> SearchPatterns { get; } = new List<string> { "poetry.lock" };

Просмотреть файл

@ -28,7 +28,6 @@
namespace Microsoft.ComponentDetection.Detectors.Ruby;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@ -36,14 +35,22 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
[Export(typeof(IComponentDetector))]
public class RubyComponentDetector : FileComponentDetector
{
private static readonly Regex HeadingRegex = new Regex("^[A-Z ]+$", RegexOptions.Compiled);
private static readonly Regex DependencyDefinitionRegex = new Regex("^ {4}[A-Za-z-]+", RegexOptions.Compiled);
private static readonly Regex SubDependencyRegex = new Regex("^ {6}[A-Za-z-]+", RegexOptions.Compiled);
public RubyComponentDetector() => this.NeedsAutomaticRootDependencyCalculation = true;
public RubyComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.NeedsAutomaticRootDependencyCalculation = true;
this.Logger = logger;
}
private enum SectionType
{

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Rust;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -13,7 +12,6 @@ using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Rust.Contracts;
using Tomlyn;
[Export(typeof(IComponentDetector))]
public class RustCrateDetector : FileComponentDetector
{
private const string CargoLockSearchPattern = "Cargo.lock";
@ -23,6 +21,16 @@ public class RustCrateDetector : FileComponentDetector
@"^(?<packageName>[^ ]+)(?: (?<version>[^ ]+))?(?: \((?<source>[^()]*)\))?$",
RegexOptions.Compiled);
public RustCrateDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.Logger = logger;
}
public override string Id => "RustCrateDetector";
public override IList<string> SearchPatterns => new List<string> { CargoLockSearchPattern };

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Spdx;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
@ -16,11 +15,20 @@ using Newtonsoft.Json.Linq;
/// Spdx22ComponentDetector discover SPDX SBOM files in JSON format and create components with the information about
/// what SPDX document describes.
/// </summary>
[Export(typeof(IComponentDetector))]
public class Spdx22ComponentDetector : FileComponentDetector, IDefaultOffComponentDetector
{
private readonly IEnumerable<string> supportedSPDXVersions = new List<string> { "SPDX-2.2" };
public Spdx22ComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.Logger = logger;
}
public override IEnumerable<string> Categories =>
new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Spdx) };
@ -30,7 +38,7 @@ public class Spdx22ComponentDetector : FileComponentDetector, IDefaultOffCompone
public override int Version => 1;
public override IList<string> SearchPatterns { get; } = new List<string> { "*.spdx.json" };
public override IList<string> SearchPatterns => new List<string> { "*.spdx.json" };
protected override Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary<string, string> detectorArgs)
{

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Vcpkg;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -11,16 +10,26 @@ using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Vcpkg.Contracts;
using Newtonsoft.Json;
[Export(typeof(IComponentDetector))]
public class VcpkgComponentDetector : FileComponentDetector, IExperimentalDetector
{
private readonly HashSet<string> projectRoots = new HashSet<string>();
[Import]
public ICommandLineInvocationService CommandLineInvocationService { get; set; }
private readonly ICommandLineInvocationService commandLineInvocationService;
private readonly IEnvironmentVariableService envVarService;
[Import]
public IEnvironmentVariableService EnvVarService { get; set; }
public VcpkgComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
ICommandLineInvocationService commandLineInvocationService,
IEnvironmentVariableService environmentVariableService,
ILogger logger)
{
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.commandLineInvocationService = commandLineInvocationService;
this.envVarService = environmentVariableService;
this.Logger = logger;
}
public override string Id { get; } = "Vcpkg";

Просмотреть файл

@ -0,0 +1,10 @@
namespace Microsoft.ComponentDetection.Detectors.Yarn;
using System.IO;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
public interface IYarnLockFileFactory
{
Task<YarnLockFile> ParseYarnLockFileAsync(Stream file, ILogger logger);
}

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Yarn.Parsers;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using Microsoft.ComponentDetection.Contracts;
@ -17,8 +16,9 @@ public class YarnLockParser : IYarnLockParser
private static readonly List<YarnLockVersion> SupportedVersions = new List<YarnLockVersion> { YarnLockVersion.V1, YarnLockVersion.V2 };
[Import]
public ILogger Logger { get; set; }
private readonly ILogger logger;
public YarnLockParser(ILogger logger) => this.logger = logger;
public static string NormalizeVersion(string version)
{
@ -124,7 +124,7 @@ public class YarnLockParser : IYarnLockParser
var versionValue = block.Values.FirstOrDefault(x => string.Equals(x.Key, VersionString, StringComparison.OrdinalIgnoreCase));
if (default(KeyValuePair<string, string>).Equals(versionValue))
{
this.Logger.LogWarning("Block without version detected");
this.logger.LogWarning("Block without version detected");
return blockTitleMember;
}

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Detectors.Yarn;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
@ -12,9 +11,22 @@ using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Npm;
[Export(typeof(IComponentDetector))]
public class YarnLockComponentDetector : FileComponentDetector
{
private readonly IYarnLockFileFactory yarnLockFileFactory;
public YarnLockComponentDetector(
IComponentStreamEnumerableFactory componentStreamEnumerableFactory,
IObservableDirectoryWalkerFactory walkerFactory,
IYarnLockFileFactory yarnLockFileFactory,
ILogger logger)
{
this.yarnLockFileFactory = yarnLockFileFactory;
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory;
this.Scanner = walkerFactory;
this.Logger = logger;
}
public override string Id { get; } = "Yarn";
public override IList<string> SearchPatterns { get; } = new List<string> { "yarn.lock" };
@ -45,7 +57,7 @@ public class YarnLockComponentDetector : FileComponentDetector
try
{
var parsed = await YarnLockFileFactory.ParseYarnLockFileAsync(file.Stream, this.Logger);
var parsed = await this.yarnLockFileFactory.ParseYarnLockFileAsync(file.Stream, this.Logger);
this.DetectComponents(parsed, file.Location, singleFileComponentRecorder);
}
catch (Exception ex)

Просмотреть файл

@ -5,17 +5,17 @@ using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Detectors.Yarn.Parsers;
public static class YarnLockFileFactory
public class YarnLockFileFactory : IYarnLockFileFactory
{
static YarnLockFileFactory() => Parsers = new List<IYarnLockParser> { new YarnLockParser() };
private readonly IEnumerable<IYarnLockParser> parsers;
public static IList<IYarnLockParser> Parsers { get; }
public YarnLockFileFactory(IEnumerable<IYarnLockParser> parsers) => this.parsers = parsers;
public static async Task<YarnLockFile> ParseYarnLockFileAsync(Stream file, ILogger logger)
public async Task<YarnLockFile> ParseYarnLockFileAsync(Stream file, ILogger logger)
{
var blockFile = await YarnBlockFile.CreateBlockFileAsync(file);
foreach (var parser in Parsers)
foreach (var parser in this.parsers)
{
if (parser.CanParse(blockFile.YarnLockVersion))
{

Просмотреть файл

@ -1,17 +1,14 @@
namespace Microsoft.ComponentDetection.Orchestrator;
namespace Microsoft.ComponentDetection.Orchestrator;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using CommandLine;
using Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
[Export(typeof(IArgumentHelper))]
public class ArgumentHelper : IArgumentHelper
{
public ArgumentHelper() => this.ArgumentSets = Enumerable.Empty<IScanArguments>();
private readonly IEnumerable<IScanArguments> argumentSets;
[ImportMany]
public IEnumerable<IScanArguments> ArgumentSets { get; set; }
public ArgumentHelper(IEnumerable<IScanArguments> argumentSets) => this.argumentSets = argumentSets;
public static IDictionary<string, string> GetDetectorArgs(IEnumerable<string> detectorArgsList)
{
@ -34,7 +31,7 @@ public class ArgumentHelper : IArgumentHelper
public ParserResult<object> ParseArguments(string[] args)
{
return Parser.Default.ParseArguments(args, this.ArgumentSets.Select(x => x.GetType()).ToArray());
return Parser.Default.ParseArguments(args, this.argumentSets.Select(x => x.GetType()).ToArray());
}
public ParserResult<T> ParseArguments<T>(string[] args, bool ignoreInvalidArgs = false)

Просмотреть файл

@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using CommandLine;
using Microsoft.ComponentDetection.Common;
using Microsoft.ComponentDetection.Contracts;
using Newtonsoft.Json;
public class BaseArguments : IScanArguments

Просмотреть файл

@ -1,12 +1,10 @@
namespace Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
namespace Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using CommandLine;
using Newtonsoft.Json;
[Verb("scan", HelpText = "Scans components")]
[Export(typeof(IScanArguments))]
public class BcdeArguments : BaseArguments, IDetectionArguments
{
[Option("DirectoryExclusionList", Required = false, Separator = ';', HelpText = "Filters out specific directories following a minimatch pattern.")]

Просмотреть файл

@ -1,9 +1,7 @@
namespace Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
using System.Composition;
namespace Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
using CommandLine;
[Verb("dev", HelpText = "Dev command", Hidden = true)]
[Export(typeof(IScanArguments))]
public class BcdeDevArguments : BcdeArguments, IDetectionArguments
{
// TODO: Add option to specify download directory for GH database

Просмотреть файл

@ -2,7 +2,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.ComponentDetection.Common;
using Microsoft.ComponentDetection.Contracts;
public interface IScanArguments
{

Просмотреть файл

@ -1,9 +1,7 @@
namespace Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
using System.Composition;
namespace Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
using CommandLine;
[Verb("list-detectors", HelpText = "Lists available detectors")]
[Export(typeof(IScanArguments))]
public class ListDetectionArgs : BaseArguments, IListDetectionArgs
{
}

Просмотреть файл

@ -1,15 +1,12 @@
namespace Microsoft.ComponentDetection.Orchestrator;
namespace Microsoft.ComponentDetection.Orchestrator;
using System;
using System.Composition;
using Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
[Export]
public class CommandLineArgumentsExporter
{
public CommandLineArgumentsExporter() => this.DelayedInjectionLazy = new Lazy<IScanArguments>(() => ArgumentsForDelayedInjection);
public static IScanArguments ArgumentsForDelayedInjection { get; set; }
[Export("InjectableDetectionArguments")]
public Lazy<IScanArguments> DelayedInjectionLazy { get; set; }
}

Просмотреть файл

@ -1,27 +0,0 @@
namespace Microsoft.ComponentDetection.Orchestrator.Exceptions;
using System;
using System.Runtime.Serialization;
[Serializable]
internal class NoDetectorsFoundException : Exception
{
public NoDetectorsFoundException()
: base("Unable to load any detector plugins.")
{
}
public NoDetectorsFoundException(string message)
: base(message)
{
}
public NoDetectorsFoundException(string message, Exception innerException)
: base(message, innerException)
{
}
protected NoDetectorsFoundException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}

Просмотреть файл

@ -1,13 +1,132 @@
namespace Microsoft.ComponentDetection.Orchestrator.Extensions;
using Microsoft.ComponentDetection.Common;
using Microsoft.ComponentDetection.Common.Telemetry;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Detectors.CocoaPods;
using Microsoft.ComponentDetection.Detectors.Dockerfile;
using Microsoft.ComponentDetection.Detectors.Go;
using Microsoft.ComponentDetection.Detectors.Gradle;
using Microsoft.ComponentDetection.Detectors.Ivy;
using Microsoft.ComponentDetection.Detectors.Linux;
using Microsoft.ComponentDetection.Detectors.Maven;
using Microsoft.ComponentDetection.Detectors.Npm;
using Microsoft.ComponentDetection.Detectors.NuGet;
using Microsoft.ComponentDetection.Detectors.Pip;
using Microsoft.ComponentDetection.Detectors.Pnpm;
using Microsoft.ComponentDetection.Detectors.Poetry;
using Microsoft.ComponentDetection.Detectors.Ruby;
using Microsoft.ComponentDetection.Detectors.Rust;
using Microsoft.ComponentDetection.Detectors.Spdx;
using Microsoft.ComponentDetection.Detectors.Vcpkg;
using Microsoft.ComponentDetection.Detectors.Yarn;
using Microsoft.ComponentDetection.Detectors.Yarn.Parsers;
using Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
using Microsoft.ComponentDetection.Orchestrator.Services;
using Microsoft.ComponentDetection.Orchestrator.Services.GraphTranslation;
using Microsoft.Extensions.DependencyInjection;
internal static class ServiceCollectionExtensions
public static class ServiceCollectionExtensions
{
/// <summary>
/// Register Component Detection services.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to register the services with.</param>
/// <returns>The <see cref="IServiceCollection" /> so that additional calls can be chained.</returns>
public static IServiceCollection AddComponentDetection(this IServiceCollection services) => services;
public static IServiceCollection AddComponentDetection(this IServiceCollection services)
{
services.AddSingleton<Orchestrator>();
// Shared services
services.AddSingleton<ITelemetryService, CommandLineTelemetryService>();
services.AddSingleton<ICommandLineInvocationService, CommandLineInvocationService>();
services.AddSingleton<IComponentStreamEnumerableFactory, ComponentStreamEnumerableFactory>();
services.AddSingleton<IConsoleWritingService, ConsoleWritingService>();
services.AddSingleton<IDockerService, DockerService>();
services.AddSingleton<IEnvironmentVariableService, EnvironmentVariableService>();
services.AddSingleton<IObservableDirectoryWalkerFactory, FastDirectoryWalkerFactory>();
services.AddSingleton<IFileUtilityService, FileUtilityService>();
services.AddSingleton<IFileWritingService, FileWritingService>();
services.AddSingleton<IGraphTranslationService, DefaultGraphTranslationService>();
services.AddSingleton<ILogger, Logger>();
services.AddSingleton<IPathUtilityService, PathUtilityService>();
services.AddSingleton<ISafeFileEnumerableFactory, SafeFileEnumerableFactory>();
// Command line services
services.AddSingleton<IScanArguments, BcdeArguments>();
services.AddSingleton<IScanArguments, BcdeDevArguments>();
services.AddSingleton<IScanArguments, ListDetectionArgs>();
services.AddSingleton<IArgumentHandlingService, BcdeDevCommandService>();
services.AddSingleton<IArgumentHandlingService, BcdeScanCommandService>();
services.AddSingleton<IArgumentHandlingService, DetectorListingCommandService>();
services.AddSingleton<IBcdeScanExecutionService, BcdeScanExecutionService>();
services.AddSingleton<IDetectorProcessingService, DetectorProcessingService>();
services.AddSingleton<IDetectorRestrictionService, DetectorRestrictionService>();
services.AddSingleton<IArgumentHelper, ArgumentHelper>();
// Detectors
// CocoaPods
services.AddSingleton<IComponentDetector, PodComponentDetector>();
// Dockerfile
services.AddSingleton<IComponentDetector, DockerfileComponentDetector>();
// Go
services.AddSingleton<IComponentDetector, GoComponentDetector>();
// Gradle
services.AddSingleton<IComponentDetector, GradleComponentDetector>();
// Ivy
services.AddSingleton<IComponentDetector, IvyDetector>();
// Linux
services.AddSingleton<ILinuxScanner, LinuxScanner>();
services.AddSingleton<IComponentDetector, LinuxContainerDetector>();
// Maven
services.AddSingleton<IMavenCommandService, MavenCommandService>();
services.AddSingleton<IMavenStyleDependencyGraphParserService, MavenStyleDependencyGraphParserService>();
services.AddSingleton<IComponentDetector, MvnCliComponentDetector>();
// npm
services.AddSingleton<IComponentDetector, NpmComponentDetector>();
services.AddSingleton<IComponentDetector, NpmComponentDetectorWithRoots>();
// NuGet
services.AddSingleton<IComponentDetector, NuGetComponentDetector>();
services.AddSingleton<IComponentDetector, NuGetPackagesConfigDetector>();
services.AddSingleton<IComponentDetector, NuGetProjectModelProjectCentricComponentDetector>();
// PIP
services.AddSingleton<IPyPiClient, PyPiClient>();
services.AddSingleton<IPythonCommandService, PythonCommandService>();
services.AddSingleton<IPythonResolver, PythonResolver>();
services.AddSingleton<IComponentDetector, PipComponentDetector>();
// pnpm
services.AddSingleton<IComponentDetector, PnpmComponentDetector>();
// Poetry
services.AddSingleton<IComponentDetector, PoetryComponentDetector>();
// Ruby
services.AddSingleton<IComponentDetector, RubyComponentDetector>();
// Rust
services.AddSingleton<IComponentDetector, RustCrateDetector>();
// SPDX
services.AddSingleton<IComponentDetector, Spdx22ComponentDetector>();
// VCPKG
services.AddSingleton<IComponentDetector, VcpkgComponentDetector>();
// Yarn
services.AddSingleton<IYarnLockParser, YarnLockParser>();
services.AddSingleton<IYarnLockFileFactory, YarnLockFileFactory>();
services.AddSingleton<IComponentDetector, YarnLockComponentDetector>();
return services;
}
}

Просмотреть файл

@ -4,4 +4,6 @@ using CommandLine;
public interface IArgumentHelper
{
ParserResult<object> ParseArguments(string[] args);
ParserResult<T> ParseArguments<T>(string[] args, bool ignoreInvalidArgs = false);
}

Просмотреть файл

@ -8,11 +8,6 @@
<PackageReference Include="Polly" />
<PackageReference Include="System.Runtime.Loader" />
<PackageReference Include="System.Threading.Tasks.Dataflow" />
<PackageReference Include="System.Composition.AttributedModel" />
<PackageReference Include="System.Composition.Convention" />
<PackageReference Include="System.Composition.Hosting" />
<PackageReference Include="System.Composition.Runtime" />
<PackageReference Include="System.Composition.TypedParts" />
<PackageReference Include="System.Reactive" />
</ItemGroup>

Просмотреть файл

@ -1,8 +1,6 @@
namespace Microsoft.ComponentDetection.Orchestrator;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Composition.Hosting;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
@ -19,30 +17,37 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.BcdeModels;
using Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
using Microsoft.ComponentDetection.Orchestrator.Services;
using Microsoft.ComponentDetection.Orchestrator.Services.GraphTranslation;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
public class Orchestrator
{
private static readonly bool IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
[ImportMany]
private static IEnumerable<IArgumentHandlingService> ArgumentHandlers { get; set; }
private readonly IServiceProvider serviceProvider;
private readonly IEnumerable<IArgumentHandlingService> argumentHandlers;
private readonly IFileWritingService fileWritingService;
private readonly IArgumentHelper argumentHelper;
private readonly ILogger logger;
[Import]
private static Logger Logger { get; set; }
[Import]
private static FileWritingService FileWritingService { get; set; }
[Import]
private static IArgumentHelper ArgumentHelper { get; set; }
public Orchestrator(
IServiceProvider serviceProvider,
IEnumerable<IArgumentHandlingService> argumentHandlers,
IFileWritingService fileWritingService,
IArgumentHelper argumentHelper,
ILogger logger)
{
this.serviceProvider = serviceProvider;
this.argumentHandlers = argumentHandlers;
this.fileWritingService = fileWritingService;
this.argumentHelper = argumentHelper;
this.logger = logger;
}
public async Task<ScanResult> LoadAsync(string[] args, CancellationToken cancellationToken = default)
{
var argumentHelper = new ArgumentHelper { ArgumentSets = new[] { new BaseArguments() } };
BaseArguments baseArguments = null;
var parserResult = argumentHelper.ParseArguments<BaseArguments>(args, true);
var parserResult = this.argumentHelper.ParseArguments<BaseArguments>(args, true);
parserResult.WithParsed(x => baseArguments = x);
if (parserResult.Tag == ParserResultType.NotParsed)
{
@ -50,27 +55,9 @@ public class Orchestrator
baseArguments = new BaseArguments();
}
var additionalDITargets = baseArguments.AdditionalDITargets ?? Enumerable.Empty<string>();
// Load all types from Common (where Logger lives) and our executing assembly.
var configuration = new ContainerConfiguration()
.WithAssembly(typeof(Logger).Assembly)
.WithAssembly(Assembly.GetExecutingAssembly());
foreach (var assemblyPath in additionalDITargets)
{
var assemblies = Assembly.LoadFrom(assemblyPath);
AddAssembliesWithType<ITelemetryService>(assemblies, configuration);
AddAssembliesWithType<IGraphTranslationService>(assemblies, configuration);
}
using (var container = configuration.CreateContainer())
{
container.SatisfyImports(this);
container.SatisfyImports(TelemetryRelay.Instance);
}
// This is required so TelemetryRelay can be accessed via it's static singleton
// It should be refactored out at a later date
TelemetryRelay.Instance.Init(this.serviceProvider.GetRequiredService<IEnumerable<ITelemetryService>>());
TelemetryRelay.Instance.SetTelemetryMode(baseArguments.DebugTelemetry ? TelemetryMode.Debug : TelemetryMode.Production);
var shouldFailureBeSuppressed = false;
@ -94,7 +81,7 @@ public class Orchestrator
// The order of these things is a little weird, but done this way mostly to prevent any of the logic inside if blocks from being duplicated
if (shouldFailureBeSuppressed)
{
Logger.LogInfo("The scan had some detections complete while others encountered errors. The log file should indicate any issues that happened during the scan.");
this.logger.LogInfo("The scan had some detections complete while others encountered errors. The log file should indicate any issues that happened during the scan.");
}
if (returnResult.ResultCode == ProcessingResultCode.TimeoutError)
@ -119,13 +106,6 @@ public class Orchestrator
return returnResult;
}
private static void AddAssembliesWithType<T>(Assembly assembly, ContainerConfiguration containerConfiguration)
{
assembly.GetTypes()
.Where(x => typeof(T).IsAssignableFrom(x)).ToList()
.ForEach(service => containerConfiguration = containerConfiguration.WithPart(service));
}
public async Task<ScanResult> HandleCommandAsync(
string[] args,
BcdeExecutionTelemetryRecord telemetryRecord,
@ -136,7 +116,7 @@ public class Orchestrator
ResultCode = ProcessingResultCode.Error,
};
var parsedArguments = ArgumentHelper.ParseArguments(args);
var parsedArguments = this.argumentHelper.ParseArguments(args);
await parsedArguments.WithParsedAsync<IScanArguments>(async argumentSet =>
{
CommandLineArgumentsExporter.ArgumentsForDelayedInjection = argumentSet;
@ -150,9 +130,9 @@ public class Orchestrator
await this.GenerateEnvironmentSpecificTelemetryAsync(telemetryRecord);
telemetryRecord.Arguments = JsonConvert.SerializeObject(argumentSet);
FileWritingService.Init(argumentSet.Output);
Logger.Init(argumentSet.Verbosity, writeLinePrefix: true);
Logger.LogInfo($"Run correlation id: {TelemetryConstants.CorrelationId}");
this.fileWritingService.Init(argumentSet.Output);
this.logger.Init(argumentSet.Verbosity, writeLinePrefix: true);
this.logger.LogInfo($"Run correlation id: {TelemetryConstants.CorrelationId}");
return await this.DispatchAsync(argumentSet, cancellationToken);
});
@ -229,13 +209,13 @@ public class Orchestrator
ResultCode = ProcessingResultCode.Error,
};
if (ArgumentHandlers == null)
if (this.argumentHandlers == null)
{
Logger.LogError("No argument handling services were registered.");
this.logger.LogError("No argument handling services were registered.");
return scanResult;
}
foreach (var handler in ArgumentHandlers)
foreach (var handler in this.argumentHandlers)
{
if (handler.CanHandle(arguments))
{
@ -246,7 +226,7 @@ public class Orchestrator
}
catch (TimeoutException timeoutException)
{
Logger.LogError(timeoutException.Message);
this.logger.LogError(timeoutException.Message);
scanResult.ResultCode = ProcessingResultCode.TimeoutError;
}
@ -254,7 +234,7 @@ public class Orchestrator
}
}
Logger.LogError("No handlers for the provided Argument Set were found.");
this.logger.LogError("No handlers for the provided Argument Set were found.");
return scanResult;
}
@ -274,8 +254,8 @@ public class Orchestrator
var e = ae.GetBaseException();
if (e is InvalidUserInputException)
{
Logger.LogError($"Something bad happened, is everything configured correctly?");
Logger.LogException(e, isError: true, printException: true);
this.logger.LogError($"Something bad happened, is everything configured correctly?");
this.logger.LogException(e, isError: true, printException: true);
record.ErrorMessage = e.ToString();
result.ResultCode = ProcessingResultCode.InputError;
@ -285,8 +265,8 @@ public class Orchestrator
else
{
// On an exception, return error to dotnet core
Logger.LogError($"There was an unexpected error: ");
Logger.LogException(e, isError: true);
this.logger.LogError($"There was an unexpected error: ");
this.logger.LogException(e, isError: true);
var errorMessage = new StringBuilder();
errorMessage.AppendLine(e.ToString());
@ -295,7 +275,7 @@ public class Orchestrator
foreach (var loaderException in refEx.LoaderExceptions)
{
var loaderExceptionString = loaderException.ToString();
Logger.LogError(loaderExceptionString);
this.logger.LogError(loaderExceptionString);
errorMessage.AppendLine(loaderExceptionString);
}
}

Просмотреть файл

@ -1,16 +1,21 @@
namespace Microsoft.ComponentDetection.Orchestrator.Services;
namespace Microsoft.ComponentDetection.Orchestrator.Services;
using System;
using System.Composition;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.BcdeModels;
using Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
[Export(typeof(IArgumentHandlingService))]
public class BcdeDevCommandService : ServiceBase, IArgumentHandlingService
{
[Import]
public IBcdeScanExecutionService BcdeScanExecutionService { get; set; }
private readonly IBcdeScanExecutionService bcdeScanExecutionService;
public BcdeDevCommandService(IBcdeScanExecutionService bcdeScanExecutionService, ILogger logger)
{
this.bcdeScanExecutionService = bcdeScanExecutionService;
this.Logger = logger;
}
public bool CanHandle(IScanArguments arguments)
{
@ -22,7 +27,7 @@ public class BcdeDevCommandService : ServiceBase, IArgumentHandlingService
// Run BCDE with the given arguments
var detectionArguments = arguments as BcdeArguments;
var result = await this.BcdeScanExecutionService.ExecuteScanAsync(detectionArguments);
var result = await this.bcdeScanExecutionService.ExecuteScanAsync(detectionArguments);
var detectedComponents = result.ComponentsFound.ToList();
foreach (var detectedComponent in detectedComponents)
{

Просмотреть файл

@ -1,22 +1,29 @@
namespace Microsoft.ComponentDetection.Orchestrator.Services;
using System.Composition;
namespace Microsoft.ComponentDetection.Orchestrator.Services;
using System.IO;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Common;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.BcdeModels;
using Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
using Newtonsoft.Json;
[Export(typeof(IArgumentHandlingService))]
public class BcdeScanCommandService : ServiceBase, IArgumentHandlingService
{
public const string ManifestRelativePath = "ScanManifest_{timestamp}.json";
[Import]
public IFileWritingService FileWritingService { get; set; }
private readonly IFileWritingService fileWritingService;
private readonly IBcdeScanExecutionService bcdeScanExecutionService;
[Import]
public IBcdeScanExecutionService BcdeScanExecutionService { get; set; }
public BcdeScanCommandService(
IFileWritingService fileWritingService,
IBcdeScanExecutionService bcdeScanExecutionService,
ILogger logger)
{
this.fileWritingService = fileWritingService;
this.bcdeScanExecutionService = bcdeScanExecutionService;
this.Logger = logger;
}
public bool CanHandle(IScanArguments arguments)
{
@ -26,7 +33,7 @@ public class BcdeScanCommandService : ServiceBase, IArgumentHandlingService
public async Task<ScanResult> HandleAsync(IScanArguments arguments)
{
var bcdeArguments = (BcdeArguments)arguments;
var result = await this.BcdeScanExecutionService.ExecuteScanAsync(bcdeArguments);
var result = await this.bcdeScanExecutionService.ExecuteScanAsync(bcdeArguments);
this.WriteComponentManifest(bcdeArguments, result);
return result;
}
@ -42,16 +49,16 @@ public class BcdeScanCommandService : ServiceBase, IArgumentHandlingService
}
else
{
this.Logger.LogInfo($"Scan Manifest file: {this.FileWritingService.ResolveFilePath(ManifestRelativePath)}");
this.Logger.LogInfo($"Scan Manifest file: {this.fileWritingService.ResolveFilePath(ManifestRelativePath)}");
}
if (userRequestedManifestPath == null)
{
this.FileWritingService.AppendToFile(ManifestRelativePath, JsonConvert.SerializeObject(scanResult, Formatting.Indented));
this.fileWritingService.AppendToFile(ManifestRelativePath, JsonConvert.SerializeObject(scanResult, Formatting.Indented));
}
else
{
this.FileWritingService.WriteFile(userRequestedManifestPath, JsonConvert.SerializeObject(scanResult, Formatting.Indented));
this.fileWritingService.WriteFile(userRequestedManifestPath, JsonConvert.SerializeObject(scanResult, Formatting.Indented));
}
}
}

Просмотреть файл

@ -2,50 +2,45 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.BcdeModels;
using Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
using Microsoft.ComponentDetection.Orchestrator.Exceptions;
using Microsoft.ComponentDetection.Orchestrator.Services.GraphTranslation;
[Export(typeof(IBcdeScanExecutionService))]
public class BcdeScanExecutionService : ServiceBase, IBcdeScanExecutionService
{
[Import]
public IDetectorRegistryService DetectorRegistryService { get; set; }
private readonly IEnumerable<IComponentDetector> detectors;
private readonly IDetectorProcessingService detectorProcessingService;
private readonly IDetectorRestrictionService detectorRestrictionService;
private readonly IGraphTranslationService graphTranslationService;
[Import]
public IDetectorProcessingService DetectorProcessingService { get; set; }
[Import]
public IDetectorRestrictionService DetectorRestrictionService { get; set; }
[ImportMany]
public IEnumerable<Lazy<IGraphTranslationService, GraphTranslationServiceMetadata>> GraphTranslationServices { get; set; }
public BcdeScanExecutionService(
IEnumerable<IComponentDetector> detectors,
IDetectorProcessingService detectorProcessingService,
IDetectorRestrictionService detectorRestrictionService,
IGraphTranslationService graphTranslationService,
ILogger logger)
{
this.detectors = detectors;
this.detectorProcessingService = detectorProcessingService;
this.detectorRestrictionService = detectorRestrictionService;
this.graphTranslationService = graphTranslationService;
this.Logger = logger;
}
public async Task<ScanResult> ExecuteScanAsync(IDetectionArguments detectionArguments)
{
this.Logger.LogCreateLoggingGroup();
var initialDetectors = this.DetectorRegistryService.GetDetectors(detectionArguments.AdditionalPluginDirectories, detectionArguments.AdditionalDITargets, detectionArguments.SkipPluginsDirectory).ToImmutableList();
if (!initialDetectors.Any())
{
throw new NoDetectorsFoundException();
}
var detectorRestrictions = this.GetDetectorRestrictions(detectionArguments);
var detectors = this.DetectorRestrictionService.ApplyRestrictions(detectorRestrictions, initialDetectors).ToImmutableList();
var detectors = this.detectorRestrictionService.ApplyRestrictions(detectorRestrictions, this.detectors).ToImmutableList();
this.Logger.LogVerbose($"Finished applying restrictions to detectors.");
var processingResult = await this.DetectorProcessingService.ProcessDetectorsAsync(detectionArguments, detectors, detectorRestrictions);
var graphTranslationService = this.GraphTranslationServices.OrderBy(gts => gts.Metadata.Priority).Last().Value;
var scanResult = graphTranslationService.GenerateScanResultFromProcessingResult(processingResult, detectionArguments);
var processingResult = await this.detectorProcessingService.ProcessDetectorsAsync(detectionArguments, detectors, detectorRestrictions);
var scanResult = this.graphTranslationService.GenerateScanResultFromProcessingResult(processingResult, detectionArguments);
scanResult.DetectorsInScan = detectors.Select(x => ConvertToContract(x)).ToList();
scanResult.ResultCode = processingResult.ResultCode;

Просмотреть файл

@ -1,16 +1,21 @@
namespace Microsoft.ComponentDetection.Orchestrator.Services;
using System.Composition;
using System.Linq;
namespace Microsoft.ComponentDetection.Orchestrator.Services;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.BcdeModels;
using Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
[Export(typeof(IArgumentHandlingService))]
public class DetectorListingCommandService : ServiceBase, IArgumentHandlingService
{
[Import]
public IDetectorRegistryService DetectorRegistryService { get; set; }
private readonly IEnumerable<IComponentDetector> detectors;
public DetectorListingCommandService(
IEnumerable<IComponentDetector> detectors,
ILogger logger)
{
this.detectors = detectors;
this.Logger = logger;
}
public bool CanHandle(IScanArguments arguments)
{
@ -28,13 +33,9 @@ public class DetectorListingCommandService : ServiceBase, IArgumentHandlingServi
private async Task<ProcessingResultCode> ListDetectorsAsync(IScanArguments listArguments)
{
var detectors = this.DetectorRegistryService.GetDetectors(listArguments.AdditionalPluginDirectories, listArguments.AdditionalDITargets, listArguments.SkipPluginsDirectory);
if (detectors.Any())
foreach (var detector in this.detectors)
{
foreach (var detector in detectors)
{
this.Logger.LogInfo($"{detector.Id}");
}
this.Logger.LogInfo($"{detector.Id}");
}
return await Task.FromResult(ProcessingResultCode.Success);

Просмотреть файл

@ -2,7 +2,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Composition;
using System.Diagnostics;
using System.IO;
using System.Linq;
@ -18,18 +17,17 @@ using Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
using Newtonsoft.Json;
using static System.Environment;
[Export(typeof(IDetectorProcessingService))]
[Shared]
public class DetectorProcessingService : ServiceBase, IDetectorProcessingService
{
/// <summary>
/// Gets or sets the factory for handing back component streams to File detectors. Injected automatically by MEF composition.
/// </summary>
[Import]
public IComponentStreamEnumerableFactory ComponentStreamEnumerableFactory { get; set; }
private readonly IObservableDirectoryWalkerFactory scanner;
[Import]
public IObservableDirectoryWalkerFactory Scanner { get; set; }
public DetectorProcessingService(
IObservableDirectoryWalkerFactory scanner,
ILogger logger)
{
this.scanner = scanner;
this.Logger = logger;
}
public async Task<DetectorProcessingResult> ProcessDetectorsAsync(IDetectionArguments detectionArguments, IEnumerable<IComponentDetector> detectors, DetectorRestrictions detectorRestrictions)
{

Просмотреть файл

@ -1,162 +0,0 @@
namespace Microsoft.ComponentDetection.Orchestrator.Services;
using System.Collections.Generic;
using System.Composition;
using System.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.ComponentDetection.Common.Telemetry.Records;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Detectors;
// Note : This class isn't unit testable in a meaningful way. Be careful when making changes that you're sure you can test them manually. This class should remain very simple to help prevent future bugs.
[Export(typeof(IDetectorRegistryService))]
[Shared]
public class DetectorRegistryService : ServiceBase, IDetectorRegistryService
{
[Import]
public IDetectorDependencies DetectorDependencies { get; set; }
private IEnumerable<IComponentDetector> ComponentDetectors { get; set; }
public IEnumerable<IComponentDetector> GetDetectors(IEnumerable<DirectoryInfo> additionalSearchDirectories, IEnumerable<string> extraDetectorAssemblies, bool skipPluginsDirectory = false)
{
var directoriesToSearch = new List<DirectoryInfo>();
// Checking Plugins directory is not required when skip argument is provided
if (!skipPluginsDirectory)
{
var executableLocation = Assembly.GetEntryAssembly().Location;
var searchPath = Path.Combine(Path.GetDirectoryName(executableLocation), "Plugins");
directoriesToSearch.Add(new DirectoryInfo(searchPath));
}
if (additionalSearchDirectories != null)
{
directoriesToSearch.AddRange(additionalSearchDirectories);
}
this.ComponentDetectors = this.GetComponentDetectors(directoriesToSearch, extraDetectorAssemblies);
if (!this.ComponentDetectors.Any())
{
this.Logger.LogError($"No component detectors were found in {directoriesToSearch.FirstOrDefault()} or other provided search paths.");
}
return this.ComponentDetectors;
}
public IEnumerable<IComponentDetector> GetDetectors(Assembly assemblyToSearch, IEnumerable<string> extraDetectorAssemblies)
{
this.Logger.LogInfo($"Attempting to load component detectors from {assemblyToSearch.FullName}");
var loadedDetectors = this.LoadComponentDetectorsFromAssemblies(new List<Assembly> { assemblyToSearch }, extraDetectorAssemblies);
var pluralPhrase = loadedDetectors.Count == 1 ? "detector was" : "detectors were";
this.Logger.LogInfo($"{loadedDetectors.Count} {pluralPhrase} found in {assemblyToSearch.FullName}");
return loadedDetectors;
}
private IList<IComponentDetector> GetComponentDetectors(IEnumerable<DirectoryInfo> searchPaths, IEnumerable<string> extraDetectorAssemblies)
{
var detectors = new List<IComponentDetector>();
using (var record = new LoadComponentDetectorsTelemetryRecord())
{
this.Logger.LogInfo($"Attempting to load default detectors");
var assembly = Assembly.GetAssembly(typeof(IComponentGovernanceOwnedDetectors));
var loadedDetectors = this.LoadComponentDetectorsFromAssemblies(new[] { assembly }, extraDetectorAssemblies);
var pluralPhrase = loadedDetectors.Count == 1 ? "detector was" : "detectors were";
this.Logger.LogInfo($"{loadedDetectors.Count} {pluralPhrase} found in {assembly.GetName().Name}\n");
detectors.AddRange(loadedDetectors);
record.DetectorIds = string.Join(",", loadedDetectors.Select(x => x.Id));
}
foreach (var searchPath in searchPaths)
{
if (!searchPath.Exists)
{
this.Logger.LogWarning($"Provided search path {searchPath.FullName} does not exist.");
continue;
}
using var record = new LoadComponentDetectorsTelemetryRecord();
this.Logger.LogInfo($"Attempting to load component detectors from {searchPath}");
var assemblies = this.SafeLoadAssemblies(searchPath.GetFiles("*.dll", SearchOption.AllDirectories).Select(x => x.FullName));
var loadedDetectors = this.LoadComponentDetectorsFromAssemblies(assemblies, extraDetectorAssemblies);
var pluralPhrase = loadedDetectors.Count == 1 ? "detector was" : "detectors were";
this.Logger.LogInfo($"{loadedDetectors.Count} {pluralPhrase} found in {searchPath}\n");
detectors.AddRange(loadedDetectors);
record.DetectorIds = string.Join(",", loadedDetectors.Select(x => x.Id));
}
return detectors;
}
private IList<IComponentDetector> LoadComponentDetectorsFromAssemblies(IEnumerable<Assembly> assemblies, IEnumerable<string> extraDetectorAssemblies)
{
new InjectionParameters(this.DetectorDependencies);
var configuration = new ContainerConfiguration()
.WithAssemblies(assemblies);
foreach (var detectorAssemblyPath in extraDetectorAssemblies)
{
var detectorAssembly = Assembly.LoadFrom(detectorAssemblyPath);
var detectorTypes = detectorAssembly.GetTypes().Where(x => typeof(IComponentDetector).IsAssignableFrom(x));
foreach (var detectorType in detectorTypes)
{
configuration = configuration.WithPart(detectorType);
}
}
configuration = configuration
.WithPart(typeof(InjectionParameters));
using var container = configuration.CreateContainer();
return container.GetExports<IComponentDetector>().ToList();
}
// Plugin producers may include files we have already loaded
private IList<Assembly> SafeLoadAssemblies(IEnumerable<string> files)
{
var assemblyList = new List<Assembly>();
foreach (var file in files)
{
try
{
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(file);
assemblyList.Add(assembly);
}
catch (FileLoadException ex)
{
if (ex.Message == "Assembly with same name is already loaded")
{
continue;
}
else
{
throw;
}
}
}
return assemblyList;
}
}

Просмотреть файл

@ -1,19 +1,18 @@
namespace Microsoft.ComponentDetection.Orchestrator.Services;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Orchestrator.Exceptions;
[Export(typeof(IDetectorRestrictionService))]
public class DetectorRestrictionService : IDetectorRestrictionService
{
private readonly IList<string> oldDetectorIds = new List<string> { "MSLicenseDevNpm", "MSLicenseDevNpmList", "MSLicenseNpm", "MSLicenseNpmList" };
private readonly string newDetectorId = "NpmWithRoots";
[Import]
public ILogger Logger { get; set; }
private readonly ILogger logger;
public DetectorRestrictionService(ILogger logger) => this.logger = logger;
public IEnumerable<IComponentDetector> ApplyRestrictions(DetectorRestrictions restrictions, IEnumerable<IComponentDetector> detectors)
{
@ -47,7 +46,7 @@ public class DetectorRestrictionService : IDetectorRestrictionService
}
else
{
this.Logger.LogWarning($"The detector '{id}' has been phased out, we will run the '{this.newDetectorId}' detector which replaced its functionality.");
this.logger.LogWarning($"The detector '{id}' has been phased out, we will run the '{this.newDetectorId}' detector which replaced its functionality.");
}
}
}

Просмотреть файл

@ -1,7 +1,6 @@
namespace Microsoft.ComponentDetection.Orchestrator.Services.GraphTranslation;
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -13,10 +12,10 @@ using Microsoft.ComponentDetection.Contracts.BcdeModels;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Orchestrator.ArgumentSets;
[Export(typeof(IGraphTranslationService))]
[ExportMetadata("Priority", 0)]
public class DefaultGraphTranslationService : ServiceBase, IGraphTranslationService
{
public DefaultGraphTranslationService(ILogger logger) => this.Logger = logger;
public ScanResult GenerateScanResultFromProcessingResult(DetectorProcessingResult detectorProcessingResult, IDetectionArguments detectionArguments)
{
var recorderDetectorPairs = detectorProcessingResult.ComponentRecorders;

Просмотреть файл

@ -1,12 +0,0 @@
namespace Microsoft.ComponentDetection.Orchestrator.Services.GraphTranslation;
using System.ComponentModel;
public class GraphTranslationServiceMetadata
{
/// <summary>
/// Gets the priority level for the exported service.
/// This allows the importer of the graph translation service to pick the most preferred service.
/// </summary>
[DefaultValue(0)]
public int Priority { get; }
}

Просмотреть файл

@ -1,12 +0,0 @@
namespace Microsoft.ComponentDetection.Orchestrator.Services;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Microsoft.ComponentDetection.Contracts;
public interface IDetectorRegistryService
{
IEnumerable<IComponentDetector> GetDetectors(IEnumerable<DirectoryInfo> additionalSearchDirectories, IEnumerable<string> extraDetectorAssemblies, bool skipPluginsDirectory = false);
IEnumerable<IComponentDetector> GetDetectors(Assembly assemblyToSearch, IEnumerable<string> extraDetectorAssemblies);
}

Просмотреть файл

@ -1,9 +1,7 @@
namespace Microsoft.ComponentDetection.Orchestrator.Services;
using System.Composition;
namespace Microsoft.ComponentDetection.Orchestrator.Services;
using Microsoft.ComponentDetection.Contracts;
public abstract class ServiceBase
{
[Import]
public ILogger Logger { get; set; }
protected ILogger Logger { get; set; }
}

Просмотреть файл

@ -1,51 +1,42 @@
namespace Microsoft.ComponentDetection;
using System;
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Orchestrator;
using Microsoft.ComponentDetection.Orchestrator.Extensions;
using Microsoft.Extensions.DependencyInjection;
public static class Program
try
{
public static async Task Main(string[] args)
if (args.Contains("--debug", StringComparer.OrdinalIgnoreCase))
{
try
Console.WriteLine($"Waiting for debugger attach. PID: {Process.GetCurrentProcess().Id}");
while (!Debugger.IsAttached)
{
AppDomain.CurrentDomain.ProcessExit += (not, used) =>
{
Console.WriteLine($"Process terminating.");
};
if (args.Any(x => string.Equals(x, "--Debug", StringComparison.OrdinalIgnoreCase)))
{
Console.WriteLine($"Waiting for debugger attach. PID: {Process.GetCurrentProcess().Id}");
while (!Debugger.IsAttached)
{
await Task.Delay(1000);
}
}
var orchestrator = new Orchestrator.Orchestrator();
var result = await orchestrator.LoadAsync(args);
var exitCode = (int)result.ResultCode;
if (result.ResultCode == ProcessingResultCode.Error || result.ResultCode == ProcessingResultCode.InputError)
{
exitCode = -1;
}
Console.WriteLine($"Execution finished, status: {exitCode}.");
// force an exit, not letting any lingering threads not responding.
Environment.Exit(exitCode);
}
catch (ArgumentException ae)
{
await Console.Error.WriteLineAsync(ae.ToString());
Environment.Exit(-1);
await Task.Delay(1000);
}
}
var serviceProvider = new ServiceCollection()
.AddComponentDetection()
.BuildServiceProvider();
var orchestrator = serviceProvider.GetRequiredService<Orchestrator>();
var result = await orchestrator.LoadAsync(args);
var exitCode = (int)result.ResultCode;
if (result.ResultCode is ProcessingResultCode.Error or ProcessingResultCode.InputError)
{
exitCode = -1;
}
Console.WriteLine($"Execution finished, status: {exitCode}.");
// force an exit, not letting any lingering threads not responding.
Environment.Exit(exitCode);
}
catch (ArgumentException ae)
{
await Console.Error.WriteLineAsync(ae.ToString());
Environment.Exit(-1);
}

Просмотреть файл

@ -3,8 +3,10 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
[TestClass]
[TestCategory("Governance/All")]
@ -15,13 +17,10 @@ public class DockerServiceTests
private const string TestImageWithBaseDetails = "governancecontainerregistry.azurecr.io/testcontainers/dockertags_test:testtag";
private DockerService dockerService;
private readonly Mock<ILogger> loggerMock = new();
private readonly DockerService dockerService;
[TestInitialize]
public void TestInitialize()
{
this.dockerService = new DockerService();
}
public DockerServiceTests() => this.dockerService = new DockerService(this.loggerMock.Object);
[TestMethod]
public async Task DockerService_CanPingDockerAsync()
@ -62,7 +61,7 @@ public class DockerServiceTests
details.Should().NotBeNull();
details.Tags.Should().Contain("governancecontainerregistry.azurecr.io/testcontainers/dockertags_test:testtag");
var expectedImageId = "sha256:5edc12e9a797b59b9209354ff99d8550e7a1f90ca924c103fa3358e1a9ce15fe";
var expectedCreatedAt = DateTime.Parse("2021-09-23T23:47:57.442225064Z");
var expectedCreatedAt = DateTime.Parse("2021-09-23T23:47:57.442225064Z").ToUniversalTime();
details.Should().NotBeNull();
details.Id.Should().BeGreaterThan(0);

Просмотреть файл

@ -23,7 +23,7 @@ public class FileEnumerationTests
var loggerMock = new Mock<ILogger>();
var pathUtility = new PathUtilityService();
var pathUtility = new PathUtilityService(loggerMock.Object);
var sfe = new SafeFileEnumerable(new DirectoryInfo(Path.Combine(testDirectory, "root")), new[] { "*" }, loggerMock.Object, pathUtility, (name, directoryName) => false, true);
var foundFiles = new List<string>();

Просмотреть файл

@ -1,5 +1,6 @@
namespace Microsoft.ComponentDetection.Common.Tests;
using System;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
@ -8,11 +9,10 @@ using Moq;
[TestCategory("Governance/ComponentDetection")]
public class LoggerTests
{
private Mock<IFileWritingService> fileWritingServiceMock;
private Mock<IConsoleWritingService> consoleWritingServiceMock;
private readonly Mock<IFileWritingService> fileWritingServiceMock;
private readonly Mock<IConsoleWritingService> consoleWritingServiceMock;
[TestInitialize]
public void TestInitialize()
public LoggerTests()
{
this.consoleWritingServiceMock = new Mock<IConsoleWritingService>();
this.fileWritingServiceMock = new Mock<IFileWritingService>();
@ -28,11 +28,7 @@ public class LoggerTests
[TestMethod]
public void LogCreateLoggingGroup_HandlesFailedInit()
{
var logger = new Logger
{
ConsoleWriter = this.consoleWritingServiceMock.Object,
FileWritingService = null,
};
var logger = new Logger(this.consoleWritingServiceMock.Object, null);
// This should throw an exception while setting up the file writing service, but handle it
logger.Init(VerbosityMode.Normal);
@ -264,11 +260,7 @@ public class LoggerTests
private Logger CreateLogger(VerbosityMode verbosityMode)
{
var serviceUnderTest = new Logger
{
ConsoleWriter = this.consoleWritingServiceMock.Object,
FileWritingService = this.fileWritingServiceMock.Object,
};
var serviceUnderTest = new Logger(this.consoleWritingServiceMock.Object, this.fileWritingServiceMock.Object);
serviceUnderTest.Init(verbosityMode);

Просмотреть файл

@ -0,0 +1,10 @@
namespace Microsoft.ComponentDetection.Detectors.Tests;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.TestsUtilities;
public abstract class BaseDetectorTest<T>
where T : FileComponentDetector
{
private protected DetectorTestUtilityBuilder<T> DetectorTestUtility { get; } = new();
}

Просмотреть файл

@ -1,57 +1,34 @@
namespace Microsoft.ComponentDetection.Detectors.Tests;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.ComponentDetection.Common.DependencyGraph;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Go;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class GoComponentDetectorTests
public class GoComponentDetectorTests : BaseDetectorTest<GoComponentDetector>
{
private DetectorTestUtility<GoComponentDetector> detectorTestUtility;
private Mock<ICommandLineInvocationService> commandLineMock;
private readonly Mock<ICommandLineInvocationService> commandLineMock;
private readonly Mock<IEnvironmentVariableService> envVarService;
private Mock<IEnvironmentVariableService> envVarService;
private ScanRequest scanRequest;
[TestInitialize]
public void TestInitialize()
public GoComponentDetectorTests()
{
this.commandLineMock = new Mock<ICommandLineInvocationService>();
this.envVarService = new Mock<IEnvironmentVariableService>();
var loggerMock = new Mock<ILogger>();
this.envVarService.Setup(x => x.IsEnvironmentVariableValueTrue("DisableGoCliScan")).Returns(true);
var detector = new GoComponentDetector
{
CommandLineInvocationService = this.commandLineMock.Object,
Logger = loggerMock.Object,
EnvVarService = this.envVarService.Object,
};
var tempPath = Path.GetTempPath();
var detectionPath = Path.Combine(tempPath, Guid.NewGuid().ToString());
Directory.CreateDirectory(detectionPath);
this.scanRequest = new ScanRequest(new DirectoryInfo(detectionPath), (name, directoryName) => false, loggerMock.Object, null, null, new ComponentRecorder());
this.detectorTestUtility = DetectorTestUtilityCreator.Create<GoComponentDetector>()
.WithScanRequest(this.scanRequest)
.WithDetector(detector);
this.commandLineMock.Setup(x => x.CanCommandBeLocatedAsync("go", null, It.IsAny<DirectoryInfo>(), It.IsAny<string[]>()))
.ReturnsAsync(false);
this.DetectorTestUtility.AddServiceMock(this.commandLineMock);
this.envVarService = new Mock<IEnvironmentVariableService>();
this.envVarService.Setup(x => x.IsEnvironmentVariableValueTrue("DisableGoCliScan")).Returns(true);
this.DetectorTestUtility.AddServiceMock(this.envVarService);
}
[TestMethod]
@ -66,7 +43,7 @@ require (
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
github.com/dgrijalva/jwt-go v3.2.0+incompatible
)";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("go.mod", goMod)
.ExecuteDetectorAsync();
@ -97,7 +74,7 @@ github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
)";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("go.sum", goSum)
.ExecuteDetectorAsync();
@ -133,7 +110,7 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
)";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("go.mod", goMod)
.ExecuteDetectorAsync();
@ -171,7 +148,7 @@ require (
github.com/Azure/go-autorest v10.15.2+incompatible
)";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("go.mod", goMod1)
.WithFile("go.mod", goMod2, fileLocation: Path.Join(Path.GetTempPath(), "another-location", "go.mod"))
.ExecuteDetectorAsync();
@ -197,7 +174,7 @@ lorem ipsum
four score and seven bugs ago
$#26^#25%4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("go.mod", invalidGoMod)
.ExecuteDetectorAsync();
@ -214,7 +191,7 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwC
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
)";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("go.sum", goSum)
.ExecuteDetectorAsync();
@ -239,7 +216,7 @@ replace (
github.com/docker/distribution => github.com/docker/distribution v0.0.0-20191216044856-a8371794149d
)
";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("go.mod", goMod)
.ExecuteDetectorAsync();
@ -359,7 +336,7 @@ replace (
this.envVarService.Setup(x => x.IsEnvironmentVariableValueTrue("DisableGoCliScan")).Returns(false);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("go.mod", string.Empty)
.ExecuteDetectorAsync();
@ -421,7 +398,7 @@ github.com/prometheus/client_golang@v1.12.1 github.com/prometheus/common@v0.32.1
this.envVarService.Setup(x => x.IsEnvironmentVariableValueTrue("DisableGoCliScan")).Returns(false);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("go.mod", string.Empty)
.ExecuteDetectorAsync();

Просмотреть файл

@ -7,26 +7,17 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Gradle;
using Microsoft.ComponentDetection.Detectors.Tests.Utilities;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class GradleComponentDetectorTests
public class GradleComponentDetectorTests : BaseDetectorTest<GradleComponentDetector>
{
private DetectorTestUtility<GradleComponentDetector> detectorTestUtility;
[TestInitialize]
public void TestInitialize()
{
this.detectorTestUtility = DetectorTestUtilityCreator.Create<GradleComponentDetector>();
}
[TestMethod]
public async Task TestGradleDetectorWithNoFiles_ReturnsSuccessfullyAsync()
{
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
@ -41,7 +32,7 @@ public class GradleComponentDetectorTests
org.springframework:spring-core:5.0.5.RELEASE
org.springframework:spring-jcl:5.0.5.RELEASE";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("gradle.lockfile", validFileOne)
.ExecuteDetectorAsync();
@ -72,7 +63,7 @@ org.springframework:spring-jcl:5.0.5.RELEASE";
org.springframework:spring-core:5.0.5.RELEASE=debugCompile,releaseCompile
org.springframework:spring-jcl:5.0.5.RELEASE=lintClassPath,debugCompile,releaseCompile";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("gradle.lockfile", validFileOne)
.ExecuteDetectorAsync();
@ -111,7 +102,7 @@ com.fasterxml.jackson.core:jackson-databind:2.8.11.3
org.msgpack:msgpack-core:0.8.16
org.springframework:spring-jcl:5.0.5.RELEASE";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("gradle.lockfile", validFileOne)
.WithFile("gradle2.lockfile", validFileTwo)
.ExecuteDetectorAsync();
@ -156,7 +147,7 @@ org.springframework:spring-jcl:5.0.5.RELEASE";
var validFileTwo =
"org.springframework:spring-beans:5.0.5.RELEASE";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("gradle.lockfile", validFileOne)
.WithFile("gradle2.lockfile", validFileTwo)
.ExecuteDetectorAsync();
@ -194,7 +185,7 @@ lorem ipsum
four score and seven bugs ago
$#26^#25%4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("gradle.lockfile", invalidFileOne)
.WithFile("gradle2.lockfile", validFileTwo)
.ExecuteDetectorAsync();

Просмотреть файл

@ -5,50 +5,23 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.ComponentDetection.Common.DependencyGraph;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Ivy;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class IvyDetectorTests
public class IvyDetectorTests : BaseDetectorTest<IvyDetector>
{
private Mock<ICommandLineInvocationService> commandLineMock;
private DetectorTestUtility<IvyDetector> detectorTestUtility;
private ScanRequest scanRequest;
private readonly Mock<ICommandLineInvocationService> commandLineMock;
[TestInitialize]
public void InitializeTests()
public IvyDetectorTests()
{
this.commandLineMock = new Mock<ICommandLineInvocationService>();
var loggerMock = new Mock<ILogger>();
var detector = new IvyDetector
{
CommandLineInvocationService = this.commandLineMock.Object,
Logger = loggerMock.Object,
};
var tempPath = Path.GetTempPath();
var detectionPath = Path.Combine(tempPath, Guid.NewGuid().ToString());
Directory.CreateDirectory(detectionPath);
this.scanRequest = new ScanRequest(new DirectoryInfo(detectionPath), (name, directoryName) => false, loggerMock.Object, null, null, new ComponentRecorder());
this.detectorTestUtility = DetectorTestUtilityCreator.Create<IvyDetector>()
.WithScanRequest(this.scanRequest)
.WithDetector(detector);
}
[TestCleanup]
public void TestCleanup()
{
this.scanRequest.SourceDirectory.Delete(recursive: true);
this.DetectorTestUtility.AddServiceMock(this.commandLineMock);
}
[TestMethod]
@ -57,7 +30,7 @@ public class IvyDetectorTests
this.commandLineMock.Setup(x => x.CanCommandBeLocatedAsync(IvyDetector.PrimaryCommand, IvyDetector.AdditionalValidCommands, IvyDetector.AntVersionArgument))
.ReturnsAsync(false);
var (detectorResult, componentRecorder) = await this.detectorTestUtility.ExecuteDetectorAsync();
var (detectorResult, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync();
Assert.AreEqual(componentRecorder.GetDetectedComponents().Count(), 0);
Assert.AreEqual(detectorResult.ResultCode, ProcessingResultCode.Success);
@ -76,7 +49,7 @@ public class IvyDetectorTests
this.IvyHappyPath(content: registerUsageContent);
var (detectorResult, componentRecorder) = await this.detectorTestUtility.ExecuteDetectorAsync();
var (detectorResult, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync();
var detectedComponents = componentRecorder.GetDetectedComponents(); // IsDevelopmentDependency = true in componentRecorder but null in detectedComponents... why?
Assert.AreEqual(3, detectedComponents.Count());
@ -104,7 +77,7 @@ public class IvyDetectorTests
this.commandLineMock.Setup(x => x.CanCommandBeLocatedAsync(IvyDetector.PrimaryCommand, IvyDetector.AdditionalValidCommands, IvyDetector.AntVersionArgument))
.ReturnsAsync(true);
Func<Task> action = async () => await this.detectorTestUtility.ExecuteDetectorAsync();
Func<Task> action = async () => await this.DetectorTestUtility.ExecuteDetectorAsync();
await action.Should().NotThrowAsync();
}
@ -126,7 +99,7 @@ public class IvyDetectorTests
this.IvyHappyPath(content: registerUsageContent);
var (detectorResult, componentRecorder) = await this.detectorTestUtility.ExecuteDetectorAsync();
var (detectorResult, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync();
var detectedComponents = componentRecorder.GetDetectedComponents(); // IsDevelopmentDependency = true in componentRecorder but null in detectedComponents... why?
Assert.AreEqual(3, detectedComponents.Count());
@ -149,23 +122,15 @@ public class IvyDetectorTests
dependencyGraph.IsDevelopmentDependency(d3Id).Should().BeFalse();
}
protected bool ShouldBeEquivalentTo<T>(IEnumerable<T> result, IEnumerable<T> expected)
{
result.Should<T>().BeEquivalentTo(expected);
return true;
}
private void IvyHappyPath(string content)
{
this.commandLineMock.Setup(x => x.CanCommandBeLocatedAsync(IvyDetector.PrimaryCommand, IvyDetector.AdditionalValidCommands, IvyDetector.AntVersionArgument))
.ReturnsAsync(true);
var expectedIvyXmlLocation = this.scanRequest.SourceDirectory.FullName;
File.WriteAllText(Path.Combine(expectedIvyXmlLocation, "ivy.xml"), "(dummy content)");
File.WriteAllText(Path.Combine(expectedIvyXmlLocation, "ivysettings.xml"), "(dummy content)");
this.detectorTestUtility
.WithFile("ivy.xml", "(dummy content)", fileLocation: Path.Combine(expectedIvyXmlLocation, "ivy.xml"));
File.WriteAllText(Path.Combine(Path.GetTempPath(), "ivy.xml"), "(dummy content)");
File.WriteAllText(Path.Combine(Path.GetTempPath(), "ivysettings.xml"), "(dummy content)");
this.DetectorTestUtility
.WithFile("ivy.xml", "(dummy content)", fileLocation: Path.Combine(Path.GetTempPath(), "ivy.xml"));
this.commandLineMock.Setup(
x => x.ExecuteCommandAsync(

Просмотреть файл

@ -32,12 +32,11 @@ public class LinuxContainerDetectorTests
},
};
private Mock<IDockerService> mockDockerService;
private Mock<ILogger> mockLogger;
private Mock<ILinuxScanner> mockSyftLinuxScanner;
private readonly Mock<IDockerService> mockDockerService;
private readonly Mock<ILogger> mockLogger;
private readonly Mock<ILinuxScanner> mockSyftLinuxScanner;
[TestInitialize]
public void TestInitialize()
public LinuxContainerDetectorTests()
{
this.mockDockerService = new Mock<IDockerService>();
this.mockDockerService.Setup(service => service.CanRunLinuxContainersAsync(It.IsAny<CancellationToken>()))
@ -61,12 +60,10 @@ public class LinuxContainerDetectorTests
var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, new List<string> { NodeLatestImage }, componentRecorder);
var linuxContainerDetector = new LinuxContainerDetector
{
LinuxScanner = this.mockSyftLinuxScanner.Object,
Logger = this.mockLogger.Object,
DockerService = this.mockDockerService.Object,
};
var linuxContainerDetector = new LinuxContainerDetector(
this.mockSyftLinuxScanner.Object,
this.mockDockerService.Object,
this.mockLogger.Object);
var scanResult = await linuxContainerDetector.ExecuteDetectorAsync(scanRequest);
@ -91,12 +88,10 @@ public class LinuxContainerDetectorTests
this.mockDockerService.Setup(service => service.CanRunLinuxContainersAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(false);
var linuxContainerDetector = new LinuxContainerDetector
{
LinuxScanner = this.mockSyftLinuxScanner.Object,
Logger = this.mockLogger.Object,
DockerService = this.mockDockerService.Object,
};
var linuxContainerDetector = new LinuxContainerDetector(
this.mockSyftLinuxScanner.Object,
this.mockDockerService.Object,
this.mockLogger.Object);
var scanResult = await linuxContainerDetector.ExecuteDetectorAsync(scanRequest);
@ -115,12 +110,10 @@ public class LinuxContainerDetectorTests
var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, null, componentRecorder);
var linuxContainerDetector = new LinuxContainerDetector
{
LinuxScanner = this.mockSyftLinuxScanner.Object,
Logger = this.mockLogger.Object,
DockerService = this.mockDockerService.Object,
};
var linuxContainerDetector = new LinuxContainerDetector(
this.mockSyftLinuxScanner.Object,
this.mockDockerService.Object,
this.mockLogger.Object);
var scanResult = await linuxContainerDetector.ExecuteDetectorAsync(scanRequest);
@ -139,12 +132,10 @@ public class LinuxContainerDetectorTests
var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, new List<string> { "UPPERCASE" }, componentRecorder);
var linuxContainerDetector = new LinuxContainerDetector
{
LinuxScanner = this.mockSyftLinuxScanner.Object,
Logger = this.mockLogger.Object,
DockerService = this.mockDockerService.Object,
};
var linuxContainerDetector = new LinuxContainerDetector(
this.mockSyftLinuxScanner.Object,
this.mockDockerService.Object,
this.mockLogger.Object);
var scanResult = await linuxContainerDetector.ExecuteDetectorAsync(scanRequest);
@ -164,12 +155,10 @@ public class LinuxContainerDetectorTests
var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, new List<string> { NodeLatestImage, NodeLatestDigest }, componentRecorder);
var linuxContainerDetector = new LinuxContainerDetector
{
LinuxScanner = this.mockSyftLinuxScanner.Object,
Logger = this.mockLogger.Object,
DockerService = this.mockDockerService.Object,
};
var linuxContainerDetector = new LinuxContainerDetector(
this.mockSyftLinuxScanner.Object,
this.mockDockerService.Object,
this.mockLogger.Object);
var scanResult = await linuxContainerDetector.ExecuteDetectorAsync(scanRequest);
@ -189,12 +178,10 @@ public class LinuxContainerDetectorTests
var detectorArgs = new Dictionary<string, string> { { "Linux.ScanningTimeoutSec", "2" } };
var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, detectorArgs, new List<string> { NodeLatestImage }, new ComponentRecorder());
var linuxContainerDetector = new LinuxContainerDetector
{
LinuxScanner = this.mockSyftLinuxScanner.Object,
Logger = this.mockLogger.Object,
DockerService = this.mockDockerService.Object,
};
var linuxContainerDetector = new LinuxContainerDetector(
this.mockSyftLinuxScanner.Object,
this.mockDockerService.Object,
this.mockLogger.Object);
Func<Task> action = async () => await linuxContainerDetector.ExecuteDetectorAsync(scanRequest);
await action.Should().NotThrowAsync<OperationCanceledException>();

Просмотреть файл

@ -35,11 +35,11 @@ public class LinuxScannerTests
]
}";
private LinuxScanner linuxScanner;
private Mock<IDockerService> mockDockerService;
private readonly LinuxScanner linuxScanner;
private readonly Mock<IDockerService> mockDockerService;
private readonly Mock<ILogger> mockLogger;
[TestInitialize]
public void TestInitialize()
public LinuxScannerTests()
{
this.mockDockerService = new Mock<IDockerService>();
this.mockDockerService.Setup(service => service.CanPingDockerAsync(It.IsAny<CancellationToken>()))
@ -48,7 +48,9 @@ public class LinuxScannerTests
this.mockDockerService.Setup(service => service.CreateAndRunContainerAsync(It.IsAny<string>(), It.IsAny<List<string>>(), It.IsAny<CancellationToken>()))
.ReturnsAsync((SyftOutput, string.Empty));
this.linuxScanner = new LinuxScanner { DockerService = this.mockDockerService.Object };
this.mockLogger = new Mock<ILogger>();
this.linuxScanner = new LinuxScanner(this.mockDockerService.Object, this.mockLogger.Object);
}
[TestMethod]

Просмотреть файл

@ -17,24 +17,21 @@ using Moq;
[TestCategory("Governance/ComponentDetection")]
public class MavenCommandServiceTests
{
private Mock<ICommandLineInvocationService> commandLineMock;
private Mock<IMavenStyleDependencyGraphParserService> parserServiceMock;
private MavenCommandService mavenCommandService;
private readonly Mock<ICommandLineInvocationService> commandLineMock;
private readonly Mock<IMavenStyleDependencyGraphParserService> parserServiceMock;
private readonly MavenCommandService mavenCommandService;
[TestInitialize]
public void InitializeTests()
public MavenCommandServiceTests()
{
this.commandLineMock = new Mock<ICommandLineInvocationService>();
var loggerMock = new Mock<ILogger>();
this.parserServiceMock = new Mock<IMavenStyleDependencyGraphParserService>();
this.mavenCommandService = new MavenCommandService
{
CommandLineInvocationService = this.commandLineMock.Object,
ParserService = this.parserServiceMock.Object,
Logger = loggerMock.Object,
};
this.mavenCommandService = new MavenCommandService(
this.commandLineMock.Object,
this.parserServiceMock.Object,
loggerMock.Object);
}
[TestMethod]

Просмотреть файл

@ -1,73 +1,38 @@
namespace Microsoft.ComponentDetection.Detectors.Tests;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.ComponentDetection.Common.DependencyGraph;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Maven;
using Microsoft.ComponentDetection.Detectors.Tests.Utilities;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class MvnCliDetectorTests
public class MvnCliDetectorTests : BaseDetectorTest<MvnCliComponentDetector>
{
private IMavenCommandService mavenCommandService;
private Mock<ICommandLineInvocationService> commandLineMock;
private DetectorTestUtility<MvnCliComponentDetector> detectorTestUtility;
private ScanRequest scanRequest;
private readonly Mock<IMavenCommandService> mavenCommandServiceMock;
[TestInitialize]
public void InitializeTests()
public MvnCliDetectorTests()
{
this.commandLineMock = new Mock<ICommandLineInvocationService>();
this.mavenCommandService = new MavenCommandService
{
CommandLineInvocationService = this.commandLineMock.Object,
ParserService = new MavenStyleDependencyGraphParserService(),
};
var loggerMock = new Mock<ILogger>();
var detector = new MvnCliComponentDetector
{
MavenCommandService = this.mavenCommandService,
Logger = loggerMock.Object,
};
var tempPath = Path.GetTempPath();
var detectionPath = Path.Combine(tempPath, Guid.NewGuid().ToString());
Directory.CreateDirectory(detectionPath);
this.scanRequest = new ScanRequest(new DirectoryInfo(detectionPath), (name, directoryName) => false, loggerMock.Object, null, null, new ComponentRecorder());
this.detectorTestUtility = DetectorTestUtilityCreator.Create<MvnCliComponentDetector>()
.WithScanRequest(this.scanRequest)
.WithDetector(detector);
}
[TestCleanup]
public void TestCleanup()
{
this.scanRequest.SourceDirectory.Delete();
this.mavenCommandServiceMock = new Mock<IMavenCommandService>();
this.DetectorTestUtility.AddServiceMock(this.mavenCommandServiceMock);
}
[TestMethod]
public async Task IfMavenIsNotAvailableThenExitDetectorGracefullyAsync()
{
this.commandLineMock.Setup(x => x.CanCommandBeLocatedAsync(
MavenCommandService.PrimaryCommand,
MavenCommandService.AdditionalValidCommands,
MavenCommandService.MvnVersionArgument)).ReturnsAsync(false);
this.mavenCommandServiceMock.Setup(x => x.MavenCLIExistsAsync())
.ReturnsAsync(false);
var (detectorResult, componentRecorder) = await this.detectorTestUtility.ExecuteDetectorAsync();
var (detectorResult, componentRecorder) = await this.DetectorTestUtility
.ExecuteDetectorAsync();
Assert.AreEqual(componentRecorder.GetDetectedComponents().Count(), 0);
Assert.AreEqual(detectorResult.ResultCode, ProcessingResultCode.Success);
@ -79,8 +44,9 @@ public class MvnCliDetectorTests
const string componentString = "org.apache.maven:maven-compat:jar:3.6.1-SNAPSHOT";
this.MvnCliHappyPath(content: componentString);
var (detectorResult, componentRecorder) = await this.detectorTestUtility.ExecuteDetectorAsync();
this.mavenCommandServiceMock.Setup(x => x.ParseDependenciesFile(It.IsAny<ProcessRequest>()))
.Callback((ProcessRequest pr) => pr.SingleFileComponentRecorder.RegisterUsage(new DetectedComponent(new MavenComponent("org.apache.maven", "maven-compat", "3.6.1-SNAPSHOT"))));
var (detectorResult, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync();
var detectedComponents = componentRecorder.GetDetectedComponents();
Assert.AreEqual(detectedComponents.Count(), 1);
@ -97,12 +63,10 @@ public class MvnCliDetectorTests
[TestMethod]
public async Task MavenCli_FileObservableIsNotPresent_DetectionShouldNotFailAsync()
{
this.commandLineMock.Setup(x => x.CanCommandBeLocatedAsync(
MavenCommandService.PrimaryCommand,
MavenCommandService.AdditionalValidCommands,
MavenCommandService.MvnVersionArgument)).ReturnsAsync(true);
this.mavenCommandServiceMock.Setup(x => x.MavenCLIExistsAsync())
.ReturnsAsync(true);
Func<Task> action = async () => await this.detectorTestUtility.ExecuteDetectorAsync();
Func<Task> action = async () => await this.DetectorTestUtility.ExecuteDetectorAsync();
await action.Should().NotThrowAsync();
}
@ -116,9 +80,25 @@ public class MvnCliDetectorTests
var content = $@"com.bcde.test:top-level:jar:1.0.0{Environment.NewLine}\- {componentString}{Environment.NewLine} \- {childComponentString}";
this.MvnCliHappyPath(content);
this.mavenCommandServiceMock.Setup(x => x.ParseDependenciesFile(It.IsAny<ProcessRequest>()))
.Callback((ProcessRequest pr) =>
{
pr.SingleFileComponentRecorder.RegisterUsage(
new DetectedComponent(
new MavenComponent("com.bcde.test", "top-levelt", "1.0.0")),
isExplicitReferencedDependency: true);
pr.SingleFileComponentRecorder.RegisterUsage(
new DetectedComponent(
new MavenComponent("org.apache.maven", "maven-compat", "3.6.1-SNAPSHOT")),
isExplicitReferencedDependency: true);
pr.SingleFileComponentRecorder.RegisterUsage(
new DetectedComponent(
new MavenComponent("org.apache.maven", "maven-compat-child", "3.6.1-SNAPSHOT")),
isExplicitReferencedDependency: false,
parentComponentId: "org.apache.maven maven-compat 3.6.1-SNAPSHOT - Maven");
});
var (detectorResult, componentRecorder) = await this.detectorTestUtility
.ExecuteDetectorAsync();
var (detectorResult, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync();
var detectedComponents = componentRecorder.GetDetectedComponents();
Assert.AreEqual(detectedComponents.Count(), 3);
@ -154,8 +134,30 @@ public class MvnCliDetectorTests
const string leafComponentId = "org.apache.maven maven-compat-child 3.6.1-SNAPSHOT - Maven";
this.MvnCliHappyPath(content);
this.mavenCommandServiceMock.Setup(x => x.ParseDependenciesFile(It.IsAny<ProcessRequest>()))
.Callback((ProcessRequest pr) =>
{
pr.SingleFileComponentRecorder.RegisterUsage(
new DetectedComponent(
new MavenComponent("com.bcde.test", "top-levelt", "1.0.0")),
isExplicitReferencedDependency: true);
pr.SingleFileComponentRecorder.RegisterUsage(
new DetectedComponent(
new MavenComponent("org.apache.maven", "maven-compat", "3.6.1-SNAPSHOT")),
isExplicitReferencedDependency: true);
pr.SingleFileComponentRecorder.RegisterUsage(
new DetectedComponent(
new MavenComponent("org.apache.maven", "maven-compat-parent", "3.6.1-SNAPSHOT")),
isExplicitReferencedDependency: false,
parentComponentId: "org.apache.maven maven-compat 3.6.1-SNAPSHOT - Maven");
pr.SingleFileComponentRecorder.RegisterUsage(
new DetectedComponent(
new MavenComponent("org.apache.maven", "maven-compat-child", "3.6.1-SNAPSHOT")),
isExplicitReferencedDependency: false,
parentComponentId: "org.apache.maven maven-compat-parent 3.6.1-SNAPSHOT - Maven");
});
var (detectorResult, componentRecorder) = await this.detectorTestUtility.ExecuteDetectorAsync();
var (detectorResult, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync();
componentRecorder.GetDetectedComponents().Should().HaveCount(4);
detectorResult.ResultCode.Should().Be(ProcessingResultCode.Success);
@ -183,23 +185,13 @@ public class MvnCliDetectorTests
private void MvnCliHappyPath(string content)
{
this.commandLineMock.Setup(x => x.CanCommandBeLocatedAsync(MavenCommandService.PrimaryCommand, MavenCommandService.AdditionalValidCommands, MavenCommandService.MvnVersionArgument)).ReturnsAsync(true);
const string bcdeMvnFileName = "bcde.mvndeps";
var expectedPomLocation = this.scanRequest.SourceDirectory.FullName;
var bcdeMvnFileName = "bcde.mvndeps";
this.detectorTestUtility.WithFile("pom.xml", content, fileLocation: expectedPomLocation)
.WithFile("pom.xml", content, searchPatterns: new[] { bcdeMvnFileName }, fileLocation: Path.Combine(expectedPomLocation, "pom.xml"));
var cliParameters = new[] { "dependency:tree", "-B", $"-DoutputFile={bcdeMvnFileName}", "-DoutputType=text", $"-f{expectedPomLocation}" };
this.commandLineMock.Setup(x => x.ExecuteCommandAsync(
MavenCommandService.PrimaryCommand,
MavenCommandService.AdditionalValidCommands,
It.Is<string[]>(y => this.ShouldBeEquivalentTo(y, cliParameters))))
.ReturnsAsync(new CommandLineExecutionResult
{
ExitCode = 0,
});
this.mavenCommandServiceMock.Setup(x => x.BcdeMvnDependencyFileName)
.Returns(bcdeMvnFileName);
this.mavenCommandServiceMock.Setup(x => x.MavenCLIExistsAsync())
.ReturnsAsync(true);
this.DetectorTestUtility.WithFile("pom.xml", content)
.WithFile("pom.xml", content, searchPatterns: new[] { bcdeMvnFileName });
}
}

Просмотреть файл

@ -1,31 +1,19 @@
namespace Microsoft.ComponentDetection.Detectors.Tests;
namespace Microsoft.ComponentDetection.Detectors.Tests;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Npm;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using static Microsoft.ComponentDetection.Detectors.Tests.Utilities.TestUtilityExtensions;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class NpmDetectorTests
public class NpmDetectorTests : BaseDetectorTest<NpmComponentDetector>
{
private readonly DetectorTestUtility<NpmComponentDetector> detectorTestUtility = DetectorTestUtilityCreator.Create<NpmComponentDetector>();
private readonly List<string> packageJsonSearchPattern = new List<string> { "package.json" };
private Mock<IPathUtilityService> pathUtilityService;
[TestInitialize]
public void TestInitialize()
{
this.pathUtilityService = new Mock<IPathUtilityService>();
this.pathUtilityService.Setup(x => x.GetParentDirectory(It.IsAny<string>())).Returns((string path) => Path.GetDirectoryName(path));
}
[TestMethod]
public async Task TestNpmDetector_NameAndVersionDetectedAsync()
@ -34,10 +22,8 @@ public class NpmDetectorTests
var version = NewRandomVersion();
var (packageJsonName, packageJsonContents, packageJsonPath) =
NpmTestUtilities.GetPackageJsonNoDependenciesForNameAndVersion(componentName, version);
var detector = new NpmComponentDetector();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
@ -54,10 +40,8 @@ public class NpmDetectorTests
var authorName = GetRandomString();
var authorEmail = GetRandomString();
var (packageJsonName, packageJsonContents, packageJsonPath) = NpmTestUtilities.GetPackageJsonNoDependenciesForAuthorAndEmailInJsonFormat(authorName, authorEmail);
var detector = new NpmComponentDetector();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
@ -74,10 +58,8 @@ public class NpmDetectorTests
var authorName = GetRandomString();
var (packageJsonName, packageJsonContents, packageJsonPath) =
NpmTestUtilities.GetPackageJsonNoDependenciesForAuthorAndEmailInJsonFormat(authorName, null);
var detector = new NpmComponentDetector();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
@ -96,10 +78,8 @@ public class NpmDetectorTests
var authroUrl = GetRandomString();
var (packageJsonName, packageJsonContents, packageJsonPath) =
NpmTestUtilities.GetPackageJsonNoDependenciesForAuthorAndEmailAsSingleString(authorName, authorEmail, authroUrl);
var detector = new NpmComponentDetector();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
@ -117,10 +97,8 @@ public class NpmDetectorTests
var authroUrl = GetRandomString();
var (packageJsonName, packageJsonContents, packageJsonPath) =
NpmTestUtilities.GetPackageJsonNoDependenciesForAuthorAndEmailAsSingleString(authorName, null, authroUrl);
var detector = new NpmComponentDetector();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
@ -139,10 +117,8 @@ public class NpmDetectorTests
var authorEmail = GetRandomString();
var (packageJsonName, packageJsonContents, packageJsonPath) =
NpmTestUtilities.GetPackageJsonNoDependenciesMalformedAuthorAsSingleString(authorName, authorEmail, authroUrl);
var detector = new NpmComponentDetector();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
@ -159,10 +135,8 @@ public class NpmDetectorTests
var authroUrl = GetRandomString();
var (packageJsonName, packageJsonContents, packageJsonPath) =
NpmTestUtilities.GetPackageJsonNoDependenciesForAuthorAndEmailAsSingleString(authorName);
var detector = new NpmComponentDetector();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
@ -180,10 +154,8 @@ public class NpmDetectorTests
var authorEmail = GetRandomString();
var (packageJsonName, packageJsonContents, packageJsonPath) =
NpmTestUtilities.GetPackageJsonNoDependenciesForAuthorAndEmailAsSingleString(authorName, authorEmail);
var detector = new NpmComponentDetector();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
@ -202,10 +174,8 @@ public class NpmDetectorTests
var authorEmail = GetRandomString();
var (packageJsonName, packageJsonContents, packageJsonPath) =
NpmTestUtilities.GetPackageJsonNoDependenciesForAuthorAndEmailInJsonFormat(authorName, authorEmail);
var detector = new NpmComponentDetector();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
@ -223,10 +193,8 @@ public class NpmDetectorTests
var authorEmail = GetRandomString();
var (packageJsonName, packageJsonContents, packageJsonPath) =
NpmTestUtilities.GetPackageJsonNoDependenciesForAuthorAndEmailAsSingleString(authorName, authorEmail);
var detector = new NpmComponentDetector();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();

Просмотреть файл

@ -9,7 +9,6 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Npm;
using Microsoft.ComponentDetection.Detectors.Tests.Utilities;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using static Microsoft.ComponentDetection.Detectors.Tests.Utilities.TestUtilityExtensions;
@ -17,19 +16,18 @@ using static Microsoft.ComponentDetection.Detectors.Tests.Utilities.TestUtilityE
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class NpmDetectorWithRootsTests
public class NpmDetectorWithRootsTests : BaseDetectorTest<NpmComponentDetectorWithRoots>
{
private readonly DetectorTestUtility<NpmComponentDetectorWithRoots> detectorTestUtility = DetectorTestUtilityCreator.Create<NpmComponentDetectorWithRoots>();
private readonly string packageLockJsonFileName = "package-lock.json";
private readonly string packageJsonFileName = "package.json";
private readonly List<string> packageJsonSearchPattern = new List<string> { "package.json" };
private Mock<IPathUtilityService> pathUtilityService;
private readonly List<string> packageJsonSearchPattern = new() { "package.json" };
private readonly List<string> packageLockJsonSearchPatterns = new() { "package-lock.json", "npm-shrinkwrap.json", "lerna.json" };
private readonly Mock<IPathUtilityService> mockPathUtilityService;
[TestInitialize]
public void TestInitialize()
public NpmDetectorWithRootsTests()
{
this.pathUtilityService = new Mock<IPathUtilityService>();
this.pathUtilityService.Setup(x => x.GetParentDirectory(It.IsAny<string>())).Returns((string path) => Path.GetDirectoryName(path));
this.mockPathUtilityService = new Mock<IPathUtilityService>();
this.DetectorTestUtility.AddServiceMock(this.mockPathUtilityService);
}
[TestMethod]
@ -41,14 +39,8 @@ public class NpmDetectorWithRootsTests
var (packageLockName, packageLockContents, packageLockPath) = NpmTestUtilities.GetWellFormedPackageLock2(this.packageLockJsonFileName, componentName0, version0);
var (packageJsonName, packageJsonContents, packageJsonPath) = NpmTestUtilities.GetPackageJsonOneRoot(componentName0, version0);
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile(packageLockName, packageLockContents, detector.SearchPatterns, fileLocation: packageLockPath)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageLockName, packageLockContents, this.packageLockJsonSearchPatterns, fileLocation: packageLockPath)
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
@ -73,14 +65,8 @@ public class NpmDetectorWithRootsTests
var (packageLockName, packageLockContents, packageLockPath) = NpmTestUtilities.GetWellFormedPackageLock2(this.packageLockJsonFileName);
var (packageJsonName, packageJsonContents, packageJsonPath) = NpmTestUtilities.GetPackageJsonOneRoot(componentName0, version0);
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile(packageLockName, packageLockContents, detector.SearchPatterns, fileLocation: packageLockPath)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageLockName, packageLockContents, this.packageLockJsonSearchPatterns, fileLocation: packageLockPath)
.WithFile(packageJsonName, packageJsonContents, this.packageJsonSearchPattern, fileLocation: packageJsonPath)
.ExecuteDetectorAsync();
@ -93,14 +79,8 @@ public class NpmDetectorWithRootsTests
{
var (packageLockName, packageLockContents, packageLockPath) = NpmTestUtilities.GetWellFormedPackageLock2(this.packageLockJsonFileName);
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile(packageLockName, packageLockContents, detector.SearchPatterns, fileLocation: packageLockPath)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageLockName, packageLockContents, this.packageLockJsonSearchPatterns, fileLocation: packageLockPath)
.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
@ -130,14 +110,8 @@ public class NpmDetectorWithRootsTests
var packageJsonTemplate = string.Format(packagejson, componentName0, version0, componentName2, version2);
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile(packageLockName, packageLockContents, detector.SearchPatterns)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageLockName, packageLockContents, this.packageLockJsonSearchPatterns)
.WithFile(this.packageJsonFileName, packageJsonTemplate, this.packageJsonSearchPattern)
.ExecuteDetectorAsync();
@ -192,14 +166,8 @@ public class NpmDetectorWithRootsTests
var packageJsonTemplate = string.Format(packagejson, componentName0, version0, componentName2, version2);
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile(packageLockName, packageLockContents, detector.SearchPatterns, fileLocation: packageLockPath)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageLockName, packageLockContents, this.packageLockJsonSearchPatterns, fileLocation: packageLockPath)
.WithFile(this.packageJsonFileName, packageJsonTemplate, this.packageJsonSearchPattern)
.ExecuteDetectorAsync();
@ -262,14 +230,8 @@ public class NpmDetectorWithRootsTests
var packageJsonTemplate = string.Format(packagejson, componentName0, version0, componentName2, version2);
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile(this.packageLockJsonFileName, packageLockTemplate, detector.SearchPatterns)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.packageLockJsonFileName, packageLockTemplate, this.packageLockJsonSearchPatterns)
.WithFile(this.packageJsonFileName, packageJsonTemplate, this.packageJsonSearchPattern)
.ExecuteDetectorAsync();
@ -321,14 +283,8 @@ public class NpmDetectorWithRootsTests
var packageJsonTemplate = string.Format(packagejson, componentName0, version0, componentName2, version2);
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile(this.packageLockJsonFileName, packageLockTemplate, detector.SearchPatterns)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.packageLockJsonFileName, packageLockTemplate, this.packageLockJsonSearchPatterns)
.WithFile(this.packageJsonFileName, packageJsonTemplate, this.packageJsonSearchPattern)
.ExecuteDetectorAsync();
@ -387,14 +343,11 @@ public class NpmDetectorWithRootsTests
var packageJsonTemplate = string.Format(packagejson, componentName0, version0, componentName1, version1, componentName2, version2);
var detector = new NpmComponentDetectorWithRoots();
this.pathUtilityService.Setup(x => x.IsFileBelowAnother(It.IsAny<string>(), It.IsAny<string>())).Returns(true);
detector.PathUtilityService = this.pathUtilityService.Object;
this.mockPathUtilityService.Setup(x => x.IsFileBelowAnother(It.IsAny<string>(), It.IsAny<string>())).Returns(true);
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile("lerna.json", "unused string", detector.SearchPatterns, fileLocation: lernaFileLocation)
.WithFile(this.packageLockJsonFileName, packageLockTemplate, detector.SearchPatterns, fileLocation: lockFileLocation)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("lerna.json", "unused string", this.packageLockJsonSearchPatterns, fileLocation: lernaFileLocation)
.WithFile(this.packageLockJsonFileName, packageLockTemplate, this.packageLockJsonSearchPatterns, fileLocation: lockFileLocation)
.WithFile(this.packageJsonFileName, packageJsonTemplate, this.packageJsonSearchPattern, fileLocation: packageJsonFileLocation)
.ExecuteDetectorAsync();
@ -448,14 +401,8 @@ public class NpmDetectorWithRootsTests
var packageJsonTemplate = string.Format(packagejson, componentName0, version0, componentName2, version2);
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile(this.packageLockJsonFileName, packageLockTemplate, detector.SearchPatterns)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.packageLockJsonFileName, packageLockTemplate, this.packageLockJsonSearchPatterns)
.WithFile(this.packageJsonFileName, packageJsonTemplate, this.packageJsonSearchPattern)
.ExecuteDetectorAsync();
@ -485,14 +432,8 @@ public class NpmDetectorWithRootsTests
var (packageLockName, packageLockContents, packageLockPath) = NpmTestUtilities.GetWellFormedPackageLock2(lockFileName, componentName0, version0);
var (packageJsonName, packageJsonContents, packageJsonPath) = NpmTestUtilities.GetPackageJsonOneRoot(componentName0, version0);
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile(packageLockName, packageLockContents, detector.SearchPatterns, fileLocation: packageLockPath)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(packageLockName, packageLockContents, this.packageLockJsonSearchPatterns, fileLocation: packageLockPath)
.WithFile(this.packageJsonFileName, packageJsonContents, this.packageJsonSearchPattern)
.ExecuteDetectorAsync();
@ -536,18 +477,12 @@ public class NpmDetectorWithRootsTests
var packageJsonTemplate2 = string.Format(packagejson, componentName2, version2, "test2");
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
/* Top level */
.WithFile(packageLockName, packageLockContents, detector.SearchPatterns, fileLocation: packageLockPath)
.WithFile(packageLockName, packageLockContents, this.packageLockJsonSearchPatterns, fileLocation: packageLockPath)
.WithFile(this.packageJsonFileName, packageJsonTemplate, this.packageJsonSearchPattern)
/* Under node_modules */
.WithFile(packageLockName2, packageLockContents2, detector.SearchPatterns, fileLocation: packageLockUnderNodeModules)
.WithFile(packageLockName2, packageLockContents2, this.packageLockJsonSearchPatterns, fileLocation: packageLockUnderNodeModules)
.WithFile(this.packageJsonFileName, packageJsonTemplate2, this.packageJsonSearchPattern, fileLocation: packageJsonUnderNodeModules)
.ExecuteDetectorAsync();
@ -621,14 +556,8 @@ public class NpmDetectorWithRootsTests
var packageJsonTemplate = string.Format(packagejson, componentA.Name, componentA.Version, componentB.Name, componentB.Version);
var detector = new NpmComponentDetectorWithRoots
{
PathUtilityService = this.pathUtilityService.Object,
};
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithDetector(detector)
.WithFile(this.packageLockJsonFileName, packageLockTemplate, detector.SearchPatterns)
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.packageLockJsonFileName, packageLockTemplate, this.packageLockJsonSearchPatterns)
.WithFile(this.packageJsonFileName, packageJsonTemplate, this.packageJsonSearchPattern)
.ExecuteDetectorAsync();

Просмотреть файл

@ -12,29 +12,21 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.Internal;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.NuGet;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class NuGetComponentDetectorTests
public class NuGetComponentDetectorTests : BaseDetectorTest<NuGetComponentDetector>
{
private Mock<ILogger> loggerMock;
private DetectorTestUtility<NuGetComponentDetector> detectorTestUtility;
[TestInitialize]
public void TestInitialize()
{
this.loggerMock = new Mock<ILogger>();
this.detectorTestUtility = DetectorTestUtilityCreator.Create<NuGetComponentDetector>();
}
private static readonly IEnumerable<string> DetectorSearchPattern =
new List<string> { "*.nupkg", "*.nuspec", "nuget.config", "paket.lock" };
[TestMethod]
public async Task TestNuGetDetectorWithNoFiles_ReturnsSuccessfullyAsync()
{
var (scanResult, componentRecorder) = await this.detectorTestUtility.ExecuteDetectorAsync();
var (scanResult, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
Assert.AreEqual(0, componentRecorder.GetDetectedComponents().Count());
@ -48,7 +40,7 @@ public class NuGetComponentDetectorTests
var testAuthors = new string[] { "author 1", "author 2" };
var nuspec = NugetTestUtilities.GetValidNuspec(testComponentName, testVersion, testAuthors);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("*.nuspec", nuspec)
.ExecuteDetectorAsync();
@ -70,7 +62,7 @@ public class NuGetComponentDetectorTests
var testAuthors = new string[] { "author 1" };
var nuspec = NugetTestUtilities.GetValidNuspec(testComponentName, testVersion, testAuthors);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("*.nuspec", nuspec)
.ExecuteDetectorAsync();
@ -89,7 +81,7 @@ public class NuGetComponentDetectorTests
{
var nupkg = await NugetTestUtilities.ZipNupkgComponentAsync("test.nupkg", NugetTestUtilities.GetRandomValidNuspec());
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("test.nupkg", nupkg)
.ExecuteDetectorAsync();
@ -103,7 +95,7 @@ public class NuGetComponentDetectorTests
var nuspec = NugetTestUtilities.GetRandomValidNuSpecComponent();
var nupkg = await NugetTestUtilities.ZipNupkgComponentAsync("test.nupkg", NugetTestUtilities.GetRandomValidNuspec());
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("test.nuspec", nuspec)
.WithFile("test.nupkg", nupkg)
.ExecuteDetectorAsync();
@ -147,7 +139,7 @@ NUGET
log4net (1.2.10)
";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("paket.lock", paketLock)
.ExecuteDetectorAsync();
@ -164,14 +156,16 @@ NUGET
var malformedNupkg = await NugetTestUtilities.ZipNupkgComponentAsync("malformed.nupkg", NugetTestUtilities.GetRandomMalformedNuPkgComponent());
var nuspec = NugetTestUtilities.GetRandomValidNuSpecComponent();
var (scanResult, componentRecorder) = await this.detectorTestUtility
.WithLogger(this.loggerMock)
var mockLogger = new Mock<ILogger>();
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("test.nuspec", nuspec)
.WithFile("test.nupkg", validNupkg)
.WithFile("malformed.nupkg", malformedNupkg)
.AddServiceMock(mockLogger)
.ExecuteDetectorAsync();
this.loggerMock.Verify(x => x.LogFailedReadingFile(Path.Join(Path.GetTempPath(), "malformed.nupkg"), It.IsAny<Exception>()));
mockLogger.Verify(x => x.LogFailedReadingFile(Path.Join(Path.GetTempPath(), "malformed.nupkg"), It.IsAny<Exception>()));
Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode);
Assert.AreEqual(2, componentRecorder.GetDetectedComponents().Count());
@ -188,11 +182,9 @@ NUGET
var streamsDetectedInAdditionalDirectoryPass = new List<IComponentStream> { nugetConfigComponent };
var componentRecorder = new ComponentRecorder();
var detector = new NuGetComponentDetector();
var mockLogger = new Mock<ILogger>();
var sourceDirectoryPath = this.CreateTemporaryDirectory();
detector.Logger = this.loggerMock.Object;
// Use strict mock evaluation because we're doing some "fun" stuff with this mock.
var componentStreamEnumerableFactoryMock = new Mock<IComponentStreamEnumerableFactory>(MockBehavior.Strict);
var directoryWalkerMock = new Mock<IObservableDirectoryWalkerFactory>(MockBehavior.Strict);
@ -213,7 +205,7 @@ NUGET
componentStreamEnumerableFactoryMock.Setup(
x => x.GetComponentStreams(
Match.Create<DirectoryInfo>(info => info.FullName.Contains(sourceDirectoryPath)),
Match.Create<IEnumerable<string>>(stuff => detector.SearchPatterns.Intersect(stuff).Count() == detector.SearchPatterns.Count),
Match.Create<IEnumerable<string>>(stuff => DetectorSearchPattern.Intersect(stuff).Count() == DetectorSearchPattern.Count()),
It.IsAny<ExcludeDirectoryPredicate>(),
It.IsAny<bool>()))
.Returns(Enumerable.Empty<IComponentStream>());
@ -222,7 +214,7 @@ NUGET
componentStreamEnumerableFactoryMock.Setup(
x => x.GetComponentStreams(
Match.Create<DirectoryInfo>(info => info.FullName.Contains(additionalDirectory)),
Match.Create<IEnumerable<string>>(stuff => detector.SearchPatterns.Intersect(stuff).Count() == detector.SearchPatterns.Count),
Match.Create<IEnumerable<string>>(stuff => DetectorSearchPattern.Intersect(stuff).Count() == DetectorSearchPattern.Count()),
It.IsAny<ExcludeDirectoryPredicate>(),
It.IsAny<bool>()))
.Returns(streamsDetectedInNormalPass);
@ -243,8 +235,10 @@ NUGET
It.IsAny<ComponentRecorder>()))
.Returns(() => streamsDetectedInNormalPass.Select(cs => new ProcessRequest { ComponentStream = cs, SingleFileComponentRecorder = componentRecorder.CreateSingleFileComponentRecorder(cs.Location) }).ToObservable());
detector.ComponentStreamEnumerableFactory = componentStreamEnumerableFactoryMock.Object;
detector.Scanner = directoryWalkerMock.Object;
var detector = new NuGetComponentDetector(
componentStreamEnumerableFactoryMock.Object,
directoryWalkerMock.Object,
mockLogger.Object);
var scanResult = await detector.ExecuteDetectorAsync(new ScanRequest(new DirectoryInfo(sourceDirectoryPath), (name, directoryName) => false, null, new Dictionary<string, string>(), null, componentRecorder));
@ -258,7 +252,7 @@ NUGET
{
var nupkg = await NugetTestUtilities.ZipNupkgComponentAsync("Newtonsoft.Json.nupkg", NugetTestUtilities.GetValidNuspec("Newtonsoft.Json", "9.0.1", new[] { "JamesNK" }));
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Newtonsoft.Json.nupkg", nupkg)
.ExecuteDetectorAsync();

Просмотреть файл

@ -10,7 +10,6 @@ using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.NuGet;
using Microsoft.ComponentDetection.Detectors.Tests.Mocks;
using Microsoft.ComponentDetection.Detectors.Tests.Utilities;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Newtonsoft.Json;
@ -18,39 +17,24 @@ using Newtonsoft.Json;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class NuGetProjectModelProjectCentricComponentDetectorTests
public class NuGetProjectModelProjectCentricComponentDetectorTests : BaseDetectorTest<NuGetProjectModelProjectCentricComponentDetector>
{
private readonly string projectAssetsJsonFileName = "project.assets.json";
private DetectorTestUtility<NuGetProjectModelProjectCentricComponentDetector> detectorTestUtility;
private readonly Mock<IFileUtilityService> fileUtilityServiceMock;
[TestInitialize]
public void TestInitialize()
public NuGetProjectModelProjectCentricComponentDetectorTests()
{
var detector = new NuGetProjectModelProjectCentricComponentDetector();
var loggerMock = new Mock<ILogger>();
loggerMock.Setup(x => x.LogWarning(It.IsAny<string>())).Callback<string>(message => Console.WriteLine(message));
loggerMock.Setup(x => x.LogFailedReadingFile(It.IsAny<string>(), It.IsAny<Exception>())).Callback<string, Exception>((message, exception) =>
{
Console.WriteLine(message);
Console.WriteLine(exception.ToString());
});
detector.Logger = loggerMock.Object;
var fileUtilityServiceMock = new Mock<IFileUtilityService>();
fileUtilityServiceMock.Setup(x => x.Exists(It.IsAny<string>()))
this.fileUtilityServiceMock = new Mock<IFileUtilityService>();
this.fileUtilityServiceMock.Setup(x => x.Exists(It.IsAny<string>()))
.Returns(true);
detector.FileUtilityService = fileUtilityServiceMock.Object;
this.detectorTestUtility = DetectorTestUtilityCreator.Create<NuGetProjectModelProjectCentricComponentDetector>()
.WithDetector(detector);
this.DetectorTestUtility.AddServiceMock(this.fileUtilityServiceMock);
}
[TestMethod]
public async Task ScanDirectoryAsync_Base_2_2_VerificationAsync()
{
var osAgnostic = this.Convert22SampleToOSAgnostic(TestResources.project_assets_2_2);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.projectAssetsJsonFileName, osAgnostic)
.ExecuteDetectorAsync();
@ -73,7 +57,7 @@ public class NuGetProjectModelProjectCentricComponentDetectorTests
public async Task ScanDirectoryAsync_Base_2_2_additional_VerificationAsync()
{
var osAgnostic = this.Convert22SampleToOSAgnostic(TestResources.project_assets_2_2_additional);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.projectAssetsJsonFileName, osAgnostic)
.ExecuteDetectorAsync();
@ -99,7 +83,7 @@ public class NuGetProjectModelProjectCentricComponentDetectorTests
public async Task ScanDirectoryAsync_ExcludedFrameworkComponent_2_2_VerificationAsync()
{
var osAgnostic = this.Convert22SampleToOSAgnostic(TestResources.project_assets_2_2);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.projectAssetsJsonFileName, osAgnostic)
.ExecuteDetectorAsync();
@ -114,7 +98,7 @@ public class NuGetProjectModelProjectCentricComponentDetectorTests
public async Task ScanDirectoryAsync_DependencyGraph_2_2_additional_VerificationAsync()
{
var osAgnostic = this.Convert22SampleToOSAgnostic(TestResources.project_assets_2_2_additional);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.projectAssetsJsonFileName, osAgnostic)
.ExecuteDetectorAsync();
var graphsByLocation = componentRecorder.GetDependencyGraphsByLocation();
@ -194,7 +178,7 @@ public class NuGetProjectModelProjectCentricComponentDetectorTests
public async Task ScanDirectoryAsync_Base_3_1_VerificationAsync()
{
var osAgnostic = this.Convert31SampleToOSAgnostic(TestResources.project_assets_3_1);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.projectAssetsJsonFileName, osAgnostic)
.ExecuteDetectorAsync();
@ -216,7 +200,7 @@ public class NuGetProjectModelProjectCentricComponentDetectorTests
public async Task ScanDirectoryAsync_ExcludedFrameworkComponent_3_1_VerificationAsync()
{
var osAgnostic = this.Convert31SampleToOSAgnostic(TestResources.project_assets_3_1);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.projectAssetsJsonFileName, osAgnostic)
.ExecuteDetectorAsync();
@ -232,7 +216,7 @@ public class NuGetProjectModelProjectCentricComponentDetectorTests
public async Task ScanDirectoryAsync_DependencyGraph_3_1_VerificationAsync()
{
var osAgnostic = this.Convert31SampleToOSAgnostic(TestResources.project_assets_3_1);
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.projectAssetsJsonFileName, osAgnostic)
.ExecuteDetectorAsync();
@ -285,7 +269,7 @@ public class NuGetProjectModelProjectCentricComponentDetectorTests
},
""packageFolders"": {}
}";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.projectAssetsJsonFileName, osAgnostic)
.ExecuteDetectorAsync();

Просмотреть файл

@ -9,58 +9,46 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Pip;
using Microsoft.ComponentDetection.Detectors.Tests.Utilities;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Newtonsoft.Json;
[TestClass]
public class PipComponentDetectorTests
public class PipComponentDetectorTests : BaseDetectorTest<PipComponentDetector>
{
private Mock<IPythonCommandService> pythonCommandService;
private Mock<IPythonResolver> pythonResolver;
private Mock<ILogger> loggerMock;
private readonly Mock<IPythonCommandService> pythonCommandService;
private readonly Mock<IPythonResolver> pythonResolver;
private DetectorTestUtility<PipComponentDetector> detectorTestUtility;
[TestInitialize]
public void TestInitialize()
public PipComponentDetectorTests()
{
this.pythonCommandService = new Mock<IPythonCommandService>();
this.DetectorTestUtility.AddServiceMock(this.pythonCommandService);
this.pythonResolver = new Mock<IPythonResolver>();
this.loggerMock = new Mock<ILogger>();
var detector = new PipComponentDetector
{
PythonCommandService = this.pythonCommandService.Object,
PythonResolver = this.pythonResolver.Object,
Logger = this.loggerMock.Object,
};
this.detectorTestUtility = DetectorTestUtilityCreator.Create<PipComponentDetector>()
.WithDetector(detector);
this.DetectorTestUtility.AddServiceMock(this.pythonResolver);
}
[TestMethod]
public async Task TestPipDetector_PythonNotInstalledAsync()
{
var mockLogger = new Mock<ILogger>();
mockLogger.Setup(x => x.LogInfo(It.Is<string>(l => l.Contains("No python found"))));
this.DetectorTestUtility.AddServiceMock(mockLogger);
this.pythonCommandService.Setup(x => x.PythonExistsAsync(It.IsAny<string>())).ReturnsAsync(false);
this.loggerMock.Setup(x => x.LogInfo(It.Is<string>(l => l.Contains("No python found"))));
var (result, componentRecorder) = await this.detectorTestUtility
var (result, componentRecorder) = await this.DetectorTestUtility
.WithFile("setup.py", string.Empty)
.WithLogger(this.loggerMock)
.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, result.ResultCode);
this.loggerMock.VerifyAll();
mockLogger.VerifyAll();
}
[TestMethod]
public async Task TestPipDetector_PythonInstalledNoFilesAsync()
{
var (result, componentRecorder) = await this.detectorTestUtility.ExecuteDetectorAsync();
var (result, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync();
Assert.AreEqual(ProcessingResultCode.Success, result.ResultCode);
}
@ -96,7 +84,7 @@ public class PipComponentDetectorTests
this.pythonResolver.Setup(x => x.ResolveRootsAsync(It.Is<IList<PipDependencySpecification>>(p => p.Any(d => d.Name == "b")))).ReturnsAsync(setupPyRoots);
this.pythonResolver.Setup(x => x.ResolveRootsAsync(It.Is<IList<PipDependencySpecification>>(p => p.Any(d => d.Name == "d")))).ReturnsAsync(requirementsTxtRoots);
var (result, componentRecorder) = await this.detectorTestUtility
var (result, componentRecorder) = await this.DetectorTestUtility
.WithFile("setup.py", string.Empty)
.WithFile("requirements.txt", string.Empty)
.ExecuteDetectorAsync();
@ -152,7 +140,7 @@ public class PipComponentDetectorTests
this.pythonResolver.Setup(x => x.ResolveRootsAsync(It.Is<IList<PipDependencySpecification>>(p => p.Any(d => d.Name == "h")))).ReturnsAsync(requirementsTxtRoots);
this.pythonResolver.Setup(x => x.ResolveRootsAsync(It.Is<IList<PipDependencySpecification>>(p => p.Any(d => d.Name == "g")))).ReturnsAsync(requirementsTxtRoots2);
var (result, componentRecorder) = await this.detectorTestUtility
var (result, componentRecorder) = await this.DetectorTestUtility
.WithFile("requirements.txt", string.Empty)
.WithFile("requirements.txt", string.Empty, fileLocation: Path.Join(Path.GetTempPath(), "TEST", "requirements.txt"))
.ExecuteDetectorAsync();
@ -205,7 +193,7 @@ public class PipComponentDetectorTests
x.ResolveRootsAsync(It.Is<IList<PipDependencySpecification>>(p => p.Any(d => d.Name == "c"))))
.ReturnsAsync(new List<PipGraphNode> { rootC, rootD, rootE, });
var (result, componentRecorder) = await this.detectorTestUtility
var (result, componentRecorder) = await this.DetectorTestUtility
.WithFile("setup.py", string.Empty, fileLocation: file1)
.WithFile("setup.py", string.Empty, fileLocation: file2)
.ExecuteDetectorAsync();

Просмотреть файл

@ -47,7 +47,7 @@ public class PipResolverTests
var dependencies = new List<PipDependencySpecification> { a };
var resolver = new PythonResolver() { PypiClient = this.pyPiClient.Object, Logger = this.loggerMock.Object, };
var resolver = new PythonResolver(this.pyPiClient.Object, this.loggerMock.Object);
var resolveResult = await resolver.ResolveRootsAsync(dependencies);
@ -90,7 +90,7 @@ public class PipResolverTests
var dependencies = new List<PipDependencySpecification> { a, doesNotExist };
var resolver = new PythonResolver() { PypiClient = this.pyPiClient.Object, Logger = this.loggerMock.Object, };
var resolver = new PythonResolver(this.pyPiClient.Object, this.loggerMock.Object);
var resolveResult = await resolver.ResolveRootsAsync(dependencies);
@ -130,7 +130,7 @@ public class PipResolverTests
var dependencies = new List<PipDependencySpecification> { a };
var resolver = new PythonResolver() { PypiClient = this.pyPiClient.Object, Logger = this.loggerMock.Object, };
var resolver = new PythonResolver(this.pyPiClient.Object, this.loggerMock.Object);
var resolveResult = await resolver.ResolveRootsAsync(dependencies);
@ -173,7 +173,7 @@ public class PipResolverTests
var dependencies = new List<PipDependencySpecification> { a };
var resolver = new PythonResolver() { PypiClient = this.pyPiClient.Object, Logger = this.loggerMock.Object, };
var resolver = new PythonResolver(this.pyPiClient.Object, this.loggerMock.Object);
var resolveResult = await resolver.ResolveRootsAsync(dependencies);

Просмотреть файл

@ -9,22 +9,24 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Pnpm;
using Microsoft.ComponentDetection.Detectors.Tests.Utilities;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class PnpmDetectorTests
public class PnpmDetectorTests : BaseDetectorTest<PnpmComponentDetector>
{
private DetectorTestUtility<PnpmComponentDetector> detectorTestUtility;
[TestInitialize]
public void TestInitialize()
public PnpmDetectorTests()
{
var componentRecorder = new ComponentRecorder(enableManualTrackingOfExplicitReferences: false);
this.detectorTestUtility = DetectorTestUtilityCreator.Create<PnpmComponentDetector>()
.WithScanRequest(new ScanRequest(new DirectoryInfo(Path.GetTempPath()), null, null, new Dictionary<string, string>(), null, componentRecorder));
this.DetectorTestUtility.WithScanRequest(
new ScanRequest(
new DirectoryInfo(Path.GetTempPath()),
null,
null,
new Dictionary<string, string>(),
null,
componentRecorder));
}
[TestMethod]
@ -69,7 +71,7 @@ registry: 'https://test/registry'
shrinkwrapMinorVersion: 7
shrinkwrapVersion: 3";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("shrinkwrap1.yaml", yamlFile)
.ExecuteDetectorAsync();
@ -170,7 +172,7 @@ registry: 'https://test/registry'
shrinkwrapMinorVersion: 7
shrinkwrapVersion: 3";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("shrinkwrap1.yaml", yamlFile1)
.WithFile("shrinkwrap2.yaml", yamlFile2)
.ExecuteDetectorAsync();
@ -216,7 +218,7 @@ registry: 'https://test/registry'
shrinkwrapMinorVersion: 7
shrinkwrapVersion: 3";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("shrinkwrap1.yaml", yamlFile1)
.ExecuteDetectorAsync();
@ -245,7 +247,7 @@ shrinkwrapVersion: 3";
/strict-uri-encode/1.1.0:
dev: true";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("shrinkwrap1.yaml", yamlFile1)
.ExecuteDetectorAsync();
@ -276,7 +278,7 @@ shrinkwrapVersion: 3";
shared-non-dev-dep: 0.1.2
dev: true";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("shrinkwrap1.yaml", yamlFile1)
.ExecuteDetectorAsync();
@ -291,7 +293,7 @@ shrinkwrapVersion: 3";
// This is a clearly malformed Yaml. We expect parsing it to "succeed" but find no components
var yamlFile1 = @"dependencies";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("shrinkwrap1.yaml", yamlFile1)
.ExecuteDetectorAsync();
@ -321,7 +323,7 @@ packages:
/test/1.0.0:
dev: true";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("shrinkwrap1.yaml", yamlFile)
.ExecuteDetectorAsync();
@ -369,7 +371,7 @@ packages:
/nth-check/2.0.0:
resolution: {integrity: sha1-G7T22scAcvwxPoyc0UF7UHTAoSU=} ";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("shrinkwrap1.yaml", yamlFile)
.ExecuteDetectorAsync();

Просмотреть файл

@ -8,22 +8,13 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.CocoaPods;
using Microsoft.ComponentDetection.Detectors.Tests.Utilities;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class PodDetectorTest
public class PodDetectorTest : BaseDetectorTest<PodComponentDetector>
{
private DetectorTestUtility<PodComponentDetector> detectorTestUtility;
[TestInitialize]
public void TestInitialize()
{
this.detectorTestUtility = DetectorTestUtilityCreator.Create<PodComponentDetector>();
}
[TestMethod]
public async Task TestPodDetector_EmptyPodfileLockAsync()
{
@ -31,7 +22,7 @@ public class PodDetectorTest
COCOAPODS: 1.4.0.beta.1";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.ExecuteDetectorAsync();
@ -67,7 +58,7 @@ SPEC CHECKSUMS:
COCOAPODS: 0.39.0";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.ExecuteDetectorAsync();
@ -109,7 +100,7 @@ PODFILE CHECKSUM: accace11c2720ac62a63c1b7629cc202a7e108b8
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.ExecuteDetectorAsync();
@ -153,7 +144,7 @@ PODFILE CHECKSUM: accace11c2720ac62a63c1b7629cc202a7e108b8
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.ExecuteDetectorAsync();
@ -196,7 +187,7 @@ PODFILE CHECKSUM: accace11c2720ac62a63c1b7629cc202a7e108b8
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.ExecuteDetectorAsync();
@ -239,7 +230,7 @@ PODFILE CHECKSUM: accace11c2720ac62a63c1b7629cc202a7e108b8
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.ExecuteDetectorAsync();
@ -276,7 +267,7 @@ PODFILE CHECKSUM: accace11c2720ac62a63c1b7629cc202a7e108b8
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.ExecuteDetectorAsync();
@ -309,7 +300,7 @@ PODFILE CHECKSUM: accace11c2720ac62a63c1b7629cc202a7e108b8
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.ExecuteDetectorAsync();
@ -374,7 +365,7 @@ PODFILE CHECKSUM: accace11c2720ac62a63c1b7629cc202a7e108b8
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.WithFile("Podfile.lock", podfileLockContent2)
.ExecuteDetectorAsync();
@ -458,7 +449,7 @@ PODFILE CHECKSUM: accace11c2720ac62a63c1b7629cc202a7e108b8
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.WithFile("Podfile.lock", podfileLockContent2)
.ExecuteDetectorAsync();
@ -555,7 +546,7 @@ PODFILE CHECKSUM: accace11c2720ac62a63c1b7629cc202a7e108b8
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.WithFile("Podfile.lock", podfileLockContent2)
.ExecuteDetectorAsync();
@ -636,7 +627,7 @@ SPEC CHECKSUMS:
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.WithFile("Podfile.lock", podfileLockContent2)
.WithFile("Podfile.lock", podfileLockContent3)
@ -683,7 +674,7 @@ SPEC CHECKSUMS:
COCOAPODS: 1.8.4";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("Podfile.lock", podfileLockContent)
.WithFile("Podfile.lock", podfileLockContent2, fileLocation: Path.Join(Path.GetTempPath(), "sub-folder", "Podfile.lock"))
.ExecuteDetectorAsync();

Просмотреть файл

@ -6,22 +6,13 @@ using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Contracts.TypedComponent;
using Microsoft.ComponentDetection.Detectors.Poetry;
using Microsoft.ComponentDetection.Detectors.Tests.Utilities;
using Microsoft.ComponentDetection.TestsUtilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
[TestCategory("Governance/All")]
[TestCategory("Governance/ComponentDetection")]
public class PoetryComponentDetectorTests
public class PoetryComponentDetectorTests : BaseDetectorTest<PoetryComponentDetector>
{
private DetectorTestUtility<PoetryComponentDetector> detectorTestUtility;
[TestInitialize]
public void TestInitialize()
{
this.detectorTestUtility = DetectorTestUtilityCreator.Create<PoetryComponentDetector>();
}
[TestMethod]
public async Task TestPoetryDetector_TestCustomSourceAsync()
{
@ -39,7 +30,7 @@ url = ""https://pypi.custom.com//simple""
reference = ""custom""
";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("poetry.lock", poetryLockContent)
.ExecuteDetectorAsync();
@ -65,7 +56,7 @@ optional = false
python-versions = ""*""
";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("poetry.lock", poetryLockContent)
.ExecuteDetectorAsync();
@ -116,7 +107,7 @@ url = ""https://github.com/requests/requests.git""
reference = ""master""
resolved_reference = ""232a5596424c98d11c3cf2e29b2f6a6c591c2ff3""";
var (scanResult, componentRecorder) = await this.detectorTestUtility
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile("poetry.lock", poetryLockContent)
.ExecuteDetectorAsync();

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше