mirror of
https://github.com/anchore/syft.git
synced 2026-10-30 14:02:26 +01:00
Add package URL support to the CycloneDX presenter (#164)
* add package URL support to the CycloneDX presenter Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * wrap license tags with licenses Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/package-url/packageurl-go"
|
||||
)
|
||||
|
||||
// ApkMetadata represents all captured data for a Alpine DB package entry. See https://wiki.alpinelinux.org/wiki/Apk_spec for more information.
|
||||
type ApkMetadata struct {
|
||||
Package string `mapstructure:"P" json:"package"`
|
||||
OriginPackage string `mapstructure:"o" json:"origin-package"`
|
||||
Maintainer string `mapstructure:"m" json:"maintainer"`
|
||||
Version string `mapstructure:"V" json:"version"`
|
||||
License string `mapstructure:"L" json:"license"`
|
||||
Architecture string `mapstructure:"A" json:"architecture"`
|
||||
URL string `mapstructure:"U" json:"url"`
|
||||
Description string `mapstructure:"T" json:"description"`
|
||||
Size int `mapstructure:"S" json:"size"`
|
||||
InstalledSize int `mapstructure:"I" json:"installed-size"`
|
||||
PullDependencies string `mapstructure:"D" json:"pull-dependencies"`
|
||||
PullChecksum string `mapstructure:"C" json:"pull-checksum"`
|
||||
GitCommitOfAport string `mapstructure:"c" json:"git-commit-of-apk-port"`
|
||||
Files []ApkFileRecord `json:"files"`
|
||||
}
|
||||
|
||||
// ApkFileRecord represents a single file listing and metadata from a APK DB entry (which may have many of these file records).
|
||||
type ApkFileRecord struct {
|
||||
Path string `json:"path"`
|
||||
OwnerUID string `json:"owner-uid"`
|
||||
OwnerGUI string `json:"owner-gid"`
|
||||
Permissions string `json:"permissions"`
|
||||
Checksum string `json:"checksum"`
|
||||
}
|
||||
|
||||
func (m ApkMetadata) PackageURL() string {
|
||||
pURL := packageurl.NewPackageURL(
|
||||
// note: this is currently a candidate and not technically within spec
|
||||
// see https://github.com/package-url/purl-spec#other-candidate-types-to-define
|
||||
"alpine",
|
||||
"",
|
||||
m.Package,
|
||||
m.Version,
|
||||
packageurl.Qualifiers{
|
||||
{
|
||||
Key: "arch",
|
||||
Value: m.Architecture,
|
||||
},
|
||||
},
|
||||
"")
|
||||
return pURL.ToString()
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestApkMetadata_pURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
metadata ApkMetadata
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
metadata: ApkMetadata{
|
||||
Package: "p",
|
||||
Version: "v",
|
||||
Architecture: "a",
|
||||
},
|
||||
expected: "pkg:alpine/p@v?arch=a",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.expected, func(t *testing.T) {
|
||||
actual := test.metadata.PackageURL()
|
||||
if actual != test.expected {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(test.expected, actual, true)
|
||||
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/package-url/packageurl-go"
|
||||
)
|
||||
|
||||
// DpkgMetadata represents all captured data for a Debian package DB entry; available fields are described
|
||||
// at http://manpages.ubuntu.com/manpages/xenial/man1/dpkg-query.1.html in the --showformat section.
|
||||
type DpkgMetadata struct {
|
||||
Package string `mapstructure:"Package" json:"package"`
|
||||
Source string `mapstructure:"Source" json:"source"`
|
||||
Version string `mapstructure:"Version" json:"version"`
|
||||
Architecture string `mapstructure:"Architecture" json:"architecture"`
|
||||
// TODO: consider keeping the remaining values as an embedded map
|
||||
}
|
||||
|
||||
func (m DpkgMetadata) PackageURL(d distro.Distro) string {
|
||||
pURL := packageurl.NewPackageURL(
|
||||
// TODO: replace with `packageurl.TypeDebian` upon merge of https://github.com/package-url/packageurl-go/pull/21
|
||||
"deb",
|
||||
d.Type.String(),
|
||||
m.Package,
|
||||
m.Version,
|
||||
packageurl.Qualifiers{
|
||||
{
|
||||
Key: "arch",
|
||||
Value: m.Architecture,
|
||||
},
|
||||
},
|
||||
"")
|
||||
return pURL.ToString()
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDpkgMetadata_pURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
distro distro.Distro
|
||||
metadata DpkgMetadata
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
distro: distro.Distro{
|
||||
Type: distro.Debian,
|
||||
},
|
||||
metadata: DpkgMetadata{
|
||||
Package: "p",
|
||||
Source: "s",
|
||||
Version: "v",
|
||||
Architecture: "a",
|
||||
},
|
||||
expected: "pkg:deb/debian/p@v?arch=a",
|
||||
},
|
||||
{
|
||||
distro: distro.Distro{
|
||||
Type: distro.Ubuntu,
|
||||
},
|
||||
metadata: DpkgMetadata{
|
||||
Package: "p",
|
||||
Source: "s",
|
||||
Version: "v",
|
||||
Architecture: "a",
|
||||
},
|
||||
expected: "pkg:deb/ubuntu/p@v?arch=a",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.expected, func(t *testing.T) {
|
||||
actual := test.metadata.PackageURL(test.distro)
|
||||
if actual != test.expected {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(test.expected, actual, true)
|
||||
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package pkg
|
||||
|
||||
import "github.com/package-url/packageurl-go"
|
||||
|
||||
// JavaMetadata encapsulates all Java ecosystem metadata for a package as well as an (optional) parent relationship.
|
||||
type JavaMetadata struct {
|
||||
Manifest *JavaManifest `mapstructure:"Manifest" json:"manifest"`
|
||||
PomProperties *PomProperties `mapstructure:"PomProperties" json:"pom-properties"`
|
||||
Parent *Package `json:"parent-package"` // TODO: should this be included in the json output?
|
||||
}
|
||||
|
||||
// PomProperties represents the fields of interest extracted from a Java archive's pom.xml file.
|
||||
type PomProperties struct {
|
||||
Path string
|
||||
Name string `mapstructure:"name" json:"name"`
|
||||
GroupID string `mapstructure:"groupId" json:"group-id"`
|
||||
ArtifactID string `mapstructure:"artifactId" json:"artifact-id"`
|
||||
Version string `mapstructure:"version" json:"version"`
|
||||
Extra map[string]string `mapstructure:",remain" json:"extra-fields"`
|
||||
}
|
||||
|
||||
// JavaManifest represents the fields of interest extracted from a Java archive's META-INF/MANIFEST.MF file.
|
||||
type JavaManifest struct {
|
||||
Name string `mapstructure:"Name" json:"name"`
|
||||
ManifestVersion string `mapstructure:"Manifest-Version" json:"manifest-version"`
|
||||
SpecTitle string `mapstructure:"Specification-Title" json:"specification-title"`
|
||||
SpecVersion string `mapstructure:"Specification-Version" json:"specification-version"`
|
||||
SpecVendor string `mapstructure:"Specification-Vendor" json:"specification-vendor"`
|
||||
ImplTitle string `mapstructure:"Implementation-Title" json:"implementation-title"`
|
||||
ImplVersion string `mapstructure:"Implementation-Version" json:"implementation-version"`
|
||||
ImplVendor string `mapstructure:"Implementation-Vendor" json:"implementation-vendor"`
|
||||
Extra map[string]string `mapstructure:",remain" json:"extra-fields"`
|
||||
}
|
||||
|
||||
func (m JavaMetadata) PackageURL() string {
|
||||
if m.PomProperties != nil {
|
||||
pURL := packageurl.NewPackageURL(
|
||||
packageurl.TypeMaven,
|
||||
m.PomProperties.GroupID,
|
||||
m.PomProperties.ArtifactID,
|
||||
m.PomProperties.Version,
|
||||
nil, // TODO: there are probably several qualifiers that can be specified here
|
||||
"")
|
||||
return pURL.ToString()
|
||||
}
|
||||
|
||||
// TODO: support non-maven artifacts
|
||||
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJavaMetadata_pURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
metadata JavaMetadata
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
metadata: JavaMetadata{
|
||||
PomProperties: &PomProperties{
|
||||
Path: "p",
|
||||
Name: "n",
|
||||
GroupID: "g.id",
|
||||
ArtifactID: "a",
|
||||
Version: "v",
|
||||
},
|
||||
},
|
||||
expected: "pkg:maven/g.id/a@v",
|
||||
},
|
||||
{
|
||||
metadata: JavaMetadata{},
|
||||
expected: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.expected, func(t *testing.T) {
|
||||
actual := test.metadata.PackageURL()
|
||||
if actual != test.expected {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(test.expected, actual, true)
|
||||
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package pkg
|
||||
|
||||
// DpkgMetadata represents all captured data for a Debian package DB entry; available fields are described
|
||||
// at http://manpages.ubuntu.com/manpages/xenial/man1/dpkg-query.1.html in the --showformat section.
|
||||
type DpkgMetadata struct {
|
||||
Package string `mapstructure:"Package" json:"package"`
|
||||
Source string `mapstructure:"Source" json:"source"`
|
||||
Version string `mapstructure:"Version" json:"version"`
|
||||
// TODO: consider keeping the remaining values as an embedded map
|
||||
}
|
||||
|
||||
// RpmMetadata represents all captured data for a RPM DB package entry.
|
||||
type RpmMetadata struct {
|
||||
Version string `mapstructure:"Version" json:"version"`
|
||||
Epoch int `mapstructure:"Epoch" json:"epoch"`
|
||||
Arch string `mapstructure:"Arch" json:"architecture"`
|
||||
Release string `mapstructure:"Release" json:"release"`
|
||||
SourceRpm string `mapstructure:"SourceRpm" json:"source-rpm"`
|
||||
Size int `mapstructure:"Size" json:"size"`
|
||||
License string `mapstructure:"License" json:"license"`
|
||||
Vendor string `mapstructure:"Vendor" json:"vendor"`
|
||||
}
|
||||
|
||||
// JavaManifest represents the fields of interest extracted from a Java archive's META-INF/MANIFEST.MF file.
|
||||
type JavaManifest struct {
|
||||
Name string `mapstructure:"Name" json:"name"`
|
||||
ManifestVersion string `mapstructure:"Manifest-Version" json:"manifest-version"`
|
||||
SpecTitle string `mapstructure:"Specification-Title" json:"specification-title"`
|
||||
SpecVersion string `mapstructure:"Specification-Version" json:"specification-version"`
|
||||
SpecVendor string `mapstructure:"Specification-Vendor" json:"specification-vendor"`
|
||||
ImplTitle string `mapstructure:"Implementation-Title" json:"implementation-title"`
|
||||
ImplVersion string `mapstructure:"Implementation-Version" json:"implementation-version"`
|
||||
ImplVendor string `mapstructure:"Implementation-Vendor" json:"implementation-vendor"`
|
||||
Extra map[string]string `mapstructure:",remain" json:"extra-fields"`
|
||||
}
|
||||
|
||||
// PomProperties represents the fields of interest extracted from a Java archive's pom.xml file.
|
||||
type PomProperties struct {
|
||||
Path string
|
||||
Name string `mapstructure:"name" json:"name"`
|
||||
GroupID string `mapstructure:"groupId" json:"group-id"`
|
||||
ArtifactID string `mapstructure:"artifactId" json:"artifact-id"`
|
||||
Version string `mapstructure:"version" json:"version"`
|
||||
Extra map[string]string `mapstructure:",remain" json:"extra-fields"`
|
||||
}
|
||||
|
||||
// JavaMetadata encapsulates all Java ecosystem metadata for a package as well as an (optional) parent relationship.
|
||||
type JavaMetadata struct {
|
||||
Manifest *JavaManifest `mapstructure:"Manifest" json:"manifest"`
|
||||
PomProperties *PomProperties `mapstructure:"PomProperties" json:"pom-properties"`
|
||||
Parent *Package `json:"parent-package"`
|
||||
}
|
||||
|
||||
// ApkMetadata represents all captured data for a Alpine DB package entry. See https://wiki.alpinelinux.org/wiki/Apk_spec for more information.
|
||||
type ApkMetadata struct {
|
||||
Package string `mapstructure:"P" json:"package"`
|
||||
OriginPackage string `mapstructure:"o" json:"origin-package"`
|
||||
Maintainer string `mapstructure:"m" json:"maintainer"`
|
||||
Version string `mapstructure:"V" json:"version"`
|
||||
License string `mapstructure:"L" json:"license"`
|
||||
Architecture string `mapstructure:"A" json:"architecture"`
|
||||
URL string `mapstructure:"U" json:"url"`
|
||||
Description string `mapstructure:"T" json:"description"`
|
||||
Size int `mapstructure:"S" json:"size"`
|
||||
InstalledSize int `mapstructure:"I" json:"installed-size"`
|
||||
PullDependencies string `mapstructure:"D" json:"pull-dependencies"`
|
||||
PullChecksum string `mapstructure:"C" json:"pull-checksum"`
|
||||
GitCommitOfAport string `mapstructure:"c" json:"git-commit-of-apk-port"`
|
||||
Files []ApkFileRecord `json:"files"`
|
||||
}
|
||||
|
||||
// ApkFileRecord represents a single file listing and metadata from a APK DB entry (which may have many of these file records).
|
||||
type ApkFileRecord struct {
|
||||
Path string `json:"path"`
|
||||
OwnerUID string `json:"owner-uid"`
|
||||
OwnerGUI string `json:"owner-gid"`
|
||||
Permissions string `json:"permissions"`
|
||||
Checksum string `json:"checksum"`
|
||||
}
|
||||
@@ -5,8 +5,12 @@ package pkg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/package-url/packageurl-go"
|
||||
)
|
||||
|
||||
type ID int64
|
||||
@@ -34,3 +38,42 @@ func (p Package) ID() ID {
|
||||
func (p Package) String() string {
|
||||
return fmt.Sprintf("Pkg(type=%s, name=%s, version=%s)", p.Type, p.Name, p.Version)
|
||||
}
|
||||
|
||||
// PackageURL returns a package-URL representation of the given package (see https://github.com/package-url/purl-spec)
|
||||
func (p Package) PackageURL(d distro.Distro) string {
|
||||
// default to pURLs on the metadata
|
||||
if p.Metadata != nil {
|
||||
if i, ok := p.Metadata.(interface{ PackageURL() string }); ok {
|
||||
return i.PackageURL()
|
||||
} else if i, ok := p.Metadata.(interface{ PackageURL(distro.Distro) string }); ok {
|
||||
return i.PackageURL(d)
|
||||
}
|
||||
}
|
||||
|
||||
var purlType = p.Type.PackageURLType()
|
||||
var name = p.Name
|
||||
var namespace = ""
|
||||
|
||||
switch {
|
||||
case purlType == "":
|
||||
// there is no purl type, don't attempt to craft a purl
|
||||
// TODO: should this be a "generic" purl type instead?
|
||||
return ""
|
||||
case p.Type == GoModulePkg:
|
||||
re := regexp.MustCompile(`(\/)[^\/]*$`)
|
||||
fields := re.Split(p.Name, -1)
|
||||
namespace = fields[0]
|
||||
name = strings.TrimPrefix(p.Name, namespace+"/")
|
||||
}
|
||||
|
||||
// generate a purl from the package data
|
||||
pURL := packageurl.NewPackageURL(
|
||||
purlType,
|
||||
namespace,
|
||||
name,
|
||||
p.Version,
|
||||
nil,
|
||||
"")
|
||||
|
||||
return pURL.ToString()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPackage_pURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
pkg Package
|
||||
distro distro.Distro
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
pkg: Package{
|
||||
Name: "github.com/anchore/syft",
|
||||
Version: "v0.1.0",
|
||||
Type: GoModulePkg,
|
||||
},
|
||||
expected: "pkg:golang/github.com/anchore/syft@v0.1.0",
|
||||
},
|
||||
{
|
||||
pkg: Package{
|
||||
Name: "name",
|
||||
Version: "v0.1.0",
|
||||
Type: WheelPkg,
|
||||
},
|
||||
expected: "pkg:pypi/name@v0.1.0",
|
||||
},
|
||||
{
|
||||
pkg: Package{
|
||||
Name: "name",
|
||||
Version: "v0.1.0",
|
||||
Type: EggPkg,
|
||||
},
|
||||
expected: "pkg:pypi/name@v0.1.0",
|
||||
},
|
||||
{
|
||||
pkg: Package{
|
||||
Name: "name",
|
||||
Version: "v0.1.0",
|
||||
Type: PythonSetupPkg,
|
||||
},
|
||||
expected: "pkg:pypi/name@v0.1.0",
|
||||
},
|
||||
{
|
||||
pkg: Package{
|
||||
Name: "name",
|
||||
Version: "v0.1.0",
|
||||
Type: PythonRequirementsPkg,
|
||||
},
|
||||
expected: "pkg:pypi/name@v0.1.0",
|
||||
},
|
||||
{
|
||||
pkg: Package{
|
||||
Name: "name",
|
||||
Version: "v0.1.0",
|
||||
Type: BundlerPkg,
|
||||
},
|
||||
expected: "pkg:gem/name@v0.1.0",
|
||||
},
|
||||
{
|
||||
pkg: Package{
|
||||
Name: "name",
|
||||
Version: "v0.1.0",
|
||||
Type: NpmPkg,
|
||||
},
|
||||
expected: "pkg:npm/name@v0.1.0",
|
||||
},
|
||||
{
|
||||
pkg: Package{
|
||||
Name: "name",
|
||||
Version: "v0.1.0",
|
||||
Type: YarnPkg,
|
||||
},
|
||||
expected: "pkg:npm/name@v0.1.0",
|
||||
},
|
||||
{
|
||||
distro: distro.Distro{
|
||||
Type: distro.Ubuntu,
|
||||
},
|
||||
pkg: Package{
|
||||
Name: "bad-name",
|
||||
Version: "bad-v0.1.0",
|
||||
Type: DebPkg,
|
||||
Metadata: DpkgMetadata{
|
||||
Package: "name",
|
||||
Version: "v0.1.0",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
},
|
||||
expected: "pkg:deb/ubuntu/name@v0.1.0?arch=amd64",
|
||||
},
|
||||
{
|
||||
distro: distro.Distro{
|
||||
Type: distro.CentOS,
|
||||
},
|
||||
pkg: Package{
|
||||
Name: "bad-name",
|
||||
Version: "bad-v0.1.0",
|
||||
Type: RpmPkg,
|
||||
Metadata: RpmMetadata{
|
||||
Name: "name",
|
||||
Version: "v0.1.0",
|
||||
Epoch: 2,
|
||||
Arch: "amd64",
|
||||
Release: "3",
|
||||
},
|
||||
},
|
||||
expected: "pkg:rpm/centos/name@2:v0.1.0-3?arch=amd64",
|
||||
},
|
||||
{
|
||||
distro: distro.Distro{
|
||||
Type: distro.UnknownDistroType,
|
||||
},
|
||||
pkg: Package{
|
||||
Name: "name",
|
||||
Version: "v0.1.0",
|
||||
Type: DebPkg,
|
||||
},
|
||||
expected: "pkg:deb/name@v0.1.0",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(string(test.pkg.Type)+"|"+test.expected, func(t *testing.T) {
|
||||
actual := test.pkg.PackageURL(test.distro)
|
||||
if actual != test.expected {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(test.expected, actual, true)
|
||||
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/package-url/packageurl-go"
|
||||
)
|
||||
|
||||
// RpmMetadata represents all captured data for a RPM DB package entry.
|
||||
type RpmMetadata struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Epoch int `json:"epoch"`
|
||||
Arch string `json:"architecture"`
|
||||
Release string `json:"release"`
|
||||
SourceRpm string `json:"source-rpm"`
|
||||
Size int `json:"size"`
|
||||
License string `json:"license"`
|
||||
Vendor string `json:"vendor"`
|
||||
}
|
||||
|
||||
func (m RpmMetadata) PackageURL(d distro.Distro) string {
|
||||
pURL := packageurl.NewPackageURL(
|
||||
packageurl.TypeRPM,
|
||||
d.Type.String(),
|
||||
m.Name,
|
||||
fmt.Sprintf("%d:%s-%s", m.Epoch, m.Version, m.Release),
|
||||
packageurl.Qualifiers{
|
||||
{
|
||||
Key: "arch",
|
||||
Value: m.Arch,
|
||||
},
|
||||
},
|
||||
"")
|
||||
return pURL.ToString()
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRpmMetadata_pURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
distro distro.Distro
|
||||
metadata RpmMetadata
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
distro: distro.Distro{
|
||||
Type: distro.CentOS,
|
||||
},
|
||||
metadata: RpmMetadata{
|
||||
Name: "p",
|
||||
Version: "v",
|
||||
Arch: "a",
|
||||
Release: "r",
|
||||
Epoch: 1,
|
||||
},
|
||||
expected: "pkg:rpm/centos/p@1:v-r?arch=a",
|
||||
},
|
||||
{
|
||||
distro: distro.Distro{
|
||||
Type: distro.RedHat,
|
||||
},
|
||||
metadata: RpmMetadata{
|
||||
Name: "p",
|
||||
Version: "v",
|
||||
Arch: "a",
|
||||
Release: "r",
|
||||
Epoch: 1,
|
||||
},
|
||||
expected: "pkg:rpm/redhat/p@1:v-r?arch=a",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.expected, func(t *testing.T) {
|
||||
actual := test.metadata.PackageURL(test.distro)
|
||||
if actual != test.expected {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(test.expected, actual, true)
|
||||
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package pkg
|
||||
|
||||
import "github.com/package-url/packageurl-go"
|
||||
|
||||
// Type represents a Package Type for or within a language ecosystem (there may be multiple package types within a language ecosystem)
|
||||
type Type string
|
||||
|
||||
@@ -38,3 +40,27 @@ var AllPkgs = []Type{
|
||||
JenkinsPluginPkg,
|
||||
GoModulePkg,
|
||||
}
|
||||
|
||||
func (t Type) PackageURLType() string {
|
||||
switch t {
|
||||
case ApkPkg:
|
||||
return "alpine"
|
||||
case BundlerPkg:
|
||||
return packageurl.TypeGem
|
||||
case DebPkg:
|
||||
return "deb"
|
||||
case EggPkg, WheelPkg, PythonRequirementsPkg, PythonSetupPkg:
|
||||
return packageurl.TypePyPi
|
||||
case NpmPkg, YarnPkg:
|
||||
return packageurl.TypeNPM
|
||||
case JavaPkg, JenkinsPluginPkg:
|
||||
return packageurl.TypeMaven
|
||||
case RpmPkg:
|
||||
return packageurl.TypeRPM
|
||||
case GoModulePkg:
|
||||
return packageurl.TypeGolang
|
||||
default:
|
||||
// TODO: should this be a "generic" purl type instead?
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user