diff --git a/Directory.Packages.props b/Directory.Packages.props
index dd8034204..f0565ac4f 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 eafe08413..0dfdd6d77 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 1680dd0cc..0db3bdc7d 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 324596bc7..d981fe239 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 b1101d6fc..4a449e03a 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 70afd99de..af4b2ab0e 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 57161336a..3a096dd98 100644
--- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/GoComponent.cs
+++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/GoComponent.cs
@@ -37,14 +37,34 @@ 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 => new PackageURL("golang", null, this.Name, string.IsNullOrWhiteSpace(this.Hash) ? this.Version : this.Hash, null, null);
+ 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);
+ }
+ }
[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 c1ede70a6..f95501ec2 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 034a156ea..dd4d50d76 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 33599a5fb..675877002 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 d2c5e461c..7761bb2a3 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 36bb04a4c..fa5bd6d44 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 9d7442cf9..dc62095a7 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 11469eb67..cee2b76dc 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 1140c31d6..830e86d88 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 22be7eb61..95a62f541 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 bb3668234..ae70a95c9 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 40ba034bf..bd9877270 100644
--- a/test/Microsoft.ComponentDetection.Contracts.Tests/CppSdkComponentTests.cs
+++ b/test/Microsoft.ComponentDetection.Contracts.Tests/CppSdkComponentTests.cs
@@ -77,9 +77,7 @@ public void PackageUrl_ShouldReturnCorrectFormat()
var packageUrl = component.PackageUrl;
packageUrl.Type.Should().Be("generic");
-#pragma warning disable CA1308 // PackageURL normalizes to lowercase
- packageUrl.Name.Should().Be(name.ToLowerInvariant());
-#pragma warning restore CA1308
+ packageUrl.Name.Should().Be(name);
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 305400e47..18b9f99c4 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("test", "1.2.3", "deadbeef");
+ var goComponent = new GoComponent("github.com/example/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://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");
}
}
diff --git a/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs b/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs
index 366551ebb..57342f7e7 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("SomeGoPackage", "1.2.3", "SomeHash");
+ TypedComponent tc = new GoComponent("github.com/example/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("SomeGoPackage");
+ goComponent.Name.Should().Be("github.com/example/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("test", "1.0.0"),
+ new GoComponent("github.com/example/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 78165e6e9..a015bebaa 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,