diff --git a/docs/detectors/conan.md b/docs/detectors/conan.md new file mode 100644 index 00000000..feaec0cd --- /dev/null +++ b/docs/detectors/conan.md @@ -0,0 +1,11 @@ +# Conan Detection +## Requirements +Conan detection relies on a conan.lock file being present. + +## Detection strategy +Conan detection is performed by parsing every **conan.lock** found under the scan directory. + +## Known limitations +Conan detection will not work if lock files are not being used or not yet generated. So ensure to run the conan build to generate the lock file(s) before running the scan. + +Full dependency graph generation is not supported. However, dependency relationships identified/present in the **conan.lock** file is captured. diff --git a/src/Microsoft.ComponentDetection.Contracts/BcdeModels/TypedComponentConverter.cs b/src/Microsoft.ComponentDetection.Contracts/BcdeModels/TypedComponentConverter.cs index 6decd56c..0ed8aa09 100644 --- a/src/Microsoft.ComponentDetection.Contracts/BcdeModels/TypedComponentConverter.cs +++ b/src/Microsoft.ComponentDetection.Contracts/BcdeModels/TypedComponentConverter.cs @@ -17,6 +17,7 @@ public class TypedComponentConverter : JsonConverter { ComponentType.Git, typeof(GitComponent) }, { ComponentType.RubyGems, typeof(RubyGemsComponent) }, { ComponentType.Cargo, typeof(CargoComponent) }, + { ComponentType.Conan, typeof(ConanComponent) }, { ComponentType.Pip, typeof(PipComponent) }, { ComponentType.Go, typeof(GoComponent) }, { ComponentType.DockerImage, typeof(DockerImageComponent) }, diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs index 762f7869..371ad836 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs @@ -53,4 +53,7 @@ public enum ComponentType : byte [EnumMember] DockerReference = 16, + + [EnumMember] + Conan = 17, } diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ConanComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ConanComponent.cs new file mode 100644 index 00000000..7d114a02 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ConanComponent.cs @@ -0,0 +1,27 @@ +namespace Microsoft.ComponentDetection.Contracts.TypedComponent; + +using PackageUrl; + +public class ConanComponent : TypedComponent +{ + private ConanComponent() + { + // reserved for deserialization + } + + public ConanComponent(string name, string version) + { + this.Name = this.ValidateRequiredInput(name, nameof(this.Name), nameof(ComponentType.Conan)); + this.Version = this.ValidateRequiredInput(version, nameof(this.Version), nameof(ComponentType.Conan)); + } + + public string Name { get; set; } + + public string Version { get; set; } + + public override ComponentType Type => ComponentType.Conan; + + public override string Id => $"{this.Name} {this.Version} - {this.Type}"; + + public override PackageURL PackageUrl => new PackageURL("conan", string.Empty, this.Name, this.Version, null, string.Empty); +} diff --git a/src/Microsoft.ComponentDetection.Detectors/conan/ConanLockComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/conan/ConanLockComponentDetector.cs new file mode 100644 index 00000000..48519940 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/conan/ConanLockComponentDetector.cs @@ -0,0 +1,91 @@ +namespace Microsoft.ComponentDetection.Detectors.Conan; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.ComponentDetection.Contracts; +using Microsoft.ComponentDetection.Contracts.Internal; +using Microsoft.ComponentDetection.Contracts.TypedComponent; +using Microsoft.ComponentDetection.Detectors.Conan.Contracts; +using Microsoft.Extensions.Logging; + +public class ConanLockComponentDetector : FileComponentDetector, IDefaultOffComponentDetector +{ + public ConanLockComponentDetector( + IComponentStreamEnumerableFactory componentStreamEnumerableFactory, + IObservableDirectoryWalkerFactory walkerFactory, + ILogger logger) + { + this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory; + this.Scanner = walkerFactory; + this.Logger = logger; + } + + public override string Id => "ConanLock"; + + public override IList SearchPatterns => new List { "conan.lock" }; + + public override IEnumerable SupportedComponentTypes => new[] { ComponentType.Conan }; + + public override int Version { get; } = 1; + + public override IEnumerable Categories => new List { "Conan" }; + + protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary detectorArgs) + { + var singleFileComponentRecorder = processRequest.SingleFileComponentRecorder; + var conanLockFile = processRequest.ComponentStream; + + try + { + var conanLock = await JsonSerializer.DeserializeAsync(conanLockFile.Stream); + this.RecordLockfileVersion(conanLock.Version); + + if (!conanLock.HasNodes()) + { + return; + } + + var packagesDictionary = conanLock.GraphLock.Nodes; + var explicitReferencedDependencies = new HashSet(); + var developmentDependencies = new HashSet(); + if (packagesDictionary.ContainsKey("0")) + { + packagesDictionary.Remove("0", out var rootNode); + if (rootNode?.Requires != null) + { + explicitReferencedDependencies = new HashSet(rootNode.Requires); + } + + if (rootNode?.BuildRequires != null) + { + developmentDependencies = new HashSet(rootNode.BuildRequires); + } + } + + foreach (var (packageIndex, package) in packagesDictionary) + { + singleFileComponentRecorder.RegisterUsage( + new DetectedComponent(package.ToComponent()), + isExplicitReferencedDependency: explicitReferencedDependencies.Contains(packageIndex), + isDevelopmentDependency: developmentDependencies.Contains(packageIndex)); + } + + foreach (var (conanPackageIndex, package) in packagesDictionary) + { + var parentPackages = packagesDictionary.Values.Where(package => package.Requires?.Contains(conanPackageIndex) == true); + foreach (var parentPackage in parentPackages) + { + singleFileComponentRecorder.RegisterUsage(new DetectedComponent(package.ToComponent()), false, parentPackage.ToComponent().Id, isDevelopmentDependency: false); + } + } + } + catch (Exception e) + { + // If something went wrong, just ignore the file + this.Logger.LogError(e, "Failed to process conan.lock file '{ConanLockLocation}'", conanLockFile.Location); + } + } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/conan/Contracts/ConanLock.cs b/src/Microsoft.ComponentDetection.Detectors/conan/Contracts/ConanLock.cs new file mode 100644 index 00000000..8617dfdc --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/conan/Contracts/ConanLock.cs @@ -0,0 +1,20 @@ +namespace Microsoft.ComponentDetection.Detectors.Conan.Contracts; + +using System.Text.Json.Serialization; + +public class ConanLock +{ + [JsonPropertyName("version")] + public string Version { get; set; } + + [JsonPropertyName("profile_host")] + public string ProfileHost { get; set; } + + [JsonPropertyName("profile_build")] + public string ProfileBuild { get; set; } + + [JsonPropertyName("graph_lock")] + public ConanLockGraph GraphLock { get; set; } + + internal bool HasNodes() => this.GraphLock?.Nodes?.Count > 0; +} diff --git a/src/Microsoft.ComponentDetection.Detectors/conan/Contracts/ConanLockGraph.cs b/src/Microsoft.ComponentDetection.Detectors/conan/Contracts/ConanLockGraph.cs new file mode 100644 index 00000000..e3a79d98 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/conan/Contracts/ConanLockGraph.cs @@ -0,0 +1,13 @@ +namespace Microsoft.ComponentDetection.Detectors.Conan.Contracts; + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +public class ConanLockGraph +{ + [JsonPropertyName("revisions_enabled")] + public bool RevisionsEnabled { get; set; } + + [JsonPropertyName("nodes")] + public Dictionary Nodes { get; set; } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/conan/Contracts/ConanLockNode.cs b/src/Microsoft.ComponentDetection.Detectors/conan/Contracts/ConanLockNode.cs new file mode 100644 index 00000000..ae58b90d --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/conan/Contracts/ConanLockNode.cs @@ -0,0 +1,42 @@ +namespace Microsoft.ComponentDetection.Detectors.Conan.Contracts; + +using System; +using System.Linq; +using System.Text.Json.Serialization; +using Microsoft.ComponentDetection.Contracts.TypedComponent; + +public class ConanLockNode +{ + [JsonPropertyName("context")] + public string Context { get; set; } + + [JsonPropertyName("modified")] + public bool? Modified { get; set; } + + [JsonPropertyName("options")] + public string Options { get; set; } + + [JsonPropertyName("package_id")] + public string PackageId { get; set; } + + [JsonPropertyName("path")] + public string Path { get; set; } + + [JsonPropertyName("prev")] + public string Previous { get; set; } + + [JsonPropertyName("ref")] + public string Reference { get; set; } + + [JsonPropertyName("requires")] + public string[] Requires { get; set; } + + [JsonPropertyName("build_requires")] + public string[] BuildRequires { get; set; } + + internal string Name() => this.Reference == null ? string.Empty : this.Reference.Split('/', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).FirstOrDefault("Unknown"); + + internal TypedComponent ToComponent() => new ConanComponent(this.Name(), this.Version()); + + internal string Version() => this.Reference == null ? string.Empty : this.Reference.Split('/', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).Skip(1).FirstOrDefault("None"); +} diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs b/src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs index bbfef1ee..6ddbe37f 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs @@ -4,6 +4,7 @@ using Microsoft.ComponentDetection.Common; using Microsoft.ComponentDetection.Common.Telemetry; using Microsoft.ComponentDetection.Contracts; using Microsoft.ComponentDetection.Detectors.CocoaPods; +using Microsoft.ComponentDetection.Detectors.Conan; using Microsoft.ComponentDetection.Detectors.Dockerfile; using Microsoft.ComponentDetection.Detectors.Go; using Microsoft.ComponentDetection.Detectors.Gradle; @@ -78,6 +79,9 @@ public static class ServiceCollectionExtensions // CocoaPods services.AddSingleton(); + // Conan + services.AddSingleton(); + // Conda services.AddSingleton(); diff --git a/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs b/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs index d65bbcb5..a0d840ca 100644 --- a/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs +++ b/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs @@ -122,6 +122,18 @@ public class TypedComponentSerializationTests cargoComponent.Version.Should().Be("1.2.3"); } + [TestMethod] + public void TypedComponent_Serialization_Conan() + { + TypedComponent tc = new ConanComponent("SomeConanPackage", "1.2.3"); + var result = JsonConvert.SerializeObject(tc); + var deserializedTC = JsonConvert.DeserializeObject(result); + deserializedTC.Should().BeOfType(typeof(ConanComponent)); + var conanComponent = (ConanComponent)deserializedTC; + conanComponent.Name.Should().Be("SomeConanPackage"); + conanComponent.Version.Should().Be("1.2.3"); + } + [TestMethod] public void TypedComponent_Serialization_Pip() { diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/ConanLockComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/ConanLockComponentDetectorTests.cs new file mode 100644 index 00000000..69208325 --- /dev/null +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/ConanLockComponentDetectorTests.cs @@ -0,0 +1,259 @@ +namespace Microsoft.ComponentDetection.Detectors.Tests; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.ComponentDetection.Contracts; +using Microsoft.ComponentDetection.Contracts.TypedComponent; +using Microsoft.ComponentDetection.Detectors.Conan; +using Microsoft.ComponentDetection.Detectors.Tests.Utilities; +using Microsoft.ComponentDetection.TestsUtilities; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +[TestCategory("Governance/All")] +[TestCategory("Governance/ComponentDetection")] +public class ConanLockComponentDetectorTests : BaseDetectorTest +{ + private readonly string testConanLockString = @"{ + ""graph_lock"": { + ""nodes"": { + ""0"": { + ""ref"": ""MyConanProject/None"", + ""options"": ""SomeLongOptionsString"", + ""requires"": [ + ""1"", + ""2"", + ""3"", + ""4"", + ""5"", + ""6"" + ], + ""path"": ""../conanfile.py"", + ""context"": ""host"" + }, + ""1"": { + ""ref"": ""libabc/1.2.12#someHashOfLibAbc"", + ""options"": ""someOptionsString"", + ""package_id"": ""packageIdOfLibAbc"", + ""prev"": ""someHashOfLibAbc"", + ""context"": ""host"" + }, + ""2"": { + ""ref"": ""libawesomelibrary/3.2.1#someHashOfLibAwesomeLibrary"", + ""options"": ""someOptionsString"", + ""package_id"": ""packageIdOfLibAwesomeLibrary"", + ""prev"": ""someHashOfLibAwesomeLibrary"", + ""requires"": [ + ""1"" + ], + ""context"": ""host"" + }, + ""3"": { + ""ref"": ""libanotherlibrary1/2.3.4#someHashOfLibAnotherLibrary1"", + ""options"": ""someOptionsString"", + ""package_id"": ""packageIdOfLibAnotherLibrary1"", + ""prev"": ""someHashOfLibAnotherLibrary1"", + ""requires"": [ + ""4"", + ""6"" + ], + ""context"": ""host"" + }, + ""4"": { + ""ref"": ""libanotherlibrary2/3.4.5#someHashOfLibAnotherLibrary2"", + ""options"": ""someOptionsString"", + ""package_id"": ""packageIdOfLibAnotherLibrary2"", + ""prev"": ""someHashOfLibAnotherLibrary2"", + ""requires"": [ + ""5"" + ], + ""context"": ""host"" + }, + ""5"": { + ""ref"": ""libanotherlibrary3/4.5.6#someHashOfLibAnotherLibrary3"", + ""options"": """", + ""package_id"": ""packageIdOfLibAnotherLibrary3"", + ""prev"": ""someHashOfLibAnotherLibrary3"", + ""context"": ""host"" + }, + ""6"": { + ""ref"": ""libanotherlibrary4/5.6.7#someHashOfLibAnotherLibrary4"", + ""options"": ""someOptionsString"", + ""package_id"": ""packageIdOfLibAnotherLibrary4"", + ""prev"": ""someHashOfLibAnotherLibrary4"", + ""modified"": true, + ""context"": ""host"" + } + }, + ""revisions_enabled"": true + }, + ""version"": ""0.4"", + ""profile_host"": ""someLongProfileHostSettingsString\n"", + ""profile_build"": ""someLongProfileBuildSettingsString\n"" +} +"; + + private readonly string testConanLockStringWithNullValueForRootNode = @"{ + ""graph_lock"": { + ""nodes"": { + ""0"": null, + ""1"": { + ""ref"": ""libabc/1.2.12#someHashOfLibAbc"", + ""options"": ""someOptionsString"", + ""package_id"": ""packageIdOfLibAbc"", + ""prev"": ""someHashOfLibAbc"", + ""context"": ""host"" + } + }, + ""revisions_enabled"": true + }, + ""version"": ""0.4"", + ""profile_host"": ""someLongProfileHostSettingsString\n"", + ""profile_build"": ""someLongProfileBuildSettingsString\n"" +} +"; + + private readonly string testConanLockNoDependenciesString = @"{ + ""graph_lock"": { + ""nodes"": { + ""0"": { + ""ref"": ""MyConanProject/None"", + ""options"": ""SomeLongOptionsString"", + ""path"": ""../conanfile.py"", + ""context"": ""host"" + } + }, + ""revisions_enabled"": true + }, + ""version"": ""0.4"", + ""profile_host"": ""someLongProfileHostSettingsString\n"", + ""profile_build"": ""someLongProfileBuildSettingsString\n"" +} +"; + + [TestMethod] + public async Task TestGraphIsCorrectAsync() + { + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("Conan.lock", this.testConanLockString) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + componentRecorder.GetDetectedComponents().Count().Should().Be(6); + + var graph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); // There should only be 1 + + // Verify explicitly referenced roots + var rootComponents = new List + { + "libabc 1.2.12#someHashOfLibAbc - Conan", + "libawesomelibrary 3.2.1#someHashOfLibAwesomeLibrary - Conan", + "libanotherlibrary1 2.3.4#someHashOfLibAnotherLibrary1 - Conan", + "libanotherlibrary2 3.4.5#someHashOfLibAnotherLibrary2 - Conan", + "libanotherlibrary3 4.5.6#someHashOfLibAnotherLibrary3 - Conan", + "libanotherlibrary4 5.6.7#someHashOfLibAnotherLibrary4 - Conan", + }; + + var enumerable = graph.GetComponents().ToList(); + + rootComponents.ForEach(rootComponentId => + { + graph.IsComponentExplicitlyReferenced(rootComponentId).Should().BeTrue($"Expected Component to be explicitly referenced but it is not: {rootComponentId}"); + }); + + // components without any dependencies + graph.GetDependenciesForComponent("libabc 1.2.12#someHashOfLibAbc - Conan").Should().BeEmpty(); + graph.GetDependenciesForComponent("libanotherlibrary3 4.5.6#someHashOfLibAnotherLibrary3 - Conan").Should().BeEmpty(); + graph.GetDependenciesForComponent("libanotherlibrary4 5.6.7#someHashOfLibAnotherLibrary4 - Conan").Should().BeEmpty(); + + // Verify dependencies for other dependencies + graph.GetDependenciesForComponent("libawesomelibrary 3.2.1#someHashOfLibAwesomeLibrary - Conan").Should().BeEquivalentTo(new[] { "libabc 1.2.12#someHashOfLibAbc - Conan" }); + var a = graph.GetDependenciesForComponent("libanotherlibrary1 2.3.4#someHashOfLibAnotherLibrary1 - Conan"); + graph.GetDependenciesForComponent("libanotherlibrary1 2.3.4#someHashOfLibAnotherLibrary1 - Conan").Should().BeEquivalentTo(new[] { "libanotherlibrary2 3.4.5#someHashOfLibAnotherLibrary2 - Conan", "libanotherlibrary4 5.6.7#someHashOfLibAnotherLibrary4 - Conan" }); + graph.GetDependenciesForComponent("libanotherlibrary2 3.4.5#someHashOfLibAnotherLibrary2 - Conan").Should().BeEquivalentTo(new[] { "libanotherlibrary3 4.5.6#someHashOfLibAnotherLibrary3 - Conan" }); + } + + [TestMethod] + public async Task TestDetectionForConanLockFileWithNullValuesForRootNodeAsync() + { + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("Conan.lock", this.testConanLockStringWithNullValueForRootNode) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + componentRecorder.GetDetectedComponents().Count().Should().Be(1); + + (componentRecorder.GetDetectedComponents().First().Component as ConanComponent).Name.Should().Be("libabc"); + (componentRecorder.GetDetectedComponents().First().Component as ConanComponent).Version.Should().Be("1.2.12#someHashOfLibAbc"); + } + + [TestMethod] + public async Task TestConanDetectorAsync() + { + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("Conan.lock", this.testConanLockString) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + componentRecorder.GetDetectedComponents().Count().Should().Be(6); + + IDictionary packageVersions = new Dictionary() + { + { "libabc", "1.2.12#someHashOfLibAbc" }, + { "libawesomelibrary", "3.2.1#someHashOfLibAwesomeLibrary" }, + { "libanotherlibrary1", "2.3.4#someHashOfLibAnotherLibrary1" }, + { "libanotherlibrary2", "3.4.5#someHashOfLibAnotherLibrary2" }, + { "libanotherlibrary3", "4.5.6#someHashOfLibAnotherLibrary3" }, + { "libanotherlibrary4", "5.6.7#someHashOfLibAnotherLibrary4" }, + }; + + IDictionary> packageDependencyRoots = new Dictionary>() + { + { "libabc", new HashSet() { "libabc", "libawesomelibrary" } }, + { "libawesomelibrary", new HashSet() { "libawesomelibrary" } }, + { "libanotherlibrary1", new HashSet() { "libanotherlibrary1" } }, + { "libanotherlibrary2", new HashSet() { "libanotherlibrary2", "libanotherlibrary1" } }, + { "libanotherlibrary3", new HashSet() { "libanotherlibrary3", "libanotherlibrary1", "libanotherlibrary2" } }, + { "libanotherlibrary4", new HashSet() { "libanotherlibrary4", "libanotherlibrary1" } }, + }; + + ISet componentNames = new HashSet(); + foreach (var discoveredComponent in componentRecorder.GetDetectedComponents()) + { + // Verify each package has the right information + var packageName = (discoveredComponent.Component as ConanComponent).Name; + + // Verify version + (discoveredComponent.Component as ConanComponent).Version.Should().Be(packageVersions[packageName]); + + var dependencyRoots = new HashSet(); + + componentRecorder.AssertAllExplicitlyReferencedComponents( + discoveredComponent.Component.Id, + packageDependencyRoots[packageName].Select(expectedRoot => + new Func(parentComponent => parentComponent.Name == expectedRoot)).ToArray()); + + componentNames.Add(packageName); + } + + // Verify all packages were detected + foreach (var expectedPackage in packageVersions.Keys) + { + componentNames.Should().Contain(expectedPackage); + } + } + + [TestMethod] + public async Task TestConanDetector_SupportNoDependenciesAsync() + { + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("conan.lock", this.testConanLockNoDependenciesString) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); + } +} diff --git a/test/Microsoft.ComponentDetection.VerificationTests/resources/VerificationTest.ps1 b/test/Microsoft.ComponentDetection.VerificationTests/resources/VerificationTest.ps1 old mode 100644 new mode 100755 index f19d0067..cf5e827a --- a/test/Microsoft.ComponentDetection.VerificationTests/resources/VerificationTest.ps1 +++ b/test/Microsoft.ComponentDetection.VerificationTests/resources/VerificationTest.ps1 @@ -38,14 +38,14 @@ function main() Set-Location ((Get-Item $repoPath).FullName + "\src\Microsoft.ComponentDetection") dotnet run scan --SourceDirectory $verificationTestRepo --Output $output ` --DockerImagesToScan $dockerImagesToScan ` - --DetectorArgs DockerReference=EnableIfDefaultOff,SPDX22SBOM=EnableIfDefaultOff,CondaLock=EnableIfDefaultOff + --DetectorArgs DockerReference=EnableIfDefaultOff,SPDX22SBOM=EnableIfDefaultOff,CondaLock=EnableIfDefaultOff,ConanLock=EnableIfDefaultOff Set-Location $CDRelease dotnet restore Set-Location ($CDRelease + "\src\Microsoft.ComponentDetection") dotnet run scan --SourceDirectory $verificationTestRepo --Output $releaseOutput ` --DockerImagesToScan $dockerImagesToScan ` - --DetectorArgs DockerReference=EnableIfDefaultOff,SPDX22SBOM=EnableIfDefaultOff,CondaLock=EnableIfDefaultOff + --DetectorArgs DockerReference=EnableIfDefaultOff,SPDX22SBOM=EnableIfDefaultOff,CondaLock=EnableIfDefaultOff,ConanLock=EnableIfDefaultOff $env:GITHUB_OLD_ARTIFACTS_DIR = $releaseOutput $env:GITHUB_NEW_ARTIFACTS_DIR = $output diff --git a/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanPythonFile/conan.lock b/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanPythonFile/conan.lock new file mode 100644 index 00000000..84b7147e --- /dev/null +++ b/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanPythonFile/conan.lock @@ -0,0 +1,77 @@ +{ + "graph_lock": { + "nodes": { + "0": { + "ref": "MyAwesomeConanProject/1.2.5", + "options": "", + "requires": [ + "1" + ], + "build_requires": [ + "6" + ], + "path": "conanfile.py", + "context": "host" + }, + "1": { + "ref": "boost/1.82.0", + "options": "", + "package_id": "dd7f5f958c7381cfd81e611a16062de0c827160a", + "prev": "0", + "modified": true, + "requires": [ + "2", + "3", + "4" + ], + "build_requires": [ + "5" + ], + "context": "host" + }, + "2": { + "ref": "zlib/1.2.13", + "options": "", + "package_id": "240c2182163325b213ca6886a7614c8ed2bf1738", + "prev": "0", + "modified": true, + "context": "host" + }, + "3": { + "ref": "bzip2/1.0.8", + "options": "", + "package_id": "238a93dc813ca1550968399f1f8925565feeff8e", + "prev": "0", + "modified": true, + "context": "host" + }, + "4": { + "ref": "libbacktrace/cci.20210118", + "options": "", + "package_id": "240c2182163325b213ca6886a7614c8ed2bf1738", + "prev": "0", + "modified": true, + "context": "host" + }, + "5": { + "ref": "b2/4.9.6", + "options": "", + "package_id": "a5ad5696abf650a25eea8f377806b3d5fe234e6e", + "prev": "0", + "modified": true, + "context": "host" + }, + "6": { + "ref": "gtest/1.8.1", + "options": "", + "package_id": "fb16a498e820fb09d04ff9374a782b5b21da0601", + "prev": "0", + "modified": true, + "context": "host" + } + }, + "revisions_enabled": false + }, + "version": "0.4", + "profile_host": "\n" +} \ No newline at end of file diff --git a/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanPythonFile/conanfile.py b/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanPythonFile/conanfile.py new file mode 100644 index 00000000..6d0e2e71 --- /dev/null +++ b/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanPythonFile/conanfile.py @@ -0,0 +1,11 @@ +from conans import ConanFile + +class MyAwesome(ConanFile): + name = "MyAwesomeConanProject" + version = "1.2.5" + + def requirements(self): + self.requires("boost/1.82.0") + + def build_requirements(self): + self.tool_requires("gtest/1.8.1") diff --git a/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanTextFile/conan.lock b/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanTextFile/conan.lock new file mode 100644 index 00000000..560ece63 --- /dev/null +++ b/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanTextFile/conan.lock @@ -0,0 +1,60 @@ +{ + "graph_lock": { + "nodes": { + "0": { + "options": "", + "requires": [ + "1" + ], + "build_requires": [ + "5" + ], + "path": "conanfile.txt", + "context": "host" + }, + "1": { + "ref": "boost/1.82.0", + "options": "", + "package_id": "dd7f5f958c7381cfd81e611a16062de0c827160a", + "prev": "0", + "requires": [ + "2", + "3", + "4" + ], + "context": "host" + }, + "2": { + "ref": "zlib/1.2.13", + "options": "", + "package_id": "240c2182163325b213ca6886a7614c8ed2bf1738", + "prev": "0", + "context": "host" + }, + "3": { + "ref": "bzip2/1.0.8", + "options": "", + "package_id": "238a93dc813ca1550968399f1f8925565feeff8e", + "prev": "0", + "context": "host" + }, + "4": { + "ref": "libbacktrace/cci.20210118", + "options": "", + "package_id": "240c2182163325b213ca6886a7614c8ed2bf1738", + "prev": "0", + "context": "host" + }, + "5": { + "ref": "gtest/1.8.1", + "options": "", + "package_id": "fb16a498e820fb09d04ff9374a782b5b21da0601", + "prev": "0", + "context": "host" + } + }, + "revisions_enabled": false + }, + "version": "0.4", + "profile_host": "\n" +} \ No newline at end of file diff --git a/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanTextFile/conanfile.txt b/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanTextFile/conanfile.txt new file mode 100644 index 00000000..b7eba86a --- /dev/null +++ b/test/Microsoft.ComponentDetection.VerificationTests/resources/conan/conanTextFile/conanfile.txt @@ -0,0 +1,5 @@ +[requires] +boost/1.82.0 + +[tool_requires] +gtest/1.8.1