refactor: migrate away from MEF to Dependency Injection (#412)
This commit is contained in:
Родитель
80318142b0
Коммит
f6912c0258
|
@ -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();
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче