Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 29 additions & 5 deletions go/purl/ecosystems_simple.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package purl

import (
"strings"

"github.com/ossf/osv-schema/bindings/go/osvconstants"
"github.com/package-url/packageurl-go"
)
Expand All @@ -16,6 +18,24 @@ func (g simpleGenerator) generate(_, packageName string) (packageurl.PackageURL,
return *packageurl.NewPackageURL(g.purlType, g.namespace, packageName, "", g.qualifiers, ""), nil
}

// slashGenerator handles PURL mappings where the package name contains a slash-separated namespace.
type slashGenerator struct {
purlType string
qualifiers packageurl.Qualifiers
}

func (g slashGenerator) generate(_, packageName string) (packageurl.PackageURL, error) {
namespace := ""
name := packageName
if strings.Contains(packageName, "/") {
parts := strings.Split(packageName, "/")
name = parts[len(parts)-1]
namespace = strings.Join(parts[:len(parts)-1], "/")
}

return *packageurl.NewPackageURL(g.purlType, namespace, name, "", g.qualifiers, ""), nil
}

// simpleParser handles standard PURL mappings without special logic.
type simpleParser struct {
ecosystem osvconstants.Ecosystem
Expand All @@ -36,6 +56,11 @@ func registerSimple(ecosystem osvconstants.Ecosystem, purlType string, namespace
registerParser(purlType, namespace, simpleParser{ecosystem: ecosystem})
}

func registerSlash(ecosystem osvconstants.Ecosystem, purlType string) {
registerGenerator(ecosystem, slashGenerator{purlType: purlType})
registerParser(purlType, "", simpleParser{ecosystem: ecosystem, joinNamespace: true})
}

//nolint:gochecknoinits // init is used here to register simple ecosystems with the global PURL registry.
func init() {
// Language Ecosystems (No namespace)
Expand All @@ -44,18 +69,17 @@ func init() {
registerSimple(osvconstants.EcosystemConanCenter, "conan", "", nil)
registerSimple(osvconstants.EcosystemDockerHardenedImages, "dhi", "", nil)
registerSimple(osvconstants.EcosystemHackage, "hackage", "", nil)
registerSimple(osvconstants.EcosystemHex, "hex", "", nil)
registerSlash(osvconstants.EcosystemHex, "hex")
registerSimple(osvconstants.EcosystemJulia, "julia", "", nil)
registerSimple(osvconstants.EcosystemNuGet, "nuget", "", nil)
registerSimple(osvconstants.EcosystemOSSFuzz, "generic", "", nil)
registerSimple(osvconstants.EcosystemPackagist, "composer", "", nil)
registerSlash(osvconstants.EcosystemPackagist, "composer")
registerSimple(osvconstants.EcosystemPub, "pub", "", nil)
registerSimple(osvconstants.EcosystemPyPI, "pypi", "", nil)
registerSimple(osvconstants.EcosystemRubyGems, "gem", "", nil)
registerSimple(osvconstants.EcosystemSwiftURL, "swift", "", nil)
registerSlash(osvconstants.EcosystemSwiftURL, "swift")
registerSimple(osvconstants.EcosystemCratesIO, "cargo", "", nil)
registerGenerator(osvconstants.EcosystemNPM, simpleGenerator{purlType: "npm"})
registerParser("npm", "", simpleParser{ecosystem: osvconstants.EcosystemNPM, joinNamespace: true})
registerSlash(osvconstants.EcosystemNPM, "npm")
registerSimple(osvconstants.EcosystemOpam, "opam", "", nil)

// OS Ecosystems (With static namespace)
Expand Down
8 changes: 8 additions & 0 deletions go/purl/purl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ func TestGenerate(t *testing.T) {
{"Go", "github.com/gorilla/mux", "pkg:golang/github.com/gorilla/mux", false},
{"Go", "stdlib", "pkg:golang/stdlib", false},
{"Maven", "org.apache.commons:commons-lang3", "pkg:maven/org.apache.commons/commons-lang3", false},
{"Packagist", "drupal/colorbox", "pkg:composer/drupal/colorbox", false},
{"npm", "@babel/core", "pkg:npm/%40babel/core", false},
{"Hex", "acme/foo", "pkg:hex/acme/foo", false},
{"SwiftURL", "github.com/apple/swift-markdown", "pkg:swift/github.com/apple/swift-markdown", false},
// Error cases
{"UnknownEcosystem", "package", "", true},
}
Expand Down Expand Up @@ -58,6 +62,10 @@ func TestParse(t *testing.T) {
{"pkg:golang/stdlib@1.18", "Go", "stdlib", "1.18", false},
{"pkg:maven/org.apache.commons/commons-lang3@3.12.0", "Maven", "org.apache.commons:commons-lang3", "3.12.0", false},
{"pkg:gradle/org.apache.commons/commons-lang3@3.12.0", "Maven", "org.apache.commons:commons-lang3", "3.12.0", false}, // alias
{"pkg:composer/drupal/colorbox@1.2.3", "Packagist", "drupal/colorbox", "1.2.3", false},
{"pkg:npm/%40babel/core@1.2.3", "npm", "@babel/core", "1.2.3", false},
{"pkg:hex/acme/foo@1.2.3", "Hex", "acme/foo", "1.2.3", false},
{"pkg:swift/github.com/apple/swift-markdown@1.2.3", "SwiftURL", "github.com/apple/swift-markdown", "1.2.3", false},
// Error cases
{"invalid-purl", "", "", "", true},
{"pkg:unknown/package@1.0.0", "", "", "", true},
Expand Down
Loading