diff --git a/src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs b/src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs index 83363b1a3..12c995077 100644 --- a/src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs +++ b/src/Microsoft.ComponentDetection.Contracts/DetectorClass.cs @@ -35,8 +35,11 @@ public enum DetectorClass /// Indicates a detector applies to Conda packages. Conda, - + /// Indicates a detector applies to SPDX files. Spdx, + + /// Indicates a detector applies to Vcpkg packages. + Vcpkg, } } diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs index 73c25652b..f02c639b8 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ComponentType.cs @@ -44,8 +44,11 @@ public enum ComponentType : byte [EnumMember] Conda = 13, - + [EnumMember] Spdx = 14, + + [EnumMember] + Vcpkg = 15, } } \ No newline at end of file diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/VcpkgComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/VcpkgComponent.cs new file mode 100644 index 000000000..41037f922 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/VcpkgComponent.cs @@ -0,0 +1,73 @@ +using PackageUrl; + +namespace Microsoft.ComponentDetection.Contracts.TypedComponent +{ + public class VcpkgComponent : TypedComponent + { + private VcpkgComponent() + { + /* Reserved for deserialization */ + } + + public VcpkgComponent(string spdxid, string name, string version, string triplet = null, string portVersion = null, string description = null, string downloadLocation = null) + { + SPDXID = ValidateRequiredInput(spdxid, nameof(SPDXID), nameof(ComponentType.Vcpkg)); + Name = ValidateRequiredInput(name, nameof(Name), nameof(ComponentType.Vcpkg)); + Version = version; + PortVersion = portVersion; + Triplet = triplet; + Description = description; + DownloadLocation = downloadLocation; + } + + public string SPDXID { get; set; } + + public string Name { get; set; } + + public string DownloadLocation { get; set; } + + public string Triplet { get; set; } + + public string Version { get; set; } + + public string Description { get; set; } + + public string PortVersion { get; set; } + + public override ComponentType Type => ComponentType.Vcpkg; + + public override string Id + { + get + { + if (PortVersion != null) + { + return $"{Name} {Version}#{PortVersion} - {Type}"; + } + else + { + return $"{Name} {Version} - {Type}"; + } + } + } + + public override PackageURL PackageUrl + { + get + { + if (PortVersion != null) + { + return new PackageURL($"pkg:vcpkg/{Name}@{Version}?port_version={PortVersion}"); + } + else if (Version != null) + { + return new PackageURL($"pkg:vcpkg/{Name}@{Version}"); + } + else + { + return new PackageURL($"pkg:vcpkg/{Name}"); + } + } + } + } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/vcpkg/Contracts/Annotation.cs b/src/Microsoft.ComponentDetection.Detectors/vcpkg/Contracts/Annotation.cs new file mode 100644 index 000000000..0a11ca4cd --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/vcpkg/Contracts/Annotation.cs @@ -0,0 +1,15 @@ +using System; + +namespace Microsoft.ComponentDetection.Detectors.Vcpkg.Contracts +{ + public class Annotation + { + public DateTime Date { get; set; } + + public string Comment { get; set; } + + public string Type { get; set; } + + public string Annotator { get; set; } + } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/vcpkg/Contracts/Package.cs b/src/Microsoft.ComponentDetection.Detectors/vcpkg/Contracts/Package.cs new file mode 100644 index 000000000..fd4b7a6e8 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/vcpkg/Contracts/Package.cs @@ -0,0 +1,21 @@ +namespace Microsoft.ComponentDetection.Detectors.Vcpkg.Contracts +{ + public class Package + { + public string SPDXID { get; set; } + + public string VersionInfo { get; set; } + + public string DownloadLocation { get; set; } + + public string Filename { get; set; } + + public string Homepage { get; set; } + + public string Description { get; set; } + + public string Name { get; set; } + + public Annotation[] Annotations { get; set; } + } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/vcpkg/Contracts/VcpkgSBOM.cs b/src/Microsoft.ComponentDetection.Detectors/vcpkg/Contracts/VcpkgSBOM.cs new file mode 100644 index 000000000..77c53be03 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/vcpkg/Contracts/VcpkgSBOM.cs @@ -0,0 +1,12 @@ +namespace Microsoft.ComponentDetection.Detectors.Vcpkg.Contracts +{ + /// + /// Matches a subset of https://raw.githubusercontent.com/spdx/spdx-spec/v2.2.1/schemas/spdx-schema.json. + /// + public class VcpkgSBOM + { + public Package[] Packages { get; set; } + + public string Name { get; set; } + } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/vcpkg/VcpkgComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/vcpkg/VcpkgComponentDetector.cs new file mode 100644 index 000000000..60a8e99c6 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/vcpkg/VcpkgComponentDetector.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Composition; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.ComponentDetection.Common; +using Microsoft.ComponentDetection.Common.Telemetry.Records; +using Microsoft.ComponentDetection.Contracts; +using Microsoft.ComponentDetection.Contracts.Internal; +using Microsoft.ComponentDetection.Contracts.TypedComponent; +using Microsoft.ComponentDetection.Detectors.Vcpkg.Contracts; +using Newtonsoft.Json; + +namespace Microsoft.ComponentDetection.Detectors.Vcpkg +{ + [Export(typeof(IComponentDetector))] + public class VcpkgComponentDetector : FileComponentDetector, IDefaultOffComponentDetector + { + [Import] + public ICommandLineInvocationService CommandLineInvocationService { get; set; } + + [Import] + public IEnvironmentVariableService EnvVarService { get; set; } + + public override string Id { get; } = "Vcpkg"; + + public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Vcpkg) }; + + public override IList SearchPatterns { get; } = new List { "vcpkg.spdx.json" }; + + public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Vcpkg }; + + public override int Version => 1; + + private HashSet projectRoots = new HashSet(); + + protected override async Task OnFileFound(ProcessRequest processRequest, IDictionary detectorArgs) + { + var singleFileComponentRecorder = processRequest.SingleFileComponentRecorder; + var file = processRequest.ComponentStream; + + Logger.LogWarning($"vcpkg detector found {file}"); + + var projectRootDirectory = Directory.GetParent(file.Location); + if (projectRoots.Any(path => projectRootDirectory.FullName.StartsWith(path))) + { + return; + } + + await ParseSpdxFile(singleFileComponentRecorder, file); + } + + private async Task ParseSpdxFile( + ISingleFileComponentRecorder singleFileComponentRecorder, + IComponentStream file) + { + using var reader = new StreamReader(file.Stream); + VcpkgSBOM sbom; + try + { + sbom = JsonConvert.DeserializeObject(await reader.ReadToEndAsync()); + } + catch (Exception) + { + return; + } + + if (sbom?.Packages == null) + { + return; + } + + foreach (var item in sbom.Packages) + { + try + { + if (string.IsNullOrEmpty(item.Name)) + { + continue; + } + + Logger.LogWarning($"parsed package {item.Name}"); + if (item.SPDXID == "SPDXRef-port") + { + var split = item.VersionInfo.Split('#'); + var component = new VcpkgComponent(item.SPDXID, item.Name, split[0], portVersion: split.Length >= 2 ? split[1] : "0", downloadLocation: item.DownloadLocation); + singleFileComponentRecorder.RegisterUsage(new DetectedComponent(component)); + } + else if (item.SPDXID == "SPDXRef-binary") + { + var split = item.Name.Split(':'); + var component = new VcpkgComponent(item.SPDXID, item.Name, item.VersionInfo, triplet: split[1], downloadLocation: item.DownloadLocation); + singleFileComponentRecorder.RegisterUsage(new DetectedComponent(component)); + } + else if (item.SPDXID.StartsWith("SPDXRef-resource-")) + { + var dl = item.DownloadLocation; + var split = dl.Split("#"); + var subpath = split.Length > 1 ? split[1] : null; + dl = split.Length > 1 ? split[0] : dl; + split = dl.Split("@"); + var version = split.Length > 1 ? split[1] : null; + dl = split.Length > 1 ? split[0] : dl; + + var component = new VcpkgComponent(item.SPDXID, item.Name, version, downloadLocation: dl); + singleFileComponentRecorder.RegisterUsage(new DetectedComponent(component)); + } + } + catch (Exception) + { + Logger.LogWarning($"failed while handling {item.Name}"); + } + } + } + } +} diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/VcpkgComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/VcpkgComponentDetectorTests.cs new file mode 100644 index 000000000..9e28ccaa6 --- /dev/null +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/VcpkgComponentDetectorTests.cs @@ -0,0 +1,174 @@ +using Microsoft.ComponentDetection.Common.DependencyGraph; +using Microsoft.ComponentDetection.Contracts; +using Microsoft.ComponentDetection.TestsUtilities; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using Microsoft.ComponentDetection.Contracts.TypedComponent; +using Microsoft.ComponentDetection.Detectors.Vcpkg; +using System.Reflection; + +namespace Microsoft.ComponentDetection.Detectors.Tests +{ + [TestClass] + [TestCategory("Governance/All")] + [TestCategory("Governance/ComponentDetection")] + public class VcpkgComponentDetectorTests + { + private DetectorTestUtility detectorTestUtility; + + [TestInitialize] + public void TestInitialize() + { + var componentRecorder = new ComponentRecorder(enableManualTrackingOfExplicitReferences: false); + detectorTestUtility = DetectorTestUtilityCreator.Create() + .WithScanRequest(new ScanRequest(new DirectoryInfo(Path.GetTempPath()), null, null, new Dictionary(), null, componentRecorder)); + } + + [TestMethod] + public async Task TestNlohmann() + { + var spdxFile = @"{ + ""SPDXID"": ""SPDXRef - DOCUMENT"", + ""documentNamespace"": + ""https://spdx.org/spdxdocs/nlohmann-json-x64-linux-3.10.4-78c7f190-b402-44d1-a364-b9ac86392b84"", + ""name"": ""nlohmann-json:x64-linux@3.10.4 69dcfc6886529ad2d210f71f132d743672a7e65d2c39f53456f17fc5fc08b278"", + ""packages"": [ + { + ""name"": ""nlohmann-json"", + ""SPDXID"": ""SPDXRef-port"", + ""versionInfo"": ""3.10.4"", + ""downloadLocation"": ""git+https://github.com/Microsoft/vcpkg#ports/nlohmann-json"", + ""homepage"": ""https://github.com/nlohmann/json"", + ""licenseConcluded"": ""NOASSERTION"", + ""licenseDeclared"": ""NOASSERTION"", + ""copyrightText"": ""NOASSERTION"", + ""description"": ""JSON for Modern C++"", + ""comment"": ""This is the port (recipe) consumed by vcpkg."" + } + ] +}"; + var (scanResult, componentRecorder) = await detectorTestUtility + .WithFile("vcpkg.spdx.json", spdxFile) + .ExecuteDetector(); + + Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode); + + var detectedComponents = componentRecorder.GetDetectedComponents(); + var components = detectedComponents.ToList(); + var sbomComponent = (VcpkgComponent)components.FirstOrDefault()?.Component; + + if (sbomComponent is null) + { + throw new AssertFailedException($"{nameof(sbomComponent)} is null"); + } + + Assert.AreEqual(1, components.Count()); + Assert.AreEqual("nlohmann-json", sbomComponent.Name); + Assert.AreEqual("3.10.4", sbomComponent.Version); + Assert.AreEqual("0", sbomComponent.PortVersion); + Assert.AreEqual("SPDXRef-port", sbomComponent.SPDXID); + Assert.AreEqual("git+https://github.com/Microsoft/vcpkg#ports/nlohmann-json", sbomComponent.DownloadLocation); + Assert.AreEqual("pkg:vcpkg/nlohmann-json@3.10.4?port_version=0", sbomComponent.PackageUrl.ToString()); + } + + [TestMethod] + public async Task TestTinyxmlAndResource() + { + var spdxFile = @"{ + ""SPDXID"": ""SPDXRef - DOCUMENT"", + ""documentNamespace"": + ""https://spdx.org/spdxdocs/tinyxml2-x64-linux-9.0.0-c99e4f03-5275-458b-8a69-b5f8dfa45f18"", + ""name"": ""tinyxml2:x64-linux@9.0.0 5c7679507def92c5c71df44aec08a90a5c749f7f805b3f0e8e70f5e8a5b1b8d0"", + ""packages"": [ + { + ""name"": ""tinyxml2:x64-linux"", + ""SPDXID"": ""SPDXRef-binary"", + ""versionInfo"": ""5c7679507def92c5c71df44aec08a90a5c749f7f805b3f0e8e70f5e8a5b1b8d0"", + ""downloadLocation"": ""NONE"", + ""licenseConcluded"": ""NOASSERTION"", + ""licenseDeclared"": ""NOASSERTION"", + ""copyrightText"": ""NOASSERTION"", + ""comment"": ""This is a binary package built by vcpkg."" + }, + { + ""SPDXID"": ""SPDXRef-resource-1"", + ""name"": ""leethomason/tinyxml2"", + ""downloadLocation"": ""git+https://github.com/leethomason/tinyxml2@9.0.0"", + ""licenseConcluded"": ""NOASSERTION"", + ""licenseDeclared"": ""NOASSERTION"", + ""copyrightText"": ""NOASSERTION"", + ""checksums"": [ + { + ""algorithm"": ""SHA512"", + ""checksumValue"": ""9c5ce8131984690df302ca3e32314573b137180ed522c92fd631692979c942372a28f697fdb3d5e56bcf2d3dc596262b724d088153f3e1d721c9536f2a883367"" + } + ] + } + ] +}"; + var (scanResult, componentRecorder) = await detectorTestUtility + .WithFile("vcpkg.spdx.json", spdxFile) + .ExecuteDetector(); + + Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode); + + var detectedComponents = componentRecorder.GetDetectedComponents(); + var components = detectedComponents.ToList(); + + Assert.AreEqual(2, components.Count()); + { + var sbomComponent = (VcpkgComponent)components[0].Component; + Assert.AreEqual("tinyxml2:x64-linux", sbomComponent.Name); + Assert.AreEqual("5c7679507def92c5c71df44aec08a90a5c749f7f805b3f0e8e70f5e8a5b1b8d0", sbomComponent.Version); + Assert.AreEqual("SPDXRef-binary", sbomComponent.SPDXID); + Assert.AreEqual("NONE", sbomComponent.DownloadLocation); + } + + { + var sbomComponent = (VcpkgComponent)components[1].Component; + Assert.AreEqual("leethomason/tinyxml2", sbomComponent.Name); + Assert.AreEqual("9.0.0", sbomComponent.Version); + Assert.AreEqual("SPDXRef-resource-1", sbomComponent.SPDXID); + Assert.AreEqual("git+https://github.com/leethomason/tinyxml2", sbomComponent.DownloadLocation); + } + } + + [TestMethod] + public async Task TestBlankJson() + { + var spdxFile = "{}"; + + var (scanResult, componentRecorder) = await detectorTestUtility + .WithFile("vcpkg.spdx.json", spdxFile) + .ExecuteDetector(); + + Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode); + + var detectedComponents = componentRecorder.GetDetectedComponents(); + var components = detectedComponents.ToList(); + Assert.IsFalse(components.Any()); + } + + [TestMethod] + public async Task TestInvalidFile() + { + var spdxFile = "invalidspdxfile"; + + var (scanResult, componentRecorder) = await detectorTestUtility + .WithFile("vcpkg.spdx.json", spdxFile) + .ExecuteDetector(); + + Assert.AreEqual(ProcessingResultCode.Success, scanResult.ResultCode); + + var detectedComponents = componentRecorder.GetDetectedComponents(); + var components = detectedComponents.ToList(); + Assert.IsFalse(components.Any()); + } + } +} diff --git a/test/Microsoft.ComponentDetection.VerificationTests/resources/vcpkg/nlohmann-json/vcpkg.spdx.json b/test/Microsoft.ComponentDetection.VerificationTests/resources/vcpkg/nlohmann-json/vcpkg.spdx.json new file mode 100644 index 000000000..29bae26a3 --- /dev/null +++ b/test/Microsoft.ComponentDetection.VerificationTests/resources/vcpkg/nlohmann-json/vcpkg.spdx.json @@ -0,0 +1,115 @@ +{ + "$schema": "https://raw.githubusercontent.com/spdx/spdx-spec/v2.2.1/schemas/spdx-schema.json", + "spdxVersion": "SPDX-2.2", + "dataLicense": "CC0-1.0", + "SPDXID": "SPDXRef-DOCUMENT", + "documentNamespace": "https://spdx.org/spdxdocs/nlohmann-json-x64-linux-3.10.4-78c7f190-b402-44d1-a364-b9ac86392b84", + "name": "nlohmann-json:x64-linux@3.10.4 69dcfc6886529ad2d210f71f132d743672a7e65d2c39f53456f17fc5fc08b278", + "creationInfo": { + "creators": [ + "Tool: vcpkg-unknownhash" + ], + "created": "2022-01-18T21:12:48Z" + }, + "relationships": [ + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "GENERATES", + "relatedSpdxElement": "SPDXRef-binary" + }, + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-file-0" + }, + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-file-1" + }, + { + "spdxElementId": "SPDXRef-binary", + "relationshipType": "GENERATED_FROM", + "relatedSpdxElement": "SPDXRef-port" + }, + { + "spdxElementId": "SPDXRef-file-0", + "relationshipType": "CONTAINED_BY", + "relatedSpdxElement": "SPDXRef-port" + }, + { + "spdxElementId": "SPDXRef-file-1", + "relationshipType": "CONTAINED_BY", + "relatedSpdxElement": "SPDXRef-port" + }, + { + "spdxElementId": "SPDXRef-file-1", + "relationshipType": "DEPENDENCY_MANIFEST_OF", + "relatedSpdxElement": "SPDXRef-port" + } + ], + "packages": [ + { + "name": "nlohmann-json", + "SPDXID": "SPDXRef-port", + "versionInfo": "3.10.4", + "downloadLocation": "git+https://github.com/Microsoft/vcpkg#ports/nlohmann-json", + "homepage": "https://github.com/nlohmann/json", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", + "copyrightText": "NOASSERTION", + "description": "JSON for Modern C++", + "comment": "This is the port (recipe) consumed by vcpkg." + }, + { + "name": "nlohmann-json:x64-linux", + "SPDXID": "SPDXRef-binary", + "versionInfo": "69dcfc6886529ad2d210f71f132d743672a7e65d2c39f53456f17fc5fc08b278", + "downloadLocation": "NONE", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", + "copyrightText": "NOASSERTION", + "comment": "This is a binary package built by vcpkg." + }, + { + "SPDXID": "SPDXRef-resource-1", + "name": "nlohmann/json", + "downloadLocation": "git+https://github.com/nlohmann/json@v3.10.4", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", + "copyrightText": "NOASSERTION", + "checksums": [ + { + "algorithm": "SHA512", + "checksumValue": "f78592db6218165cbc74c10bcba40366f1bfea84405b7ee25fe97a056d5b7a15aeeb956d93296673928dcbd6e26ffcfb152f885b4a44d5d55751396ccf090835" + } + ] + } + ], + "files": [ + { + "fileName": "./portfile.cmake", + "SPDXID": "SPDXRef-file-0", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "49b4f9e11cdd0ef697a2750187fa5fa42e7e833dbf411d299ca4d1e9f147773a" + } + ], + "licenseConcluded": "NOASSERTION", + "copyrightText": "NOASSERTION" + }, + { + "fileName": "./vcpkg.json", + "SPDXID": "SPDXRef-file-1", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "b97c75815135eb812a88ee92d50170928d4c69517bfb332e181070cbce2c081b" + } + ], + "licenseConcluded": "NOASSERTION", + "copyrightText": "NOASSERTION" + } + ] +} \ No newline at end of file diff --git a/test/Microsoft.ComponentDetection.VerificationTests/resources/vcpkg/tinyxml2/vcpkg.spdx.json b/test/Microsoft.ComponentDetection.VerificationTests/resources/vcpkg/tinyxml2/vcpkg.spdx.json new file mode 100644 index 000000000..fc97fee5c --- /dev/null +++ b/test/Microsoft.ComponentDetection.VerificationTests/resources/vcpkg/tinyxml2/vcpkg.spdx.json @@ -0,0 +1,123 @@ +{ + "$schema": "https://raw.githubusercontent.com/spdx/spdx-spec/v2.2.1/schemas/spdx-schema.json", + "spdxVersion": "SPDX-2.2", + "dataLicense": "CC0-1.0", + "SPDXID": "SPDXRef-DOCUMENT", + "documentNamespace": "https://spdx.org/spdxdocs/tinyxml2-x64-linux-9.0.0-c99e4f03-5275-458b-8a69-b5f8dfa45f18", + "name": "tinyxml2:x64-linux@9.0.0 5c7679507def92c5c71df44aec08a90a5c749f7f805b3f0e8e70f5e8a5b1b8d0", + "creationInfo": { + "creators": [ + "Tool: vcpkg-unknownhash" + ], + "created": "2022-01-14T00:28:41Z" + }, + "relationships": [ + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "GENERATES", + "relatedSpdxElement": "SPDXRef-binary" + }, + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-file-0" + }, + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-file-1" + }, + { + "spdxElementId": "SPDXRef-binary", + "relationshipType": "GENERATED_FROM", + "relatedSpdxElement": "SPDXRef-port" + }, + { + "spdxElementId": "SPDXRef-file-0", + "relationshipType": "CONTAINED_BY", + "relatedSpdxElement": "SPDXRef-port" + }, + { + "spdxElementId": "SPDXRef-file-1", + "relationshipType": "CONTAINED_BY", + "relatedSpdxElement": "SPDXRef-port" + }, + { + "spdxElementId": "SPDXRef-file-1", + "relationshipType": "DEPENDENCY_MANIFEST_OF", + "relatedSpdxElement": "SPDXRef-port" + } + ], + "packages": [ + { + "name": "tinyxml2", + "SPDXID": "SPDXRef-port", + "versionInfo": "9.0.0", + "downloadLocation": "git+https://github.com/Microsoft/vcpkg#ports/tinyxml2", + "homepage": "https://github.com/leethomason/tinyxml2", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", + "copyrightText": "NOASSERTION", + "description": "A simple, small, efficient, C++ XML parser", + "comment": "This is the port (recipe) consumed by vcpkg.", + "annotations": [ + { + "annotationDate": "2010-01-29T18:30:22Z", + "annotationType": "OTHER", + "annotator": "Tool: vcpkg - 2020-01-01", + "comment": "vcpkgPackageType:port" + } + ] + }, + { + "name": "tinyxml2:x64-linux", + "SPDXID": "SPDXRef-binary", + "versionInfo": "5c7679507def92c5c71df44aec08a90a5c749f7f805b3f0e8e70f5e8a5b1b8d0", + "downloadLocation": "NONE", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", + "copyrightText": "NOASSERTION", + "comment": "This is a binary package built by vcpkg." + }, + { + "SPDXID": "SPDXRef-resource-1", + "name": "leethomason/tinyxml2", + "downloadLocation": "git+https://github.com/leethomason/tinyxml2@9.0.0", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", + "copyrightText": "NOASSERTION", + "checksums": [ + { + "algorithm": "SHA512", + "checksumValue": "9c5ce8131984690df302ca3e32314573b137180ed522c92fd631692979c942372a28f697fdb3d5e56bcf2d3dc596262b724d088153f3e1d721c9536f2a883367" + } + ] + } + ], + "files": [ + { + "fileName": "./portfile.cmake", + "SPDXID": "SPDXRef-file-0", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "dad309c46aea9ccd9a3779723970963b2792d6a7fade26f95437be8ed18ccd60" + } + ], + "licenseConcluded": "NOASSERTION", + "copyrightText": "NOASSERTION" + }, + { + "fileName": "./vcpkg.json", + "SPDXID": "SPDXRef-file-1", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "4f8ddfeb9d3faa3ecf03f22a07678a060e353cde5e2b46be1cbe519993aab841" + } + ], + "licenseConcluded": "NOASSERTION", + "copyrightText": "NOASSERTION" + } + ] +} \ No newline at end of file