diff --git a/Directory.Packages.props b/Directory.Packages.props index f0565ac4f..dd8034204 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -27,7 +27,7 @@ - + diff --git a/docs/creating-a-new-detector.md b/docs/creating-a-new-detector.md index 0dfdd6d77..eafe08413 100644 --- a/docs/creating-a-new-detector.md +++ b/docs/creating-a-new-detector.md @@ -104,7 +104,7 @@ public class YourEcosystemComponent : TypedComponent public string Version { get; set; } public override ComponentType Type => ComponentType.YourType; - public override PackageUrl PackageUrl => new PackageUrl("your-type", null, this.Name, this.Version, null, null); + public override PackageURL PackageUrl => new PackageURL("your-type", null, this.Name, this.Version, null, null); protected override string ComputeId() => $"{this.Name} {this.Version} - {this.Type}"; } ``` diff --git a/docs/schema/manifest.schema.json b/docs/schema/manifest.schema.json index 0db3bdc7d..1680dd0cc 100644 --- a/docs/schema/manifest.schema.json +++ b/docs/schema/manifest.schema.json @@ -547,4 +547,4 @@ "resultCode", "sourceDirectory" ] -} +} \ No newline at end of file diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/CargoComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/CargoComponent.cs index d981fe239..324596bc7 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/CargoComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/CargoComponent.cs @@ -44,7 +44,7 @@ public CargoComponent(string name, string version, string author = null, string public override ComponentType Type => ComponentType.Cargo; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl => new PackageUrl("cargo", string.Empty, this.Name, this.Version, null, string.Empty); + public override PackageURL PackageUrl => new PackageURL("cargo", string.Empty, this.Name, this.Version, null, string.Empty); protected override string ComputeBaseId() => $"{this.Name} {this.Version} - {this.Type}"; } diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ConanComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ConanComponent.cs index 4a449e03a..b1101d6fc 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ConanComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/ConanComponent.cs @@ -38,7 +38,7 @@ public ConanComponent(string name, string version, string previous, string packa public override ComponentType Type => ComponentType.Conan; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl => new PackageUrl("conan", string.Empty, this.Name, this.Version, null, string.Empty); + public override PackageURL PackageUrl => new PackageURL("conan", string.Empty, this.Name, this.Version, null, string.Empty); protected override string ComputeBaseId() => $"{this.Name} {this.Version} - {this.Type}"; } diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/CppSdkComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/CppSdkComponent.cs index af4b2ab0e..70afd99de 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/CppSdkComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/CppSdkComponent.cs @@ -39,7 +39,7 @@ public CppSdkComponent(string name, string version) public override ComponentType Type => ComponentType.CppSdk; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl + public override PackageURL PackageUrl { get { @@ -47,7 +47,7 @@ public override PackageUrl PackageUrl { { "type", "cppsdk" }, }; - return new PackageUrl("generic", null, this.Name, this.Version, qualifiers, null); + return new PackageURL("generic", null, this.Name, this.Version, qualifiers, null); } } diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/GoComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/GoComponent.cs index 3a096dd98..57161336a 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/GoComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/GoComponent.cs @@ -37,34 +37,14 @@ public GoComponent() // Commit should be used in place of version when available // https://github.com/package-url/purl-spec/blame/180c46d266c45aa2bd81a2038af3f78e87bb4a25/README.rst#L610 - // The golang purl spec requires a namespace: https://github.com/package-url/purl-spec/blob/master/types/golang-definition.json [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl - { - get - { - var version = string.IsNullOrWhiteSpace(this.Hash) ? this.Version : this.Hash; - var (ns, name) = this.GetNamespaceAndName(); - return new PackageUrl("golang", ns, name, version, null, null); - } - } + public override PackageURL PackageUrl => new PackageURL("golang", null, this.Name, string.IsNullOrWhiteSpace(this.Hash) ? this.Version : this.Hash, null, null); [JsonIgnore] public override ComponentType Type => ComponentType.Go; protected override string ComputeBaseId() => $"{this.Name} {this.Version} - {this.Type}"; - private (string Namespace, string Name) GetNamespaceAndName() - { - var lastSlash = this.Name.LastIndexOf('/'); - if (lastSlash > 0) - { - return (this.Name.Substring(0, lastSlash), this.Name.Substring(lastSlash + 1)); - } - - return (null, this.Name); - } - public override bool Equals(object obj) { return obj is GoComponent otherComponent && this.Equals(otherComponent); diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/LinuxComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/LinuxComponent.cs index f95501ec2..c1ede70a6 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/LinuxComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/LinuxComponent.cs @@ -46,7 +46,7 @@ public LinuxComponent(string distribution, string release, string name, string v public override ComponentType Type => ComponentType.Linux; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl + public override PackageURL PackageUrl { get { @@ -63,7 +63,7 @@ public override PackageUrl PackageUrl if (packageType != null) { - return new PackageUrl(packageType, this.Distribution, this.Name, this.Version, null, null); + return new PackageURL(packageType, this.Distribution, this.Name, this.Version, null, null); } return null; diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/MavenComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/MavenComponent.cs index dd4d50d76..034a156ea 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/MavenComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/MavenComponent.cs @@ -31,7 +31,7 @@ public MavenComponent() public override ComponentType Type => ComponentType.Maven; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl => new PackageUrl("maven", this.GroupId, this.ArtifactId, this.Version, null, null); + public override PackageURL PackageUrl => new PackageURL("maven", this.GroupId, this.ArtifactId, this.Version, null, null); protected override string ComputeBaseId() => $"{this.GroupId} {this.ArtifactId} {this.Version} - {this.Type}"; } diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/NpmComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/NpmComponent.cs index 675877002..33599a5fb 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/NpmComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/NpmComponent.cs @@ -36,7 +36,7 @@ public NpmComponent(string name, string version, string hash = null, NpmAuthor a public override ComponentType Type => ComponentType.Npm; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl => new PackageUrl("npm", null, this.Name, this.Version, null, null); + public override PackageURL PackageUrl => new PackageURL("npm", null, this.Name, this.Version, null, null); protected override string ComputeBaseId() => $"{this.Name} {this.Version} - {this.Type}"; } diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/NugetComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/NugetComponent.cs index 7761bb2a3..d2c5e461c 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/NugetComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/NugetComponent.cs @@ -31,7 +31,7 @@ public NuGetComponent(string name, string version, string[] authors = null) public override ComponentType Type => ComponentType.NuGet; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl => new PackageUrl("nuget", null, this.Name, this.Version, null, null); + public override PackageURL PackageUrl => new PackageURL("nuget", null, this.Name, this.Version, null, null); protected override string ComputeBaseId() => $"{this.Name} {this.Version} - {this.Type}"; } diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/PipComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/PipComponent.cs index fa5bd6d44..36bb04a4c 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/PipComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/PipComponent.cs @@ -40,7 +40,7 @@ public PipComponent(string name, string version, string author = null, string li public override ComponentType Type => ComponentType.Pip; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl => new PackageUrl("pypi", null, this.Name, this.Version, null, null); + public override PackageURL PackageUrl => new PackageURL("pypi", null, this.Name, this.Version, null, null); [SuppressMessage("Usage", "CA1308:Normalize String to Uppercase", Justification = "Casing cannot be overwritten.")] protected override string ComputeBaseId() => $"{this.Name} {this.Version} - {this.Type}".ToLowerInvariant(); diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/PodComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/PodComponent.cs index dc62095a7..9d7442cf9 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/PodComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/PodComponent.cs @@ -32,7 +32,7 @@ public PodComponent(string name, string version, string specRepo = "") public override ComponentType Type => ComponentType.Pod; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl + public override PackageURL PackageUrl { get { @@ -42,7 +42,7 @@ public override PackageUrl PackageUrl qualifiers.Add("repository_url", this.SpecRepo); } - return new PackageUrl("cocoapods", null, this.Name, this.Version, qualifiers, null); + return new PackageURL("cocoapods", null, this.Name, this.Version, qualifiers, null); } } diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/RubyGemsComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/RubyGemsComponent.cs index cee2b76dc..11469eb67 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/RubyGemsComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/RubyGemsComponent.cs @@ -31,7 +31,7 @@ public RubyGemsComponent(string name, string version, string source = "") public override ComponentType Type => ComponentType.RubyGems; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl => new PackageUrl("gem", null, this.Name, this.Version, null, null); + public override PackageURL PackageUrl => new PackageURL("gem", null, this.Name, this.Version, null, null); protected override string ComputeBaseId() => $"{this.Name} {this.Version} - {this.Type}"; } diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/SwiftComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/SwiftComponent.cs index 830e86d88..1140c31d6 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/SwiftComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/SwiftComponent.cs @@ -40,12 +40,12 @@ public SwiftComponent(string name, string version, string packageUrl, string has [JsonIgnore] public override ComponentType Type => ComponentType.Swift; - // Example PackageUrl -> pkg:swift/github.com/apple/swift-asn1 + // Example PackageURL -> pkg:swift/github.com/apple/swift-asn1 // type: swift // namespace: github.com/apple // name: swift-asn1 [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl => new PackageUrl( + public override PackageURL PackageUrl => new PackageURL( type: "swift", @namespace: this.GetNamespaceFromPackageUrl(), name: this.Name, diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/TypedComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/TypedComponent.cs index 95a62f541..22be7eb61 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/TypedComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/TypedComponent.cs @@ -61,7 +61,7 @@ internal TypedComponent() public string BaseId => this.baseId ??= this.ComputeBaseId(); [SystemTextJson.JsonPropertyName("packageUrl")] - public virtual PackageUrl PackageUrl { get; } + public virtual PackageURL PackageUrl { get; } /// Gets or sets SPDX license expression(s) declared by the package author. [JsonProperty("licenses", NullValueHandling = NullValueHandling.Ignore)] diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/VcpkgComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/VcpkgComponent.cs index ae70a95c9..bb3668234 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/VcpkgComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/VcpkgComponent.cs @@ -49,21 +49,21 @@ public VcpkgComponent(string spdxid, string name, string version, string triplet public override ComponentType Type => ComponentType.Vcpkg; [JsonPropertyName("packageUrl")] - public override PackageUrl PackageUrl + public override PackageURL PackageUrl { get { if (this.PortVersion > 0) { - return new PackageUrl($"pkg:vcpkg/{this.Name}@{this.Version}?port_version={this.PortVersion}"); + return new PackageURL($"pkg:vcpkg/{this.Name}@{this.Version}?port_version={this.PortVersion}"); } else if (this.Version != null) { - return new PackageUrl($"pkg:vcpkg/{this.Name}@{this.Version}"); + return new PackageURL($"pkg:vcpkg/{this.Name}@{this.Version}"); } else { - return new PackageUrl($"pkg:vcpkg/{this.Name}"); + return new PackageURL($"pkg:vcpkg/{this.Name}"); } } } diff --git a/test/Microsoft.ComponentDetection.Contracts.Tests/CppSdkComponentTests.cs b/test/Microsoft.ComponentDetection.Contracts.Tests/CppSdkComponentTests.cs index bd9877270..40ba034bf 100644 --- a/test/Microsoft.ComponentDetection.Contracts.Tests/CppSdkComponentTests.cs +++ b/test/Microsoft.ComponentDetection.Contracts.Tests/CppSdkComponentTests.cs @@ -77,7 +77,9 @@ public void PackageUrl_ShouldReturnCorrectFormat() var packageUrl = component.PackageUrl; packageUrl.Type.Should().Be("generic"); - packageUrl.Name.Should().Be(name); +#pragma warning disable CA1308 // PackageURL normalizes to lowercase + packageUrl.Name.Should().Be(name.ToLowerInvariant()); +#pragma warning restore CA1308 packageUrl.Version.Should().Be(version); packageUrl.Namespace.Should().BeNull(); packageUrl.Qualifiers.Should().ContainKey("type"); diff --git a/test/Microsoft.ComponentDetection.Contracts.Tests/PurlGenerationTests.cs b/test/Microsoft.ComponentDetection.Contracts.Tests/PurlGenerationTests.cs index 18b9f99c4..305400e47 100644 --- a/test/Microsoft.ComponentDetection.Contracts.Tests/PurlGenerationTests.cs +++ b/test/Microsoft.ComponentDetection.Contracts.Tests/PurlGenerationTests.cs @@ -24,7 +24,7 @@ public void GoPackageShouldPreferHashOverVersion() { // Commit should be used in place of version when available // https://github.com/package-url/purl-spec/blame/180c46d266c45aa2bd81a2038af3f78e87bb4a25/README.rst#L610 - var goComponent = new GoComponent("github.com/example/test", "1.2.3", "deadbeef"); + var goComponent = new GoComponent("test", "1.2.3", "deadbeef"); goComponent.PackageUrl.Version.Should().Be("deadbeef"); } @@ -97,9 +97,9 @@ public void CocoaPodNameShouldSupportPurl() var packageThree = new PodComponent("googleUtilities", "7.5.2"); packageOne.PackageUrl.Type.Should().Be("cocoapods"); - packageOne.PackageUrl.ToString().Should().Be("pkg:cocoapods/AFNetworking@4.0.1"); - packageTwo.PackageUrl.ToString().Should().Be("pkg:cocoapods/MapsIndoors@3.24.0"); - packageThree.PackageUrl.ToString().Should().Be("pkg:cocoapods/googleUtilities@7.5.2"); + packageOne.PackageUrl.ToString().Should().Be("pkg:cocoapods/afnetworking@4.0.1"); + packageTwo.PackageUrl.ToString().Should().Be("pkg:cocoapods/mapsindoors@3.24.0"); + packageThree.PackageUrl.ToString().Should().Be("pkg:cocoapods/googleutilities@7.5.2"); } [TestMethod] @@ -108,6 +108,6 @@ public void CocoaPodNameShouldPurlWithCustomQualifier() // https://github.com/package-url/purl-spec/blob/b8ddd39a6d533b8895f3b741f2e62e2695d82aa4/PURL-TYPES.rst#cocoapods var packageOne = new PodComponent("AFNetworking", "4.0.1", "https://custom_repo.example.com/path/to/repo/specs.git"); - packageOne.PackageUrl.ToString().Should().Be("pkg:cocoapods/AFNetworking@4.0.1?repository_url=https:%2F%2Fcustom_repo.example.com%2Fpath%2Fto%2Frepo%2Fspecs.git"); + packageOne.PackageUrl.ToString().Should().Be("pkg:cocoapods/afnetworking@4.0.1?repository_url=https://custom_repo.example.com/path/to/repo/specs.git"); } } diff --git a/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs b/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs index 57342f7e7..366551ebb 100644 --- a/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs +++ b/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs @@ -162,12 +162,12 @@ public void TypedComponent_Serialization_Pip() [TestMethod] public void TypedComponent_Serialization_Go() { - TypedComponent tc = new GoComponent("github.com/example/SomeGoPackage", "1.2.3", "SomeHash"); + TypedComponent tc = new GoComponent("SomeGoPackage", "1.2.3", "SomeHash"); var result = JsonSerializer.Serialize(tc); var deserializedTC = JsonSerializer.Deserialize(result); deserializedTC.Should().BeOfType(typeof(GoComponent)); var goComponent = (GoComponent)deserializedTC; - goComponent.Name.Should().Be("github.com/example/SomeGoPackage"); + goComponent.Name.Should().Be("SomeGoPackage"); goComponent.Version.Should().Be("1.2.3"); goComponent.Hash.Should().Be("SomeHash"); } @@ -305,7 +305,7 @@ public void TypedComponent_Serialization_AllComponentTypes_TypePropertyNotDuplic new NuGetComponent("test", "1.0.0"), new MavenComponent("group", "artifact", "1.0.0"), new PipComponent("test", "1.0.0"), - new GoComponent("github.com/example/test", "1.0.0"), + new GoComponent("test", "1.0.0"), new CargoComponent("test", "1.0.0"), new RubyGemsComponent("test", "1.0.0"), new GitComponent(new Uri("https://github.com/test/test"), "abc123"), diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/SwiftComponentTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/SwiftComponentTests.cs index a015bebaa..78165e6e9 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/SwiftComponentTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/SwiftComponentTests.cs @@ -102,7 +102,7 @@ public void PackageURL_ShouldReturnCorrectPackageURL_GithubHostname() var component = new SwiftComponent(name, version, packageUrl, hash); - var expectedPackageURL = new PackageUrl( + var expectedPackageURL = new PackageURL( type: "swift", @namespace: "github.com/Alamofire", name: name, @@ -124,7 +124,7 @@ public void PackageURL_ShouldReturnCorrectPackageURL_GithubHostname_Alternate() var component = new SwiftComponent(name, version, packageUrl, hash); - var expectedPackageURL = new PackageUrl( + var expectedPackageURL = new PackageURL( type: "swift", @namespace: "github.com/Alamofire", name: name, @@ -149,7 +149,7 @@ public void PackageURL_ShouldReturnCorrectPackageURL_OtherHostname() var component = new SwiftComponent(name, version, packageUrl, hash); - var expectedPackageURL = new PackageUrl( + var expectedPackageURL = new PackageURL( type: "swift", @namespace: "otherhostname.com", name: name,