Skip to content

Conversation

@petergardfjall
Copy link
Contributor

This PR is an attempt to make the code honor the spec rules on producing a canonical purl when a PackageURL is turned into its string representation (ToString() and String()).


The old test suite (test-suite-data.json) is no longer present upstream. For now I updated the Makefile to run against the last commit where test-suite-data.json was still present in the repo (it was removed in 8a699a).

This should be removed as soon as we can migrate to the new test suite (see separate PR).

It fails on the following tests:

  • Two tests with invalid subpaths: we fail to parse these, which used to be correct before all of a sudden is_invalid for these cases was swapped from true to false in this commit without much of an explanation. These test cases appear to have been removed from the new test set though.

For the new test suite (a pull request to make use of it is up here) it currently fails on 45 and passes on 468 test cases. For the failed ones:

  • For two test cases for pkg:conan I cannot figure out why we are failing. I've opened a ticket since I suspect that the test cases might be incorrect purl-spec#643.
  • Of the remaining errors almost all are ones where the expected output in the test case is not a canonical purl/does not follow purl encoding guidelines. I've opened purl-spec#644 to better understand what's expected from library implementations.

Makefile Outdated

test:
curl -Ls https://raw.githubusercontent.com/package-url/purl-spec/master/test-suite-data.json -o testdata/test-suite-data.json
curl -Ls https://raw.githubusercontent.com/package-url/purl-spec/de752b1160c7dc309482aaa80fd31884005aaec5/test-suite-data.json -o testdata/test-suite-data.json
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be entirely replaced if/when #80 is merged.

@coveralls
Copy link

Pull Request Test Coverage Report for Build 17266694404

Details

  • 35 of 36 (97.22%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+3.6%) to 85.761%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packageurl.go 35 36 97.22%
Totals Coverage Status
Change from base Build 13610888770: 3.6%
Covered Lines: 265
Relevant Lines: 309

💛 - Coveralls

for _, qq := range q {
v.Add(qq.Key, qq.Value)
}
return v.Encode()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot use Values.Encode() since it uses https://pkg.go.dev/net/url#QueryEscape under the hood to encode the value. This works in many cases but has caveats (does not work according to spec for whitespace and colon :).

u := &url.URL{
Scheme: "pkg",
RawQuery: p.Qualifiers.urlQuery(),
Fragment: p.Subpath,
Copy link
Contributor Author

@petergardfjall petergardfjall Aug 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: we cannot use url.Fragment since url.String will call u.EscapedFragment() and we end up with an incorrect escaping (similar to url.QueryEscape I believe).

Instead we "manually" add any fragment part at the end.

packageurl.go Outdated
Comment on lines 661 to 668
qualifierKeys := slices.Collect(maps.Keys(p.Qualifiers.Map()))
hasNamespace := p.Namespace != ""
hasChannel := slices.Contains(qualifierKeys, "channel")
if hasNamespace && !hasChannel {
return errors.New("channel qualifier is required if namespace is present")
}
if hasChannel && !hasNamespace {
return errors.New("namespace is required if channel qualifier is present")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An attempt to make the code more readable.

import "testing"

// Verifies that qualifier values are properly percent-encoded.
func TestQualifierValueEncoding(t *testing.T) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some explicit testing of qualifier encoding (outside of purl-spec test suite) since this was a problematic spot which had poor coverage in the upstream tests.

@petergardfjall
Copy link
Contributor Author

@shibumi @mcombuechen ?
Would anyone care to have a look?

@petergardfjall
Copy link
Contributor Author

Barring some outstanding issues with the purl spec test suite (see below) this code now passes the entire purl-spec suite. We should first merge #80 which changes the code to run against the new test suite in the purl-spec repo. When that is merged we can merge this PR.

Until these issues/PRs are fixed the code in this PR will fail to complete the entire test suite (it will fail on about 10 out of 500).


test:
curl -Ls https://raw.githubusercontent.com/package-url/purl-spec/master/test-suite-data.json -o testdata/test-suite-data.json
go test -v -cover ./...
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: relies on #80 being merged.

func validCustomRules(p PackageURL) error {
q := p.Qualifiers.Map()
switch p.Type {
case TypeConan:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conan spec has been relaxed.

return errors.New("channel qualifier does not exist")
}
} else {
if val, ok := q["channel"]; ok {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conan spec has been relaxed.

if p.Version == "" {
return errors.New("version is required")
}
case TypeCran:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -1,572 +0,0 @@
/*
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file should be replaced with packageurl_test.go from #80

@petergardfjall
Copy link
Contributor Author

Anyone up for reviewing?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants