Bump packageurl-dotnet from 2.0.0-rc.2 to 2.0.0-rc.3#1738
Bump packageurl-dotnet from 2.0.0-rc.2 to 2.0.0-rc.3#1738JamieMagee wants to merge 1 commit intomainfrom
Conversation
LinuxComponent.PackageUrl was missing the distro release -- so pkg:deb/ubuntu/bash@1 on 18.04 and 20.04 produced identical purls even though ComputeBaseId distinguished them. Now emits a distro qualifier (e.g., distro=ubuntu-20.04) to match what Syft produces. Also adds apk as a purl type for Alpine, and maps Red Hat Enterprise Linux to the short id edhat for both namespace and qualifier. Fixes #1714
There was a problem hiding this comment.
Pull request overview
This PR updates Linux PackageUrl generation to better distinguish packages across distro releases and to emit purls for Alpine packages, aligning output more closely with purl-spec/Syft conventions.
Changes:
- Add
distro=<id>-<release>qualifier to Linux purls (deb/rpm/apk) to prevent cross-distro-release overmatching. - Emit
apkpurls for Alpine Linux packages (previously returned null). - Extend/adjust unit tests to validate new Linux purl behavior, including RHEL namespace expectations.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/Microsoft.ComponentDetection.Contracts/TypedComponent/LinuxComponent.cs |
Adds distro qualifier, introduces Alpine apk purls, and RHEL→redhat namespace/qualifier mapping logic. |
test/Microsoft.ComponentDetection.Contracts.Tests/PurlGenerationTests.cs |
Updates and expands tests to assert distro qualifier presence and Alpine/RHEL purl behavior. |
Comments suppressed due to low confidence (1)
src/Microsoft.ComponentDetection.Contracts/TypedComponent/LinuxComponent.cs:123
IsRHEL()only matches the literal string "Red Hat Enterprise Linux", but the Linux detector constructsLinuxComponentusingdistro.Id(e.g., "ubuntu", "mariner"). Unlessdistro.Idis exactly that long name, RHEL packages will not be classified as RPM and will continue to produce a nullPackageUrl. Consider recognizing the expected distro id(s) (e.g., "rhel") and mapping them to the canonical "redhat" id used for the namespace/qualifier.
private bool IsRHEL()
{
return this.Distribution.Equals("RED HAT ENTERPRISE LINUX", StringComparison.OrdinalIgnoreCase);
}
private bool IsAlpine()
{
return this.Distribution.Equals("ALPINE", StringComparison.OrdinalIgnoreCase);
}
private string GetDistroId()
{
if (this.IsRHEL())
{
return "redhat";
}
return this.Distribution.ToLowerInvariant();
| [TestMethod] | ||
| public void RhelNamespaceIsRedhat() | ||
| { | ||
| // RHEL should use "redhat" as the namespace and distro id, matching Syft conventions | ||
| var rhelComponent = new LinuxComponent("Red Hat Enterprise Linux", "9.0", "bash", "1"); | ||
|
|
||
| rhelComponent.PackageUrl.Namespace.Should().Be("redhat"); | ||
| rhelComponent.PackageUrl.Qualifiers["distro"].Should().Be("redhat-9.0"); | ||
| } |
There was a problem hiding this comment.
The new RhelNamespaceIsRedhat test uses distribution: "Red Hat Enterprise Linux", but production code creates LinuxComponent from distro.Id (short ids like "ubuntu"/"mariner"). To ensure this behavior is actually covered, add/adjust a test case that uses the distro id value you expect from Syft (e.g., "rhel") and asserts the namespace/distro qualifier mapping.
| if (packageType != null) | ||
| { | ||
| return new PackageUrl(packageType, this.Distribution, this.Name, this.Version, null, null); | ||
| var distroId = this.GetDistroId(); | ||
| var qualifiers = new SortedDictionary<string, string> | ||
| { | ||
| { "distro", $"{distroId}-{this.Release}" }, | ||
| }; | ||
|
|
||
| return new PackageUrl(packageType, distroId, this.Name, this.Version, qualifiers, null); |
There was a problem hiding this comment.
PR title/description says packageurl-dotnet is bumped to 2.0.0-rc.3, but Directory.Packages.props in this change set still pins packageurl-dotnet to 2.0.0-rc.2. Either update the central package version to rc.3 or adjust the PR metadata to match what’s actually changing.
This issue also appears on line 106 of the same file.
LinuxComponent purls now include a
distroqualifier with the release version, and Alpine packages getapkpurls instead of null.Why
The purl for
pkg:deb/ubuntu/bash@1was the same whether the package came from Ubuntu 18.04 or 20.04.ComputeBaseId()already distinguished them, but the purl didn't, so anything downstream that relied on the purl for deduplication or resolution would over-match across distro versions.The purl spec includes a
distroqualifier for exactly this reason, and Syft already emits it (e.g.,distro=ubuntu-20.04). We just weren't passing it through.While I was in here, I also noticed Alpine was returning null even though
apkhas been a registered purl type for a while now.Changes
distro=<id>-<release>qualifier on all Linux purlsredhatfor namespace and qualifier (matches Syft)apktype for AlpineAlpineAndUnknownDoNotHavePurlstest since Alpine does have purls nowRhelNamespaceIsRedhattestExample before:
pkg:deb/ubuntu/bash@1Example after:
pkg:deb/ubuntu/bash@1?distro=ubuntu-18.04Fixes #1714