feat(vex): add PURL matching for CSAF VEX (#5890)

Signed-off-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
Teppei Fukuda
2024-01-10 10:37:19 +04:00
committed by GitHub
parent 958e1f11f7
commit d0c81e23c4
29 changed files with 1237 additions and 1391 deletions

View File

@@ -22,7 +22,7 @@
}, },
{ {
"name": "openssl", "name": "openssl",
"SPDXID": "SPDXRef-Package-38e5db7a21fc70a8", "SPDXID": "SPDXRef-Package-20b95c21bfbf9fc4",
"versionInfo": "1.1.1q", "versionInfo": "1.1.1q",
"supplier": "NOASSERTION", "supplier": "NOASSERTION",
"downloadLocation": "NONE", "downloadLocation": "NONE",
@@ -43,7 +43,7 @@
}, },
{ {
"name": "pip", "name": "pip",
"SPDXID": "SPDXRef-Package-f9844c873ead5dbe", "SPDXID": "SPDXRef-Package-11a429ec3bd01d80",
"versionInfo": "22.2.2", "versionInfo": "22.2.2",
"supplier": "NOASSERTION", "supplier": "NOASSERTION",
"downloadLocation": "NONE", "downloadLocation": "NONE",
@@ -110,21 +110,21 @@
}, },
{ {
"spdxElementId": "SPDXRef-Application-ee5ef1aa4ac89125", "spdxElementId": "SPDXRef-Application-ee5ef1aa4ac89125",
"relatedSpdxElement": "SPDXRef-Package-38e5db7a21fc70a8", "relatedSpdxElement": "SPDXRef-Package-20b95c21bfbf9fc4",
"relationshipType": "CONTAINS" "relationshipType": "CONTAINS"
}, },
{ {
"spdxElementId": "SPDXRef-Package-38e5db7a21fc70a8", "spdxElementId": "SPDXRef-Package-20b95c21bfbf9fc4",
"relatedSpdxElement": "SPDXRef-File-600e5e0110a84891", "relatedSpdxElement": "SPDXRef-File-600e5e0110a84891",
"relationshipType": "CONTAINS" "relationshipType": "CONTAINS"
}, },
{ {
"spdxElementId": "SPDXRef-Application-ee5ef1aa4ac89125", "spdxElementId": "SPDXRef-Application-ee5ef1aa4ac89125",
"relatedSpdxElement": "SPDXRef-Package-f9844c873ead5dbe", "relatedSpdxElement": "SPDXRef-Package-11a429ec3bd01d80",
"relationshipType": "CONTAINS" "relationshipType": "CONTAINS"
}, },
{ {
"spdxElementId": "SPDXRef-Package-f9844c873ead5dbe", "spdxElementId": "SPDXRef-Package-11a429ec3bd01d80",
"relatedSpdxElement": "SPDXRef-File-7eb62e2a3edddc0a", "relatedSpdxElement": "SPDXRef-File-7eb62e2a3edddc0a",
"relationshipType": "CONTAINS" "relationshipType": "CONTAINS"
} }

View File

@@ -88,9 +88,6 @@ func handleBitnamiImages(componentPath string, bom types.SBOM) {
// If the file path is empty, the file path will be set to the component dir path. // If the file path is empty, the file path will be set to the component dir path.
filePath := path.Join(componentPath, pkg.FilePath) filePath := path.Join(componentPath, pkg.FilePath)
bom.Applications[i].Libraries[j].FilePath = filePath bom.Applications[i].Libraries[j].FilePath = filePath
if pkg.Identifier.PURL != nil && pkg.Identifier.PURL.FilePath != "" {
bom.Applications[i].Libraries[j].Identifier.PURL.FilePath = filePath
}
} }
} }
} }

View File

@@ -35,13 +35,11 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Version: "1.36.0", Version: "1.36.0",
FilePath: "opt/bitnami/elasticsearch", FilePath: "opt/bitnami/elasticsearch",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "co.elastic.apm",
Namespace: "co.elastic.apm", Name: "apm-agent",
Name: "apm-agent", Version: "1.36.0",
Version: "1.36.0",
},
}, },
}, },
}, },
@@ -50,13 +48,11 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Version: "1.36.0", Version: "1.36.0",
FilePath: "opt/bitnami/elasticsearch", FilePath: "opt/bitnami/elasticsearch",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "co.elastic.apm",
Namespace: "co.elastic.apm", Name: "apm-agent-cached-lookup-key",
Name: "apm-agent-cached-lookup-key", Version: "1.36.0",
Version: "1.36.0",
},
}, },
}, },
}, },
@@ -65,13 +61,11 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Version: "1.36.0", Version: "1.36.0",
FilePath: "opt/bitnami/elasticsearch", FilePath: "opt/bitnami/elasticsearch",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "co.elastic.apm",
Namespace: "co.elastic.apm", Name: "apm-agent-common",
Name: "apm-agent-common", Version: "1.36.0",
Version: "1.36.0",
},
}, },
}, },
}, },
@@ -80,13 +74,11 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Version: "1.36.0", Version: "1.36.0",
FilePath: "opt/bitnami/elasticsearch", FilePath: "opt/bitnami/elasticsearch",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "co.elastic.apm",
Namespace: "co.elastic.apm", Name: "apm-agent-core",
Name: "apm-agent-core", Version: "1.36.0",
Version: "1.36.0",
},
}, },
}, },
}, },
@@ -102,16 +94,14 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Arch: "arm64", Arch: "arm64",
Licenses: []string{"Elastic-2.0"}, Licenses: []string{"Elastic-2.0"},
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeBitnami,
Type: packageurl.TypeBitnami, Name: "elasticsearch",
Name: "elasticsearch", Version: "8.9.1",
Version: "8.9.1", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "arch",
Key: "arch", Value: "arm64",
Value: "arm64",
},
}, },
}, },
}, },
@@ -137,14 +127,11 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Name: "co.elastic.apm:apm-agent", Name: "co.elastic.apm:apm-agent",
Version: "1.36.0", Version: "1.36.0",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "co.elastic.apm",
Namespace: "co.elastic.apm", Name: "apm-agent",
Name: "apm-agent", Version: "1.36.0",
Version: "1.36.0",
},
FilePath: "opt/bitnami/elasticsearch/modules/apm/elastic-apm-agent-1.36.0.jar",
}, },
BOMRef: "pkg:maven/co.elastic.apm/apm-agent@1.36.0", BOMRef: "pkg:maven/co.elastic.apm/apm-agent@1.36.0",
}, },
@@ -154,14 +141,11 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Name: "co.elastic.apm:apm-agent-cached-lookup-key", Name: "co.elastic.apm:apm-agent-cached-lookup-key",
Version: "1.36.0", Version: "1.36.0",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "co.elastic.apm",
Namespace: "co.elastic.apm", Name: "apm-agent-cached-lookup-key",
Name: "apm-agent-cached-lookup-key", Version: "1.36.0",
Version: "1.36.0",
},
FilePath: "opt/bitnami/elasticsearch/modules/apm/elastic-apm-agent-1.36.0.jar",
}, },
BOMRef: "pkg:maven/co.elastic.apm/apm-agent-cached-lookup-key@1.36.0", BOMRef: "pkg:maven/co.elastic.apm/apm-agent-cached-lookup-key@1.36.0",
}, },
@@ -187,12 +171,10 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Version: "3.7.1", Version: "3.7.1",
Licenses: []string{"MIT"}, Licenses: []string{"MIT"},
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeBitnami,
Type: packageurl.TypeBitnami, Name: "gdal",
Name: "gdal", Version: "3.7.1",
Version: "3.7.1",
},
}, },
}, },
}, },
@@ -201,12 +183,10 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Version: "3.8.3", Version: "3.8.3",
Licenses: []string{"LGPL-2.1-only"}, Licenses: []string{"LGPL-2.1-only"},
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeBitnami,
Type: packageurl.TypeBitnami, Name: "geos",
Name: "geos", Version: "3.8.3",
Version: "3.8.3",
},
}, },
}, },
}, },
@@ -215,12 +195,10 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Version: "15.3.0", Version: "15.3.0",
Licenses: []string{"PostgreSQL"}, Licenses: []string{"PostgreSQL"},
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeBitnami,
Type: packageurl.TypeBitnami, Name: "postgresql",
Name: "postgresql", Version: "15.3.0",
Version: "15.3.0",
},
}, },
}, },
}, },
@@ -229,12 +207,10 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
Version: "6.3.2", Version: "6.3.2",
Licenses: []string{"MIT"}, Licenses: []string{"MIT"},
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeBitnami,
Type: packageurl.TypeBitnami, Name: "proj",
Name: "proj", Version: "6.3.2",
Version: "6.3.2",
},
}, },
}, },
}, },

View File

@@ -151,17 +151,15 @@ func TestApplier_ApplyLayers(t *testing.T) {
SrcName: "glibc", SrcName: "glibc",
SrcVersion: "2.24-11+deb9u4", SrcVersion: "2.24-11+deb9u4",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeDebian,
Type: packageurl.TypeDebian, Namespace: "debian",
Namespace: "debian", Name: "libc6",
Name: "libc6", Version: "2.24-11+deb9u4",
Version: "2.24-11+deb9u4", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "debian-9.9",
Value: "debian-9.9",
},
}, },
}, },
}, },
@@ -177,17 +175,15 @@ func TestApplier_ApplyLayers(t *testing.T) {
SrcName: "tzdata", SrcName: "tzdata",
SrcVersion: "2019a-0+deb9u1", SrcVersion: "2019a-0+deb9u1",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeDebian,
Type: packageurl.TypeDebian, Namespace: "debian",
Namespace: "debian", Name: "tzdata",
Name: "tzdata", Version: "2019a-0+deb9u1",
Version: "2019a-0+deb9u1", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "debian-9.9",
Value: "debian-9.9",
},
}, },
}, },
}, },
@@ -211,13 +207,11 @@ func TestApplier_ApplyLayers(t *testing.T) {
DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "guzzlehttp",
Namespace: "guzzlehttp", Name: "guzzle",
Name: "guzzle", Version: "6.2.0",
Version: "6.2.0",
},
}, },
}, },
}, },
@@ -229,13 +223,11 @@ func TestApplier_ApplyLayers(t *testing.T) {
DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "symfony",
Namespace: "symfony", Name: "process",
Name: "process", Version: "v4.2.7",
Version: "v4.2.7",
},
}, },
}, },
}, },
@@ -353,17 +345,15 @@ func TestApplier_ApplyLayers(t *testing.T) {
Name: "busybox", Name: "busybox",
Version: "1.30.1-r3", Version: "1.30.1-r3",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "busybox",
Name: "busybox", Version: "1.30.1-r3",
Version: "1.30.1-r3", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.10.4",
Value: "3.10.4",
},
}, },
}, },
}, },
@@ -377,17 +367,15 @@ func TestApplier_ApplyLayers(t *testing.T) {
Name: "libcrypto1.1", Name: "libcrypto1.1",
Version: "1.1.1d-r2", Version: "1.1.1d-r2",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "libcrypto1.1",
Name: "libcrypto1.1", Version: "1.1.1d-r2",
Version: "1.1.1d-r2", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.10.4",
Value: "3.10.4",
},
}, },
}, },
}, },
@@ -401,17 +389,15 @@ func TestApplier_ApplyLayers(t *testing.T) {
Name: "libssl1.1", Name: "libssl1.1",
Version: "1.1.1d-r2", Version: "1.1.1d-r2",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "libssl1.1",
Name: "libssl1.1", Version: "1.1.1d-r2",
Version: "1.1.1d-r2", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.10.4",
Value: "3.10.4",
},
}, },
}, },
}, },
@@ -425,17 +411,15 @@ func TestApplier_ApplyLayers(t *testing.T) {
Name: "musl", Name: "musl",
Version: "1.1.22-r3", Version: "1.1.22-r3",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "musl",
Name: "musl", Version: "1.1.22-r3",
Version: "1.1.22-r3", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.10.4",
Value: "3.10.4",
},
}, },
}, },
}, },
@@ -450,17 +434,15 @@ func TestApplier_ApplyLayers(t *testing.T) {
Version: "1.1.1d-r2", Version: "1.1.1d-r2",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
//PURL: "pkg:apk/alpine/openssl@1.1.1d-r2?distro=3.10.4", //PURL: "pkg:apk/alpine/openssl@1.1.1d-r2?distro=3.10.4",
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "openssl",
Name: "openssl", Version: "1.1.1d-r2",
Version: "1.1.1d-r2", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.10.4",
Value: "3.10.4",
},
}, },
}, },
}, },
@@ -684,13 +666,11 @@ func TestApplier_ApplyLayers(t *testing.T) {
DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "guzzlehttp",
Namespace: "guzzlehttp", Name: "guzzle",
Name: "guzzle", Version: "6.2.0",
Version: "6.2.0",
},
}, },
}, },
}, },
@@ -702,13 +682,11 @@ func TestApplier_ApplyLayers(t *testing.T) {
DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "symfony",
Namespace: "symfony", Name: "process",
Name: "process", Version: "v4.2.7",
Version: "v4.2.7",
},
}, },
}, },
}, },
@@ -896,13 +874,11 @@ func TestApplier_ApplyLayers(t *testing.T) {
DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "guzzlehttp",
Namespace: "guzzlehttp", Name: "guzzle",
Name: "guzzle", Version: "6.2.0",
Version: "6.2.0",
},
}, },
}, },
}, },
@@ -914,13 +890,11 @@ func TestApplier_ApplyLayers(t *testing.T) {
DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "symfony",
Namespace: "symfony", Name: "process",
Name: "process", Version: "v4.2.7",
Version: "v4.2.7",
},
}, },
}, },
}, },

View File

@@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/knqyf263/nested" "github.com/knqyf263/nested"
"github.com/package-url/packageurl-go"
"github.com/samber/lo" "github.com/samber/lo"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
@@ -249,12 +250,13 @@ func ApplyLayers(layers []ftypes.BlobInfo) ftypes.ArtifactDetail {
return mergedLayer return mergedLayer
} }
func newPURL(pkgType ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) *ftypes.PackageURL { func newPURL(pkgType ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) *packageurl.PackageURL {
p, err := purl.New(pkgType, metadata, pkg) p, err := purl.New(pkgType, metadata, pkg)
if err != nil { if err != nil {
log.Logger.Errorf("Failed to create PackageURL: %s", err) log.Logger.Errorf("Failed to create PackageURL: %s", err)
return nil
} }
return p return p.Unwrap()
} }
// aggregate merges all packages installed by pip/gem/npm/jar/conda into each application // aggregate merges all packages installed by pip/gem/npm/jar/conda into each application

View File

@@ -1,10 +1,10 @@
package applier_test package applier_test
import ( import (
"github.com/package-url/packageurl-go"
"sort" "sort"
"testing" "testing"
"github.com/package-url/packageurl-go"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/aquasecurity/trivy/pkg/fanal/applier" "github.com/aquasecurity/trivy/pkg/fanal/applier"
@@ -145,17 +145,15 @@ func TestApplyLayers(t *testing.T) {
Version: "1.2.4", Version: "1.2.4",
Release: "4.5.8", Release: "4.5.8",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "musl",
Name: "musl", Version: "1.2.4-4.5.8",
Version: "1.2.4-4.5.8", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.10",
Value: "3.10",
},
}, },
}, },
}, },
@@ -170,17 +168,15 @@ func TestApplyLayers(t *testing.T) {
Version: "1.2.3", Version: "1.2.3",
Release: "4.5.6", Release: "4.5.6",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "openssl",
Name: "openssl", Version: "1.2.3-4.5.6",
Version: "1.2.3-4.5.6", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.10",
Value: "3.10",
},
}, },
}, },
}, },
@@ -204,13 +200,10 @@ func TestApplyLayers(t *testing.T) {
DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "activesupport",
Name: "activesupport", Version: "6.0.2.1",
Version: "6.0.2.1",
},
FilePath: "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec",
}, },
}, },
}, },
@@ -223,13 +216,10 @@ func TestApplyLayers(t *testing.T) {
DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "gon",
Name: "gon", Version: "6.3.2",
Version: "6.3.2",
},
FilePath: "usr/local/bundle/specifications/gon-6.3.2.gemspec",
}, },
}, },
}, },
@@ -247,12 +237,10 @@ func TestApplyLayers(t *testing.T) {
DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "gemlibrary1",
Name: "gemlibrary1", Version: "1.2.3",
Version: "1.2.3",
},
}, },
}, },
}, },
@@ -474,12 +462,10 @@ func TestApplyLayers(t *testing.T) {
DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "rack",
Name: "rack", Version: "4.0.0",
Version: "4.0.0",
},
}, },
}, },
}, },
@@ -491,12 +477,10 @@ func TestApplyLayers(t *testing.T) {
DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "rails",
Name: "rails", Version: "6.0.0",
Version: "6.0.0",
},
}, },
}, },
}, },
@@ -514,12 +498,10 @@ func TestApplyLayers(t *testing.T) {
DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Name: "phplibrary1",
Name: "phplibrary1", Version: "6.6.6",
Version: "6.6.6",
},
}, },
}, },
}, },
@@ -779,17 +761,15 @@ func TestApplyLayers(t *testing.T) {
Release: "4.5.7", Release: "4.5.7",
Licenses: []string{"GPL-2"}, Licenses: []string{"GPL-2"},
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeDebian,
Type: packageurl.TypeDebian, Namespace: "debian",
Namespace: "debian", Name: "libc",
Name: "libc", Version: "1.2.4-4.5.7",
Version: "1.2.4-4.5.7", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "debian-8",
Value: "debian-8",
},
}, },
}, },
}, },
@@ -805,17 +785,15 @@ func TestApplyLayers(t *testing.T) {
Release: "4.5.6", Release: "4.5.6",
Licenses: []string{"OpenSSL"}, Licenses: []string{"OpenSSL"},
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeDebian,
Type: packageurl.TypeDebian, Namespace: "debian",
Namespace: "debian", Name: "openssl",
Name: "openssl", Version: "1.2.3-4.5.6",
Version: "1.2.3-4.5.6", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "debian-8",
Value: "debian-8",
},
}, },
}, },
}, },
@@ -957,17 +935,15 @@ func TestApplyLayers(t *testing.T) {
Version: "5.6.7", Version: "5.6.7",
Release: "8", Release: "8",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM,
Type: packageurl.TypeRPM, Namespace: "redhat",
Namespace: "redhat", Name: "bash",
Name: "bash", Version: "5.6.7-8",
Version: "5.6.7-8", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "redhat-8",
Value: "redhat-8",
},
}, },
}, },
}, },
@@ -986,17 +962,15 @@ func TestApplyLayers(t *testing.T) {
Version: "1.2.4", Version: "1.2.4",
Release: "5", Release: "5",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM,
Type: packageurl.TypeRPM, Namespace: "redhat",
Namespace: "redhat", Name: "libc",
Name: "libc", Version: "1.2.4-5",
Version: "1.2.4-5", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "redhat-8",
Value: "redhat-8",
},
}, },
}, },
}, },
@@ -1017,17 +991,15 @@ func TestApplyLayers(t *testing.T) {
Version: "1.2.3", Version: "1.2.3",
Release: "4", Release: "4",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM,
Type: packageurl.TypeRPM, Namespace: "redhat",
Namespace: "redhat", Name: "openssl",
Name: "openssl", Version: "1.2.3-4",
Version: "1.2.3-4", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "redhat-8",
Value: "redhat-8",
},
}, },
}, },
}, },

View File

@@ -84,17 +84,15 @@ func TestArtifact_InspectRekorAttestation(t *testing.T) {
Name: "musl", Name: "musl",
Version: "1.2.3-r0", Version: "1.2.3-r0",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "musl",
Name: "musl", Version: "1.2.3-r0",
Version: "1.2.3-r0", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.16.2",
Value: "3.16.2",
},
}, },
}, },
}, },
@@ -235,13 +233,11 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) {
Name: "github.com/opencontainers/go-digest", Name: "github.com/opencontainers/go-digest",
Version: "v1.0.0", Version: "v1.0.0",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "github.com/opencontainers",
Namespace: "github.com/opencontainers", Name: "go-digest",
Name: "go-digest", Version: "v1.0.0",
Version: "v1.0.0",
},
}, },
BOMRef: "pkg:golang/github.com/opencontainers/go-digest@v1.0.0", BOMRef: "pkg:golang/github.com/opencontainers/go-digest@v1.0.0",
}, },
@@ -250,13 +246,11 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) {
Name: "golang.org/x/sync", Name: "golang.org/x/sync",
Version: "v0.1.0", Version: "v0.1.0",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "golang.org/x",
Namespace: "golang.org/x", Name: "sync",
Name: "sync", Version: "v0.1.0",
Version: "v0.1.0",
},
}, },
BOMRef: "pkg:golang/golang.org/x/sync@v0.1.0", BOMRef: "pkg:golang/golang.org/x/sync@v0.1.0",
}, },

View File

@@ -50,17 +50,15 @@ func TestArtifact_Inspect(t *testing.T) {
DiffID: "sha256:dd565ff850e7003356e2b252758f9bdc1ff2803f61e995e24c7844f6297f8fc3", DiffID: "sha256:dd565ff850e7003356e2b252758f9bdc1ff2803f61e995e24c7844f6297f8fc3",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "musl",
Name: "musl", Version: "1.2.3-r0",
Version: "1.2.3-r0", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.16.0",
Value: "3.16.0",
},
}, },
}, },
}, },
@@ -82,13 +80,11 @@ func TestArtifact_Inspect(t *testing.T) {
DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "log",
Name: "log", Version: "1.13.1",
Version: "1.13.1",
},
}, },
BOMRef: "pkg:composer/pear/log@1.13.1", BOMRef: "pkg:composer/pear/log@1.13.1",
}, },
@@ -101,13 +97,11 @@ func TestArtifact_Inspect(t *testing.T) {
DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "pear_exception",
Name: "pear_exception", Version: "v1.0.0",
Version: "v1.0.0",
},
}, },
BOMRef: "pkg:composer/pear/pear_exception@v1.0.0", BOMRef: "pkg:composer/pear/pear_exception@v1.0.0",
}, },
@@ -125,13 +119,11 @@ func TestArtifact_Inspect(t *testing.T) {
DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1",
}, },
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "github.com/package-url",
Namespace: "github.com/package-url", Name: "packageurl-go",
Name: "packageurl-go", Version: "v0.1.1-0.20220203205134-d70459300c8a",
Version: "v0.1.1-0.20220203205134-d70459300c8a",
},
}, },
BOMRef: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", BOMRef: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a",
}, },
@@ -150,14 +142,11 @@ func TestArtifact_Inspect(t *testing.T) {
}, },
FilePath: "app/maven/target/child-project-1.0.jar", FilePath: "app/maven/target/child-project-1.0.jar",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.codehaus.mojo",
Namespace: "org.codehaus.mojo", Name: "child-project",
Name: "child-project", Version: "1.0",
Version: "1.0",
},
FilePath: "app/maven/target/child-project-1.0.jar",
}, },
BOMRef: "pkg:maven/org.codehaus.mojo/child-project@1.0?file_path=app%2Fmaven%2Ftarget%2Fchild-project-1.0.jar", BOMRef: "pkg:maven/org.codehaus.mojo/child-project@1.0?file_path=app%2Fmaven%2Ftarget%2Fchild-project-1.0.jar",
}, },
@@ -177,13 +166,10 @@ func TestArtifact_Inspect(t *testing.T) {
}, },
FilePath: "app/app/package.json", FilePath: "app/app/package.json",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM,
Type: packageurl.TypeNPM, Name: "bootstrap",
Name: "bootstrap", Version: "5.0.2",
Version: "5.0.2",
},
FilePath: "app/app/package.json",
}, },
BOMRef: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json", BOMRef: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json",
}, },
@@ -226,17 +212,15 @@ func TestArtifact_Inspect(t *testing.T) {
SrcVersion: "1.2.3-r0", SrcVersion: "1.2.3-r0",
Licenses: []string{"MIT"}, Licenses: []string{"MIT"},
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "musl",
Name: "musl", Version: "1.2.3-r0",
Version: "1.2.3-r0", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.16.0",
Value: "3.16.0",
},
}, },
}, },
}, },
@@ -258,13 +242,11 @@ func TestArtifact_Inspect(t *testing.T) {
Name: "pear/log", Name: "pear/log",
Version: "1.13.1", Version: "1.13.1",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "log",
Name: "log", Version: "1.13.1",
Version: "1.13.1",
},
}, },
BOMRef: "pkg:composer/pear/log@1.13.1", BOMRef: "pkg:composer/pear/log@1.13.1",
}, },
@@ -277,13 +259,11 @@ func TestArtifact_Inspect(t *testing.T) {
Name: "pear/pear_exception", Name: "pear/pear_exception",
Version: "v1.0.0", Version: "v1.0.0",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "pear_exception",
Name: "pear_exception", Version: "v1.0.0",
Version: "v1.0.0",
},
}, },
BOMRef: "pkg:composer/pear/pear_exception@v1.0.0", BOMRef: "pkg:composer/pear/pear_exception@v1.0.0",
}, },
@@ -301,13 +281,11 @@ func TestArtifact_Inspect(t *testing.T) {
Name: "github.com/package-url/packageurl-go", Name: "github.com/package-url/packageurl-go",
Version: "v0.1.1-0.20220203205134-d70459300c8a", Version: "v0.1.1-0.20220203205134-d70459300c8a",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "github.com/package-url",
Namespace: "github.com/package-url", Name: "packageurl-go",
Name: "packageurl-go", Version: "v0.1.1-0.20220203205134-d70459300c8a",
Version: "v0.1.1-0.20220203205134-d70459300c8a",
},
}, },
BOMRef: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", BOMRef: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a",
}, },
@@ -325,14 +303,11 @@ func TestArtifact_Inspect(t *testing.T) {
Name: "org.codehaus.mojo:child-project", Name: "org.codehaus.mojo:child-project",
Version: "1.0", Version: "1.0",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.codehaus.mojo",
Namespace: "org.codehaus.mojo", Name: "child-project",
Name: "child-project", Version: "1.0",
Version: "1.0",
},
FilePath: "app/maven/target/child-project-1.0.jar",
}, },
BOMRef: "pkg:maven/org.codehaus.mojo/child-project@1.0?file_path=app%2Fmaven%2Ftarget%2Fchild-project-1.0.jar", BOMRef: "pkg:maven/org.codehaus.mojo/child-project@1.0?file_path=app%2Fmaven%2Ftarget%2Fchild-project-1.0.jar",
}, },
@@ -351,13 +326,10 @@ func TestArtifact_Inspect(t *testing.T) {
Name: "bootstrap", Name: "bootstrap",
Version: "5.0.2", Version: "5.0.2",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM,
Type: packageurl.TypeNPM, Name: "bootstrap",
Name: "bootstrap", Version: "5.0.2",
Version: "5.0.2",
},
FilePath: "app/app/package.json",
}, },
BOMRef: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json", BOMRef: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json",
}, },

View File

@@ -46,13 +46,11 @@ func Test_unpackagedHook_Handle(t *testing.T) {
Name: "github.com/spf13/cobra", Name: "github.com/spf13/cobra",
Version: "1.5.0", Version: "1.5.0",
Identifier: types.PkgIdentifier{ Identifier: types.PkgIdentifier{
PURL: &types.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "github.com/spf13",
Namespace: "github.com/spf13", Name: "cobra",
Name: "cobra", Version: "1.5.0",
Version: "1.5.0",
},
}, },
BOMRef: "pkg:golang/github.com/spf13/cobra@1.5.0", BOMRef: "pkg:golang/github.com/spf13/cobra@1.5.0",
}, },

View File

@@ -1,9 +1,11 @@
package types package types
import ( import (
"encoding/json"
"time" "time"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/package-url/packageurl-go"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/aquasecurity/trivy/pkg/digest" "github.com/aquasecurity/trivy/pkg/digest"
@@ -102,8 +104,51 @@ type Package struct {
// PkgIdentifier represents a software identifiers in one of more of the supported formats. // PkgIdentifier represents a software identifiers in one of more of the supported formats.
type PkgIdentifier struct { type PkgIdentifier struct {
PURL *PackageURL `json:",omitempty"` PURL *packageurl.PackageURL `json:"-"`
BOMRef string `json:",omitempty"` // For CycloneDX BOMRef string `json:",omitempty"` // For CycloneDX
}
// MarshalJSON customizes the JSON encoding of PkgIdentifier.
func (id *PkgIdentifier) MarshalJSON() ([]byte, error) {
var p string
if id.PURL != nil {
p = id.PURL.String()
}
type Alias PkgIdentifier
return json.Marshal(&struct {
PURL string `json:",omitempty"`
*Alias
}{
PURL: p,
Alias: (*Alias)(id),
})
}
// UnmarshalJSON customizes the JSON decoding of PkgIdentifier.
func (id *PkgIdentifier) UnmarshalJSON(data []byte) error {
type Alias PkgIdentifier
aux := &struct {
PURL string `json:",omitempty"`
*Alias
}{
Alias: (*Alias)(id),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux.PURL != "" {
p, err := packageurl.FromString(aux.PURL)
if err != nil {
return err
} else if len(p.Qualifiers) == 0 {
p.Qualifiers = nil
}
id.PURL = &p
}
return nil
} }
func (id *PkgIdentifier) Empty() bool { func (id *PkgIdentifier) Empty() bool {

View File

@@ -1,78 +0,0 @@
package types
import (
"encoding/json"
"github.com/package-url/packageurl-go"
"golang.org/x/xerrors"
)
type PackageURL struct {
packageurl.PackageURL
FilePath string
}
func (p *PackageURL) BOMRef() string {
// 'bom-ref' must be unique within BOM, but PURLs may conflict
// when the same packages are installed in an artifact.
// In that case, we prefer to make PURLs unique by adding file paths,
// rather than using UUIDs, even if it is not PURL technically.
// ref. https://cyclonedx.org/use-cases/#dependency-graph
purl := p.PackageURL // so that it will not override the qualifiers below
if p.FilePath != "" {
purl.Qualifiers = append(purl.Qualifiers,
packageurl.Qualifier{
Key: "file_path",
Value: p.FilePath,
},
)
}
return purl.String()
}
func (p *PackageURL) MarshalJSON() ([]byte, error) {
if p == nil {
return nil, nil
}
return json.Marshal(p.String())
}
func (p *PackageURL) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
purl, err := NewPackageURL(s)
if err != nil {
return xerrors.Errorf("failed to parse purl(%s): %w", string(b), err)
}
*p = *purl
return nil
}
func NewPackageURL(s string) (*PackageURL, error) {
p, err := packageurl.FromString(s)
if err != nil {
return nil, xerrors.Errorf("failed to parse purl(%s): %w", s, err)
}
// Take out and delete the file path from qualifiers
var filePath string
for i, q := range p.Qualifiers {
if q.Key != "file_path" {
continue
}
filePath = q.Value
p.Qualifiers = append(p.Qualifiers[:i], p.Qualifiers[i+1:]...)
break
}
if len(p.Qualifiers) == 0 {
p.Qualifiers = nil
}
return &PackageURL{
PackageURL: p,
FilePath: filePath,
}, nil
}

View File

@@ -577,7 +577,7 @@ func nodeComponent(nf bom.NodeInfo) *core.Component {
Namespace: k8sCoreComponentNamespace, Namespace: k8sCoreComponentNamespace,
}, },
}, },
PackageURL: &ftypes.PackageURL{ PackageURL: &purl.PackageURL{
PackageURL: *packageurl.NewPackageURL(golang, "", runtimeName, runtimeVersion, packageurl.Qualifiers{}, ""), PackageURL: *packageurl.NewPackageURL(golang, "", runtimeName, runtimeVersion, packageurl.Qualifiers{}, ""),
}, },
}, },
@@ -601,7 +601,7 @@ func toProperties(props map[string]string, namespace string) []core.Property {
return properties return properties
} }
func generatePURL(name, ver, nodeName string) *ftypes.PackageURL { func generatePURL(name, ver, nodeName string) *purl.PackageURL {
var namespace string var namespace string
// Identify k8s distribution. An empty namespace means upstream. // Identify k8s distribution. An empty namespace means upstream.
@@ -611,7 +611,7 @@ func generatePURL(name, ver, nodeName string) *ftypes.PackageURL {
namespace = "" namespace = ""
} }
return &ftypes.PackageURL{ return &purl.PackageURL{
PackageURL: *packageurl.NewPackageURL(purl.TypeK8s, namespace, name, ver, nil, ""), PackageURL: *packageurl.NewPackageURL(purl.TypeK8s, namespace, name, ver, nil, ""),
} }
} }

View File

@@ -2,7 +2,6 @@ package scanner
import ( import (
"context" "context"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"sort" "sort"
"testing" "testing"
@@ -98,7 +97,7 @@ func TestScanner_Scan(t *testing.T) {
Namespace: k8sCoreComponentNamespace, Namespace: k8sCoreComponentNamespace,
}, },
}, },
PackageURL: &ftypes.PackageURL{ PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: purl.TypeK8s, Type: purl.TypeK8s,
Name: "k8s.io/kubernetes", Name: "k8s.io/kubernetes",
@@ -110,7 +109,7 @@ func TestScanner_Scan(t *testing.T) {
Type: cdx.ComponentTypeApplication, Type: cdx.ComponentTypeApplication,
Name: "k8s.io/apiserver", Name: "k8s.io/apiserver",
Version: "1.21.1", Version: "1.21.1",
PackageURL: &ftypes.PackageURL{ PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: purl.TypeK8s, Type: purl.TypeK8s,
Name: "k8s.io/apiserver", Name: "k8s.io/apiserver",
@@ -123,7 +122,7 @@ func TestScanner_Scan(t *testing.T) {
Type: cdx.ComponentTypeContainer, Type: cdx.ComponentTypeContainer,
Name: "k8s.gcr.io/kube-apiserver", Name: "k8s.gcr.io/kube-apiserver",
Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f", Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
PackageURL: &ftypes.PackageURL{ PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: "oci", Type: "oci",
Name: "kube-apiserver", Name: "kube-apiserver",
@@ -234,7 +233,7 @@ func TestScanner_Scan(t *testing.T) {
Namespace: k8sCoreComponentNamespace, Namespace: k8sCoreComponentNamespace,
}, },
}, },
PackageURL: &ftypes.PackageURL{ PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: "k8s", Type: "k8s",
Name: "k8s.io/kubelet", Name: "k8s.io/kubelet",
@@ -258,7 +257,7 @@ func TestScanner_Scan(t *testing.T) {
Namespace: k8sCoreComponentNamespace, Namespace: k8sCoreComponentNamespace,
}, },
}, },
PackageURL: &ftypes.PackageURL{ PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: "golang", Type: "golang",
Name: "github.com/containerd/containerd", Name: "github.com/containerd/containerd",

View File

@@ -1617,7 +1617,9 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes(in *jlexer.Lexer,
case "PkgPath": case "PkgPath":
out.PkgPath = string(in.String()) out.PkgPath = string(in.String())
case "PkgIdentifier": case "PkgIdentifier":
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in, &out.PkgIdentifier) if data := in.Raw(); in.Ok() {
in.AddError((out.PkgIdentifier).UnmarshalJSON(data))
}
case "InstalledVersion": case "InstalledVersion":
out.InstalledVersion = string(in.String()) out.InstalledVersion = string(in.String())
case "FixedVersion": case "FixedVersion":
@@ -1843,7 +1845,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes(out *jwriter.Write
} else { } else {
out.RawString(prefix) out.RawString(prefix)
} }
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out, in.PkgIdentifier) out.Raw((in.PkgIdentifier).MarshalJSON())
} }
if in.InstalledVersion != "" { if in.InstalledVersion != "" {
const prefix string = ",\"InstalledVersion\":" const prefix string = ",\"InstalledVersion\":"
@@ -2215,71 +2217,6 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyDbPkgTypes(out *jwriter.Wri
} }
out.RawByte('}') out.RawByte('}')
} }
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in *jlexer.Lexer, out *types1.PkgIdentifier) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
in.Consumed()
}
in.Skip()
return
}
in.Delim('{')
for !in.IsDelim('}') {
key := in.UnsafeFieldName(false)
in.WantColon()
if in.IsNull() {
in.Skip()
in.WantComma()
continue
}
switch key {
case "PURL":
if in.IsNull() {
in.Skip()
out.PURL = nil
} else {
if out.PURL == nil {
out.PURL = new(types1.PackageURL)
}
if data := in.Raw(); in.Ok() {
in.AddError((*out.PURL).UnmarshalJSON(data))
}
}
case "BOMRef":
out.BOMRef = string(in.String())
default:
in.SkipRecursive()
}
in.WantComma()
}
in.Delim('}')
if isTopLevel {
in.Consumed()
}
}
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out *jwriter.Writer, in types1.PkgIdentifier) {
out.RawByte('{')
first := true
_ = first
if in.PURL != nil {
const prefix string = ",\"PURL\":"
first = false
out.RawString(prefix[1:])
out.Raw((*in.PURL).MarshalJSON())
}
if in.BOMRef != "" {
const prefix string = ",\"BOMRef\":"
if first {
first = false
out.RawString(prefix[1:])
} else {
out.RawString(prefix)
}
out.String(string(in.BOMRef))
}
out.RawByte('}')
}
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Lexer, out *types1.Package) { func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Lexer, out *types1.Package) {
isTopLevel := in.IsStart() isTopLevel := in.IsStart()
if in.IsNull() { if in.IsNull() {
@@ -2304,7 +2241,9 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le
case "Name": case "Name":
out.Name = string(in.String()) out.Name = string(in.String())
case "Identifier": case "Identifier":
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in, &out.Identifier) if data := in.Raw(); in.Ok() {
in.AddError((out.Identifier).UnmarshalJSON(data))
}
case "Version": case "Version":
out.Version = string(in.String()) out.Version = string(in.String())
case "Release": case "Release":
@@ -2358,7 +2297,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le
if out.BuildInfo == nil { if out.BuildInfo == nil {
out.BuildInfo = new(types1.BuildInfo) out.BuildInfo = new(types1.BuildInfo)
} }
easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes10(in, out.BuildInfo) easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in, out.BuildInfo)
} }
case "Indirect": case "Indirect":
out.Indirect = bool(in.Bool()) out.Indirect = bool(in.Bool())
@@ -2475,7 +2414,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter.
} else { } else {
out.RawString(prefix) out.RawString(prefix)
} }
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out, in.Identifier) out.Raw((in.Identifier).MarshalJSON())
} }
if in.Version != "" { if in.Version != "" {
const prefix string = ",\"Version\":" const prefix string = ",\"Version\":"
@@ -2614,7 +2553,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter.
} else { } else {
out.RawString(prefix) out.RawString(prefix)
} }
easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes10(out, *in.BuildInfo) easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out, *in.BuildInfo)
} }
if in.Indirect { if in.Indirect {
const prefix string = ",\"Indirect\":" const prefix string = ",\"Indirect\":"
@@ -2715,7 +2654,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter.
} }
out.RawByte('}') out.RawByte('}')
} }
func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes10(in *jlexer.Lexer, out *types1.BuildInfo) { func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in *jlexer.Lexer, out *types1.BuildInfo) {
isTopLevel := in.IsStart() isTopLevel := in.IsStart()
if in.IsNull() { if in.IsNull() {
if isTopLevel { if isTopLevel {
@@ -2771,7 +2710,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes10(in *jlexer.
in.Consumed() in.Consumed()
} }
} }
func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes10(out *jwriter.Writer, in types1.BuildInfo) { func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out *jwriter.Writer, in types1.BuildInfo) {
out.RawByte('{') out.RawByte('{')
first := true first := true
_ = first _ = first

View File

@@ -43,13 +43,135 @@ const (
TypeUnknown = "unknown" TypeUnknown = "unknown"
) )
func FromString(s string) (*ftypes.PackageURL, error) { type PackageURL struct {
return ftypes.NewPackageURL(s) packageurl.PackageURL
FilePath string
}
func FromString(s string) (*PackageURL, error) {
p, err := packageurl.FromString(s)
if err != nil {
return nil, xerrors.Errorf("failed to parse purl(%s): %w", s, err)
}
// Take out and delete the file path from qualifiers
var filePath string
for i, q := range p.Qualifiers {
if q.Key != "file_path" {
continue
}
filePath = q.Value
p.Qualifiers = append(p.Qualifiers[:i], p.Qualifiers[i+1:]...)
break
}
if len(p.Qualifiers) == 0 {
p.Qualifiers = nil
}
return &PackageURL{
PackageURL: p,
FilePath: filePath,
}, nil
}
// nolint: gocyclo
func New(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) (*PackageURL, error) {
qualifiers := parseQualifier(pkg)
pkg.Epoch = 0 // we moved Epoch to qualifiers so we don't need it in version
ptype := purlType(t)
name := pkg.Name
ver := utils.FormatVersion(pkg)
namespace := ""
subpath := ""
switch ptype {
case packageurl.TypeRPM:
ns, qs := parseRPM(metadata.OS, pkg.Modularitylabel)
namespace = string(ns)
qualifiers = append(qualifiers, qs...)
case packageurl.TypeDebian:
qualifiers = append(qualifiers, parseDeb(metadata.OS)...)
if metadata.OS != nil {
namespace = string(metadata.OS.Family)
}
case packageurl.TypeApk:
var qs packageurl.Qualifiers
name, namespace, qs = parseApk(name, metadata.OS)
qualifiers = append(qualifiers, qs...)
case packageurl.TypeMaven, string(ftypes.Gradle): // TODO: replace with packageurl.TypeGradle once they add it.
namespace, name = parseMaven(name)
case packageurl.TypePyPi:
name = parsePyPI(name)
case packageurl.TypeComposer:
namespace, name = parseComposer(name)
case packageurl.TypeGolang:
namespace, name = parseGolang(name)
if name == "" {
return nil, nil
}
case packageurl.TypeNPM:
namespace, name = parseNpm(name)
case packageurl.TypeSwift:
namespace, name = parseSwift(name)
case packageurl.TypeCocoapods:
name, subpath = parseCocoapods(name)
case packageurl.TypeOCI:
purl, err := parseOCI(metadata)
if err != nil {
return nil, err
} else if purl.Type == "" {
return nil, nil
}
return &PackageURL{PackageURL: purl}, nil
}
return &PackageURL{
PackageURL: *packageurl.NewPackageURL(ptype, namespace, name, ver, qualifiers, subpath),
FilePath: pkg.FilePath,
}, nil
}
// WithPath wraps packageurl.PackageURL with the given file path
func WithPath(purl *packageurl.PackageURL, filePath string) *PackageURL {
if purl == nil {
return nil
}
return &PackageURL{
PackageURL: *purl,
FilePath: filePath,
}
}
func (p *PackageURL) BOMRef() string {
// 'bom-ref' must be unique within BOM, but PURLs may conflict
// when the same packages are installed in an artifact.
// In that case, we prefer to make PURLs unique by adding file paths,
// rather than using UUIDs, even if it is not PURL technically.
// ref. https://cyclonedx.org/use-cases/#dependency-graph
purl := p.PackageURL // so that it will not override the qualifiers below
if p.FilePath != "" {
purl.Qualifiers = append(purl.Qualifiers,
packageurl.Qualifier{
Key: "file_path",
Value: p.FilePath,
},
)
}
return purl.String()
}
func (p *PackageURL) Unwrap() *packageurl.PackageURL {
if p == nil {
return nil
}
return &p.PackageURL
} }
// LangType returns an application type in Trivy // LangType returns an application type in Trivy
// nolint: gocyclo // nolint: gocyclo
func LangType(p *ftypes.PackageURL) ftypes.LangType { func (p *PackageURL) LangType() ftypes.LangType {
switch p.Type { switch p.Type {
case packageurl.TypeComposer: case packageurl.TypeComposer:
return ftypes.Composer return ftypes.Composer
@@ -102,13 +224,13 @@ func LangType(p *ftypes.PackageURL) ftypes.LangType {
} }
} }
func Class(p *ftypes.PackageURL) types.ResultClass { func (p *PackageURL) Class() types.ResultClass {
switch p.Type { switch p.Type {
case packageurl.TypeApk, packageurl.TypeDebian, packageurl.TypeRPM: case packageurl.TypeApk, packageurl.TypeDebian, packageurl.TypeRPM:
// OS packages // OS packages
return types.ClassOSPkg return types.ClassOSPkg
default: default:
if LangType(p) == TypeUnknown { if p.LangType() == TypeUnknown {
return types.ClassUnknown return types.ClassUnknown
} }
// Language-specific packages // Language-specific packages
@@ -116,10 +238,13 @@ func Class(p *ftypes.PackageURL) types.ResultClass {
} }
} }
func ToPackage(p *ftypes.PackageURL) *ftypes.Package { func (p *PackageURL) Package() *ftypes.Package {
pkg := &ftypes.Package{ pkg := &ftypes.Package{
Name: p.Name, Name: p.Name,
Version: p.Version, Version: p.Version,
Identifier: ftypes.PkgIdentifier{
PURL: p.Unwrap(),
},
} }
for _, q := range p.Qualifiers { for _, q := range p.Qualifiers {
switch q.Key { switch q.Key {
@@ -151,11 +276,10 @@ func ToPackage(p *ftypes.PackageURL) *ftypes.Package {
// Return packages without namespace. // Return packages without namespace.
// OS packages are not supposed to have namespace. // OS packages are not supposed to have namespace.
if p.Namespace == "" || Class(p) == types.ClassOSPkg { if p.Namespace == "" || p.Class() == types.ClassOSPkg {
return pkg return pkg
} }
// TODO: replace with packageurl.TypeGradle once they add it.
if p.Type == packageurl.TypeMaven || p.Type == packageurl.TypeGradle { if p.Type == packageurl.TypeMaven || p.Type == packageurl.TypeGradle {
// Maven and Gradle packages separate ":" // Maven and Gradle packages separate ":"
// e.g. org.springframework:spring-core // e.g. org.springframework:spring-core
@@ -167,63 +291,34 @@ func ToPackage(p *ftypes.PackageURL) *ftypes.Package {
return pkg return pkg
} }
// nolint: gocyclo // Match returns true if the given PURL "target" satisfies the constraint PURL "p".
func New(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) (*ftypes.PackageURL, error) { // - If the constraint does not have a version, it will match any version in the target.
qualifiers := parseQualifier(pkg) // - If the constraint has qualifiers, the target must have the same set of qualifiers to match.
pkg.Epoch = 0 // we moved Epoch to qualifiers so we don't need it in version func (p *PackageURL) Match(target *packageurl.PackageURL) bool {
if target == nil {
ptype := purlType(t) return false
name := pkg.Name }
ver := utils.FormatVersion(pkg) switch {
namespace := "" case p.Type != target.Type:
subpath := "" return false
case p.Namespace != target.Namespace:
switch ptype { return false
case packageurl.TypeRPM: case p.Name != target.Name:
ns, qs := parseRPM(metadata.OS, pkg.Modularitylabel) return false
namespace = string(ns) case p.Version != "" && p.Version != target.Version:
qualifiers = append(qualifiers, qs...) return false
case packageurl.TypeDebian: case p.Subpath != "" && p.Subpath != target.Subpath:
qualifiers = append(qualifiers, parseDeb(metadata.OS)...) return false
if metadata.OS != nil {
namespace = string(metadata.OS.Family)
}
case packageurl.TypeApk:
var qs packageurl.Qualifiers
name, namespace, qs = parseApk(name, metadata.OS)
qualifiers = append(qualifiers, qs...)
case packageurl.TypeMaven, string(ftypes.Gradle): // TODO: replace with packageurl.TypeGradle once they add it.
namespace, name = parseMaven(name)
case packageurl.TypePyPi:
name = parsePyPI(name)
case packageurl.TypeComposer:
namespace, name = parseComposer(name)
case packageurl.TypeGolang:
namespace, name = parseGolang(name)
if name == "" {
return nil, nil
}
case packageurl.TypeNPM:
namespace, name = parseNpm(name)
case packageurl.TypeSwift:
namespace, name = parseSwift(name)
case packageurl.TypeCocoapods:
name, subpath = parseCocoapods(name)
case packageurl.TypeOCI:
purl, err := parseOCI(metadata)
if err != nil {
return nil, err
}
if purl.Type == "" {
return nil, nil
}
return &ftypes.PackageURL{PackageURL: purl}, nil
} }
return &ftypes.PackageURL{ // All qualifiers in the constraint must be in the target to match
PackageURL: *packageurl.NewPackageURL(ptype, namespace, name, ver, qualifiers, subpath), q := target.Qualifiers.Map()
FilePath: pkg.FilePath, for k, v1 := range p.Qualifiers.Map() {
}, nil if v2, ok := q[k]; !ok || v1 != v2 {
return false
}
}
return true
} }
// ref. https://github.com/package-url/purl-spec/blob/a748c36ad415c8aeffe2b8a4a5d8a50d16d6d85f/PURL-TYPES.rst#oci // ref. https://github.com/package-url/purl-spec/blob/a748c36ad415c8aeffe2b8a4a5d8a50d16d6d85f/PURL-TYPES.rst#oci

View File

@@ -20,7 +20,7 @@ func TestNewPackageURL(t *testing.T) {
typ ftypes.TargetType typ ftypes.TargetType
pkg ftypes.Package pkg ftypes.Package
metadata types.Metadata metadata types.Metadata
want *ftypes.PackageURL want *purl.PackageURL
wantErr string wantErr string
}{ }{
{ {
@@ -30,7 +30,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "org.springframework:spring-core", Name: "org.springframework:spring-core",
Version: "5.3.14", Version: "5.3.14",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeMaven, Type: packageurl.TypeMaven,
Namespace: "org.springframework", Namespace: "org.springframework",
@@ -46,7 +46,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "org.springframework:spring-core", Name: "org.springframework:spring-core",
Version: "5.3.14", Version: "5.3.14",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeMaven, Type: packageurl.TypeMaven,
Namespace: "org.springframework", Namespace: "org.springframework",
@@ -62,7 +62,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "@xtuc/ieee754", Name: "@xtuc/ieee754",
Version: "1.2.0", Version: "1.2.0",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeNPM, Type: packageurl.TypeNPM,
Namespace: "@xtuc", Namespace: "@xtuc",
@@ -78,7 +78,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "lodash", Name: "lodash",
Version: "4.17.21", Version: "4.17.21",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeNPM, Type: packageurl.TypeNPM,
Name: "lodash", Name: "lodash",
@@ -93,7 +93,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "@xtuc/ieee754", Name: "@xtuc/ieee754",
Version: "1.2.0", Version: "1.2.0",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeNPM, Type: packageurl.TypeNPM,
Namespace: "@xtuc", Namespace: "@xtuc",
@@ -109,7 +109,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "lodash", Name: "lodash",
Version: "4.17.21", Version: "4.17.21",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeNPM, Type: packageurl.TypeNPM,
Name: "lodash", Name: "lodash",
@@ -124,7 +124,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "Django_test", Name: "Django_test",
Version: "1.2.0", Version: "1.2.0",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypePyPi, Type: packageurl.TypePyPi,
Name: "django-test", Name: "django-test",
@@ -139,7 +139,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "absl-py", Name: "absl-py",
Version: "0.4.1", Version: "0.4.1",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeConda, Type: packageurl.TypeConda,
Name: "absl-py", Name: "absl-py",
@@ -154,7 +154,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "symfony/contracts", Name: "symfony/contracts",
Version: "v1.0.2", Version: "v1.0.2",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeComposer, Type: packageurl.TypeComposer,
Namespace: "symfony", Namespace: "symfony",
@@ -170,7 +170,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "github.com/go-sql-driver/Mysql", Name: "github.com/go-sql-driver/Mysql",
Version: "v1.5.0", Version: "v1.5.0",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeGolang, Type: packageurl.TypeGolang,
Namespace: "github.com/go-sql-driver", Namespace: "github.com/go-sql-driver",
@@ -202,7 +202,7 @@ func TestNewPackageURL(t *testing.T) {
}, },
}, },
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeHex, Type: packageurl.TypeHex,
Name: "bunt", Name: "bunt",
@@ -217,7 +217,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "http", Name: "http",
Version: "0.13.2", Version: "0.13.2",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypePub, Type: packageurl.TypePub,
Name: "http", Name: "http",
@@ -233,7 +233,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "github.com/apple/swift-atomics", Name: "github.com/apple/swift-atomics",
Version: "1.1.0", Version: "1.1.0",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeSwift, Type: packageurl.TypeSwift,
Namespace: "github.com/apple", Namespace: "github.com/apple",
@@ -250,7 +250,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "GoogleUtilities/NSData+zlib", Name: "GoogleUtilities/NSData+zlib",
Version: "7.5.2", Version: "7.5.2",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeCocoapods, Type: packageurl.TypeCocoapods,
Name: "GoogleUtilities", Name: "GoogleUtilities",
@@ -267,7 +267,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "abomination", Name: "abomination",
Version: "0.7.3", Version: "0.7.3",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeCargo, Type: packageurl.TypeCargo,
Name: "abomination", Name: "abomination",
@@ -283,7 +283,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "Newtonsoft.Json", Name: "Newtonsoft.Json",
Version: "9.0.1", Version: "9.0.1",
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeNuget, Type: packageurl.TypeNuget,
Name: "Newtonsoft.Json", Name: "Newtonsoft.Json",
@@ -313,7 +313,7 @@ func TestNewPackageURL(t *testing.T) {
Name: "8", Name: "8",
}, },
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeRPM, Type: packageurl.TypeRPM,
Namespace: "redhat", Namespace: "redhat",
@@ -351,7 +351,7 @@ func TestNewPackageURL(t *testing.T) {
Architecture: "amd64", Architecture: "amd64",
}, },
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeOCI, Type: packageurl.TypeOCI,
Namespace: "", Namespace: "",
@@ -399,7 +399,7 @@ func TestNewPackageURL(t *testing.T) {
Architecture: "amd64", Architecture: "amd64",
}, },
}, },
want: &ftypes.PackageURL{ want: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeOCI, Type: packageurl.TypeOCI,
Namespace: "", Namespace: "",
@@ -451,13 +451,13 @@ func TestFromString(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
purl string purl string
want ftypes.PackageURL want purl.PackageURL
wantErr string wantErr string
}{ }{
{ {
name: "happy path for maven", name: "happy path for maven",
purl: "pkg:maven/org.springframework/spring-core@5.0.4.RELEASE", purl: "pkg:maven/org.springframework/spring-core@5.0.4.RELEASE",
want: ftypes.PackageURL{ want: purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeMaven, Type: packageurl.TypeMaven,
Namespace: "org.springframework", Namespace: "org.springframework",
@@ -470,7 +470,7 @@ func TestFromString(t *testing.T) {
{ {
name: "happy path for npm", name: "happy path for npm",
purl: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json", purl: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json",
want: ftypes.PackageURL{ want: purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeNPM, Type: packageurl.TypeNPM,
Name: "bootstrap", Name: "bootstrap",
@@ -482,7 +482,7 @@ func TestFromString(t *testing.T) {
{ {
name: "happy path for coocapods", name: "happy path for coocapods",
purl: "pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib", purl: "pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib",
want: ftypes.PackageURL{ want: purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeCocoapods, Type: packageurl.TypeCocoapods,
Name: "GoogleUtilities", Name: "GoogleUtilities",
@@ -494,7 +494,7 @@ func TestFromString(t *testing.T) {
{ {
name: "happy path for hex", name: "happy path for hex",
purl: "pkg:hex/plug@1.14.0", purl: "pkg:hex/plug@1.14.0",
want: ftypes.PackageURL{ want: purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeHex, Type: packageurl.TypeHex,
Name: "plug", Name: "plug",
@@ -505,7 +505,7 @@ func TestFromString(t *testing.T) {
{ {
name: "happy path for dart", name: "happy path for dart",
purl: "pkg:pub/http@0.13.2", purl: "pkg:pub/http@0.13.2",
want: ftypes.PackageURL{ want: purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypePub, Type: packageurl.TypePub,
Name: "http", Name: "http",
@@ -516,7 +516,7 @@ func TestFromString(t *testing.T) {
{ {
name: "happy path for apk", name: "happy path for apk",
purl: "pkg:apk/alpine/alpine-baselayout@3.2.0-r16?distro=3.14.2&epoch=1", purl: "pkg:apk/alpine/alpine-baselayout@3.2.0-r16?distro=3.14.2&epoch=1",
want: ftypes.PackageURL{ want: purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: string(analyzer.TypeApk), Type: string(analyzer.TypeApk),
Namespace: "alpine", Namespace: "alpine",
@@ -538,7 +538,7 @@ func TestFromString(t *testing.T) {
{ {
name: "happy path for rpm", name: "happy path for rpm",
purl: "pkg:rpm/redhat/containers-common@0.1.14", purl: "pkg:rpm/redhat/containers-common@0.1.14",
want: ftypes.PackageURL{ want: purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeRPM, Type: packageurl.TypeRPM,
Namespace: "redhat", Namespace: "redhat",
@@ -550,7 +550,7 @@ func TestFromString(t *testing.T) {
{ {
name: "happy path for conda", name: "happy path for conda",
purl: "pkg:conda/absl-py@0.4.1", purl: "pkg:conda/absl-py@0.4.1",
want: ftypes.PackageURL{ want: purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeConda, Type: packageurl.TypeConda,
Name: "absl-py", Name: "absl-py",
@@ -561,7 +561,7 @@ func TestFromString(t *testing.T) {
{ {
name: "bad rpm", name: "bad rpm",
purl: "pkg:rpm/redhat/a--@1.0.0", purl: "pkg:rpm/redhat/a--@1.0.0",
want: ftypes.PackageURL{ want: purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeRPM, Type: packageurl.TypeRPM,
Namespace: "redhat", Namespace: "redhat",
@@ -585,15 +585,15 @@ func TestFromString(t *testing.T) {
} }
} }
func TestToPackage(t *testing.T) { func TestPackageURL_Package(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
pkgURL *ftypes.PackageURL pkgURL *purl.PackageURL
wantPkg *ftypes.Package wantPkg *ftypes.Package
}{ }{
{ {
name: "rpm + Qualifiers", name: "rpm + Qualifiers",
pkgURL: &ftypes.PackageURL{ pkgURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeRPM, Type: packageurl.TypeRPM,
Namespace: "redhat", Namespace: "redhat",
@@ -626,26 +626,60 @@ func TestToPackage(t *testing.T) {
Arch: "x86_64", Arch: "x86_64",
Epoch: 1, Epoch: 1,
Modularitylabel: "nodejs:10:8020020200707141642:6a468ee4", Modularitylabel: "nodejs:10:8020020200707141642:6a468ee4",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeRPM,
Namespace: "redhat",
Name: "nodejs-full-i18n",
Version: "10.21.0-3.module_el8.2.0+391+8da3adc6",
Qualifiers: packageurl.Qualifiers{
{
Key: "arch",
Value: "x86_64",
},
{
Key: "epoch",
Value: "1",
},
{
Key: "modularitylabel",
Value: "nodejs:10:8020020200707141642:6a468ee4",
},
{
Key: "distro",
Value: "redhat-8",
},
},
},
},
}, },
}, },
{ {
name: "composer with namespace", name: "composer with namespace",
pkgURL: &ftypes.PackageURL{ pkgURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeComposer, Type: packageurl.TypeComposer,
Namespace: "symfony", Namespace: "symfony",
Name: "contracts", Name: "contracts",
Version: "v1.0.2", Version: "1.0.2",
}, },
}, },
wantPkg: &ftypes.Package{ wantPkg: &ftypes.Package{
Name: "symfony/contracts", Name: "symfony/contracts",
Version: "v1.0.2", Version: "1.0.2",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeComposer,
Namespace: "symfony",
Name: "contracts",
Version: "1.0.2",
},
},
}, },
}, },
{ {
name: "maven with namespace", name: "maven with namespace",
pkgURL: &ftypes.PackageURL{ pkgURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeMaven, Type: packageurl.TypeMaven,
Namespace: "org.springframework", Namespace: "org.springframework",
@@ -656,11 +690,19 @@ func TestToPackage(t *testing.T) {
wantPkg: &ftypes.Package{ wantPkg: &ftypes.Package{
Name: "org.springframework:spring-core", Name: "org.springframework:spring-core",
Version: "5.0.4.RELEASE", Version: "5.0.4.RELEASE",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeMaven,
Namespace: "org.springframework",
Name: "spring-core",
Version: "5.0.4.RELEASE",
},
},
}, },
}, },
{ {
name: "cocoapods with subpath", name: "cocoapods with subpath",
pkgURL: &ftypes.PackageURL{ pkgURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeCocoapods, Type: packageurl.TypeCocoapods,
Version: "4.2.0", Version: "4.2.0",
@@ -671,11 +713,19 @@ func TestToPackage(t *testing.T) {
wantPkg: &ftypes.Package{ wantPkg: &ftypes.Package{
Name: "AppCenter/Analytics", Name: "AppCenter/Analytics",
Version: "4.2.0", Version: "4.2.0",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeCocoapods,
Version: "4.2.0",
Name: "AppCenter",
Subpath: "Analytics",
},
},
}, },
}, },
{ {
name: "wrong epoch", name: "wrong epoch",
pkgURL: &ftypes.PackageURL{ pkgURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: packageurl.TypeRPM, Type: packageurl.TypeRPM,
Namespace: "redhat", Namespace: "redhat",
@@ -693,19 +743,33 @@ func TestToPackage(t *testing.T) {
Name: "acl", Name: "acl",
Version: "2.2.53", Version: "2.2.53",
Release: "1.el8", Release: "1.el8",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeRPM,
Namespace: "redhat",
Name: "acl",
Version: "2.2.53-1.el8",
Qualifiers: packageurl.Qualifiers{
{
Key: "epoch",
Value: "wrong",
},
},
},
},
}, },
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got := purl.ToPackage(tt.pkgURL) got := tt.pkgURL.Package()
assert.Equal(t, tt.wantPkg, got) assert.Equal(t, tt.wantPkg, got)
}) })
} }
} }
func TestLangType(t *testing.T) { func TestPackageURL_LangType(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
purl packageurl.PackageURL purl packageurl.PackageURL
@@ -743,8 +807,77 @@ func TestLangType(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
p := &ftypes.PackageURL{PackageURL: tt.purl} p := &purl.PackageURL{PackageURL: tt.purl}
assert.Equalf(t, tt.want, purl.LangType(p), "LangType()") assert.Equalf(t, tt.want, p.LangType(), "LangType()")
})
}
}
func TestPackageURL_Match(t *testing.T) {
tests := []struct {
name string
constraint string
target string
want bool
}{
{
name: "same purl",
constraint: "pkg:golang/github.com/aquasecurity/trivy@0.49.0",
target: "pkg:golang/github.com/aquasecurity/trivy@0.49.0",
want: true,
},
{
name: "different type",
constraint: "pkg:golang/github.com/aquasecurity/trivy@0.49.0",
target: "pkg:maven/github.com/aquasecurity/trivy@0.49.0",
want: false,
},
{
name: "different namespace",
constraint: "pkg:golang/github.com/aquasecurity/trivy@0.49.0",
target: "pkg:golang/github.com/aquasecurity2/trivy@0.49.0",
want: false,
},
{
name: "different name",
constraint: "pkg:golang/github.com/aquasecurity/trivy@0.49.0",
target: "pkg:golang/github.com/aquasecurity/tracee@0.49.0",
want: false,
},
{
name: "different version",
constraint: "pkg:golang/github.com/aquasecurity/trivy@0.49.0",
target: "pkg:golang/github.com/aquasecurity/trivy@0.49.1",
want: false,
},
{
name: "version wildcard",
constraint: "pkg:golang/github.com/aquasecurity/trivy",
target: "pkg:golang/github.com/aquasecurity/trivy@0.50.0",
want: true,
},
{
name: "different qualifier",
constraint: "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-12",
target: "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-13",
want: false,
},
{
name: "target more qualifiers",
constraint: "pkg:bitnami/wordpress@6.2.0?arch=arm64",
target: "pkg:bitnami/wordpress@6.2.0?arch=arm64&distro=debian-13",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c, err := purl.FromString(tt.constraint)
require.NoError(t, err)
p, err := purl.FromString(tt.target)
require.NoError(t, err)
assert.Equalf(t, tt.want, c.Match(p.Unwrap()), "Match()")
}) })
} }
} }

View File

@@ -154,13 +154,11 @@ func TestFilter(t *testing.T) {
VulnerabilityID: "CVE-2019-0001", VulnerabilityID: "CVE-2019-0001",
PkgName: "foo", PkgName: "foo",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "github.com/aquasecurity",
Namespace: "github.com/aquasecurity", Name: "foo",
Name: "foo", Version: "1.2.3",
Version: "1.2.3",
},
}, },
}, },
InstalledVersion: "1.2.3", InstalledVersion: "1.2.3",
@@ -173,13 +171,11 @@ func TestFilter(t *testing.T) {
VulnerabilityID: "CVE-2019-0001", VulnerabilityID: "CVE-2019-0001",
PkgName: "bar", PkgName: "bar",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "github.com/aquasecurity",
Namespace: "github.com/aquasecurity", Name: "bar",
Name: "bar", Version: "4.5.6",
Version: "4.5.6",
},
}, },
}, },
InstalledVersion: "4.5.6", InstalledVersion: "4.5.6",
@@ -209,13 +205,11 @@ func TestFilter(t *testing.T) {
VulnerabilityID: "CVE-2019-0001", VulnerabilityID: "CVE-2019-0001",
PkgName: "bar", PkgName: "bar",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "github.com/aquasecurity",
Namespace: "github.com/aquasecurity", Name: "bar",
Name: "bar", Version: "4.5.6",
Version: "4.5.6",
},
}, },
}, },
InstalledVersion: "4.5.6", InstalledVersion: "4.5.6",

View File

@@ -3,6 +3,7 @@ package rpc
import ( import (
"time" "time"
"github.com/package-url/packageurl-go"
"github.com/samber/lo" "github.com/samber/lo"
"google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
@@ -11,7 +12,6 @@ import (
"github.com/aquasecurity/trivy/pkg/digest" "github.com/aquasecurity/trivy/pkg/digest"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/purl"
"github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/rpc/cache" "github.com/aquasecurity/trivy/rpc/cache"
"github.com/aquasecurity/trivy/rpc/common" "github.com/aquasecurity/trivy/rpc/common"
@@ -82,7 +82,7 @@ func ConvertToRPCPkgIdentifier(pkg ftypes.PkgIdentifier) *common.PkgIdentifier {
var p string var p string
if pkg.PURL != nil { if pkg.PURL != nil {
p = pkg.PURL.BOMRef() // Use BOMRef() instead of String() so that we won't lose file_path p = pkg.PURL.String()
} }
return &common.PkgIdentifier{ return &common.PkgIdentifier{
Purl: p, Purl: p,
@@ -227,11 +227,11 @@ func ConvertFromRPCPkgIdentifier(pkg *common.PkgIdentifier) ftypes.PkgIdentifier
} }
if pkg.Purl != "" { if pkg.Purl != "" {
pu, err := purl.FromString(pkg.Purl) pu, err := packageurl.FromString(pkg.Purl)
if err != nil { if err != nil {
log.Logger.Error("Failed to parse PURL (%s): %s", pkg.Purl, err) log.Logger.Error("Failed to parse PURL (%s): %s", pkg.Purl, err)
} }
pkgID.PURL = pu pkgID.PURL = &pu
} }
return pkgID return pkgID

View File

@@ -15,8 +15,8 @@ import (
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability" "github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
"github.com/aquasecurity/trivy/pkg/clock" "github.com/aquasecurity/trivy/pkg/clock"
"github.com/aquasecurity/trivy/pkg/digest" "github.com/aquasecurity/trivy/pkg/digest"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/purl"
"github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/types"
"github.com/aquasecurity/trivy/pkg/uuid" "github.com/aquasecurity/trivy/pkg/uuid"
) )
@@ -39,7 +39,7 @@ type Component struct {
Name string Name string
Group string Group string
Version string Version string
PackageURL *ftypes.PackageURL PackageURL *purl.PackageURL
Licenses []string Licenses []string
Hashes []digest.Digest Hashes []digest.Digest
Supplier string Supplier string
@@ -232,7 +232,7 @@ func (c *CycloneDX) Vulnerabilities(uniq map[string]*cdx.Vulnerability) *[]cdx.V
return &vulns return &vulns
} }
func (c *CycloneDX) PackageURL(p *ftypes.PackageURL) string { func (c *CycloneDX) PackageURL(p *purl.PackageURL) string {
if p == nil { if p == nil {
return "" return ""
} }

View File

@@ -2,6 +2,7 @@ package core_test
import ( import (
"context" "context"
"github.com/aquasecurity/trivy/pkg/purl"
"testing" "testing"
"time" "time"
@@ -11,7 +12,6 @@ import (
"github.com/aquasecurity/trivy/pkg/clock" "github.com/aquasecurity/trivy/pkg/clock"
"github.com/aquasecurity/trivy/pkg/digest" "github.com/aquasecurity/trivy/pkg/digest"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core" "github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
"github.com/aquasecurity/trivy/pkg/uuid" "github.com/aquasecurity/trivy/pkg/uuid"
) )
@@ -43,7 +43,7 @@ func TestMarshaler_CoreComponent(t *testing.T) {
Type: cdx.ComponentTypeContainer, Type: cdx.ComponentTypeContainer,
Name: "k8s.gcr.io/kube-apiserver", Name: "k8s.gcr.io/kube-apiserver",
Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f", Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
PackageURL: &ftypes.PackageURL{ PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: "oci", Type: "oci",
Name: "kube-apiserver", Name: "kube-apiserver",
@@ -138,7 +138,7 @@ func TestMarshaler_CoreComponent(t *testing.T) {
Value: "golang", Value: "golang",
}, },
}, },
PackageURL: &ftypes.PackageURL{ PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: "golang", Type: "golang",
Name: "kubelet", Name: "kubelet",
@@ -157,7 +157,7 @@ func TestMarshaler_CoreComponent(t *testing.T) {
Value: "golang", Value: "golang",
}, },
}, },
PackageURL: &ftypes.PackageURL{ PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{ PackageURL: packageurl.PackageURL{
Type: "golang", Type: "golang",
Name: "containerd", Name: "containerd",

View File

@@ -378,7 +378,7 @@ func pkgComponent(pkg Package) (*core.Component, error) {
Name: name, Name: name,
Group: group, Group: group,
Version: version, Version: version,
PackageURL: pkg.Identifier.PURL, PackageURL: purl.WithPath(pkg.Identifier.PURL, pkg.FilePath),
Supplier: pkg.Maintainer, Supplier: pkg.Maintainer,
Licenses: pkg.Licenses, Licenses: pkg.Licenses,
Hashes: lo.Ternary(pkg.Digest == "", nil, []digest.Digest{pkg.Digest}), Hashes: lo.Ternary(pkg.Digest == "", nil, []digest.Digest{pkg.Digest}),

View File

@@ -63,21 +63,19 @@ func TestMarshaler_Marshal(t *testing.T) {
Epoch: 0, Epoch: 0,
Arch: "aarch64", Arch: "aarch64",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM,
Type: packageurl.TypeRPM, Namespace: "centos",
Namespace: "centos", Name: "binutils",
Name: "binutils", Version: "2.30-93.el8",
Version: "2.30-93.el8", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "arch",
Key: "arch", Value: "aarch64",
Value: "aarch64", },
}, {
{ Key: "distro",
Key: "distro", Value: "centos-8.3.2011",
Value: "centos-8.3.2011",
},
}, },
}, },
}, },
@@ -145,12 +143,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actionpack", Name: "actionpack",
Version: "7.0.0", Version: "7.0.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actionpack",
Name: "actionpack", Version: "7.0.0",
Version: "7.0.0",
},
}, },
}, },
Indirect: false, Indirect: false,
@@ -160,12 +156,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actioncontroller", Name: "actioncontroller",
Version: "7.0.0", Version: "7.0.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actioncontroller",
Name: "actioncontroller", Version: "7.0.0",
Version: "7.0.0",
},
}, },
}, },
Indirect: false, Indirect: false,
@@ -185,12 +179,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actionpack", Name: "actionpack",
Version: "7.0.0", Version: "7.0.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actionpack",
Name: "actionpack", Version: "7.0.0",
Version: "7.0.0",
},
}, },
}, },
}, },
@@ -206,12 +198,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "Newtonsoft.Json", Name: "Newtonsoft.Json",
Version: "9.0.1", Version: "9.0.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNuget,
Type: packageurl.TypeNuget, Name: "Newtonsoft.Json",
Name: "Newtonsoft.Json", Version: "9.0.1",
Version: "9.0.1",
},
}, },
}, },
}, },
@@ -226,13 +216,11 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "golang.org/x/crypto", Name: "golang.org/x/crypto",
Version: "v0.0.0-20210421170649-83a5a9bb288b", Version: "v0.0.0-20210421170649-83a5a9bb288b",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "golang.org/x",
Namespace: "golang.org/x", Name: "crypto",
Name: "crypto", Version: "v0.0.0-20210421170649-83a5a9bb288b",
Version: "v0.0.0-20210421170649-83a5a9bb288b",
},
}, },
}, },
}, },
@@ -667,25 +655,23 @@ func TestMarshaler_Marshal(t *testing.T) {
Epoch: 1, Epoch: 1,
Arch: "aarch64", Arch: "aarch64",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM,
Type: packageurl.TypeRPM, Namespace: "centos",
Namespace: "centos", Name: "acl",
Name: "acl", Version: "2.2.53-1.el8",
Version: "2.2.53-1.el8", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "arch",
Key: "arch", Value: "aarch64",
Value: "aarch64", },
}, {
{ Key: "distro",
Key: "distro", Value: "centos-8.3.2011",
Value: "centos-8.3.2011", },
}, {
{ Key: "epoch",
Key: "epoch", Value: "1",
Value: "1",
},
}, },
}, },
}, },
@@ -709,21 +695,19 @@ func TestMarshaler_Marshal(t *testing.T) {
Epoch: 0, Epoch: 0,
Arch: "aarch64", Arch: "aarch64",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM,
Type: packageurl.TypeRPM, Namespace: "centos",
Namespace: "centos", Name: "glibc",
Name: "glibc", Version: "2.28-151.el8",
Version: "2.28-151.el8", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "arch",
Key: "arch", Value: "aarch64",
Value: "aarch64", },
}, {
{ Key: "distro",
Key: "distro", Value: "centos-8.3.2011",
Value: "centos-8.3.2011",
},
}, },
}, },
}, },
@@ -748,13 +732,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actionpack", Name: "actionpack",
Version: "7.0.0", Version: "7.0.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actionpack",
Name: "actionpack", Version: "7.0.0",
Version: "7.0.0",
},
FilePath: "tools/project-john/specifications/actionpack.gemspec",
}, },
}, },
Layer: ftypes.Layer{ Layer: ftypes.Layer{
@@ -767,13 +748,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actionpack", Name: "actionpack",
Version: "7.0.1", Version: "7.0.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actionpack",
Name: "actionpack", Version: "7.0.1",
Version: "7.0.1",
},
FilePath: "tools/project-doe/specifications/actionpack.gemspec",
}, },
}, },
Layer: ftypes.Layer{ Layer: ftypes.Layer{
@@ -789,12 +767,10 @@ func TestMarshaler_Marshal(t *testing.T) {
PkgName: "actionpack", PkgName: "actionpack",
PkgPath: "tools/project-john/specifications/actionpack.gemspec", PkgPath: "tools/project-john/specifications/actionpack.gemspec",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actionpack",
Name: "actionpack", Version: "7.0.0",
Version: "7.0.0",
},
}, },
}, },
InstalledVersion: "7.0.0", InstalledVersion: "7.0.0",
@@ -841,12 +817,10 @@ func TestMarshaler_Marshal(t *testing.T) {
PkgName: "actionpack", PkgName: "actionpack",
PkgPath: "tools/project-doe/specifications/actionpack.gemspec", PkgPath: "tools/project-doe/specifications/actionpack.gemspec",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actionpack",
Name: "actionpack", Version: "7.0.1",
Version: "7.0.1",
},
}, },
}, },
InstalledVersion: "7.0.1", InstalledVersion: "7.0.1",
@@ -1221,12 +1195,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actioncable", Name: "actioncable",
Version: "6.1.4.1", Version: "6.1.4.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actioncable",
Name: "actioncable", Version: "6.1.4.1",
Version: "6.1.4.1",
},
}, },
}, },
}, },
@@ -1241,14 +1213,11 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "org.springframework:spring-web", Name: "org.springframework:spring-web",
Version: "5.3.22", Version: "5.3.22",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.springframework",
Namespace: "org.springframework", Name: "spring-web",
Name: "spring-web", Version: "5.3.22",
Version: "5.3.22",
},
FilePath: "spring-web-5.3.22.jar",
}, },
}, },
FilePath: "spring-web-5.3.22.jar", FilePath: "spring-web-5.3.22.jar",
@@ -1375,14 +1344,11 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "org.apache.nifi:nifi-dbcp-base", Name: "org.apache.nifi:nifi-dbcp-base",
Version: "1.20.0", Version: "1.20.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.apache.nifi",
Namespace: "org.apache.nifi", Name: "nifi-dbcp-base",
Name: "nifi-dbcp-base", Version: "1.20.0",
Version: "1.20.0",
},
FilePath: "nifi-dbcp-base-1.20.0.jar",
}, },
}, },
FilePath: "nifi-dbcp-base-1.20.0.jar", FilePath: "nifi-dbcp-base-1.20.0.jar",
@@ -1391,14 +1357,11 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "org.apache.nifi:nifi-hikari-dbcp-service", Name: "org.apache.nifi:nifi-hikari-dbcp-service",
Version: "1.20.0", Version: "1.20.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.apache.nifi",
Namespace: "org.apache.nifi", Name: "nifi-hikari-dbcp-service",
Name: "nifi-hikari-dbcp-service", Version: "1.20.0",
Version: "1.20.0",
},
FilePath: "nifi-hikari-dbcp-service-1.20.0.jar",
}, },
}, },
FilePath: "nifi-hikari-dbcp-service-1.20.0.jar", FilePath: "nifi-hikari-dbcp-service-1.20.0.jar",
@@ -1410,13 +1373,11 @@ func TestMarshaler_Marshal(t *testing.T) {
PkgName: "org.apache.nifi:nifi-dbcp-base", PkgName: "org.apache.nifi:nifi-dbcp-base",
PkgPath: "nifi-dbcp-base-1.20.0.jar", PkgPath: "nifi-dbcp-base-1.20.0.jar",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.apache.nifi",
Namespace: "org.apache.nifi", Name: "nifi-dbcp-base",
Name: "nifi-dbcp-base", Version: "1.20.0",
Version: "1.20.0",
},
}, },
}, },
InstalledVersion: "1.20.0", InstalledVersion: "1.20.0",
@@ -1462,13 +1423,11 @@ func TestMarshaler_Marshal(t *testing.T) {
PkgName: "org.apache.nifi:nifi-hikari-dbcp-service", PkgName: "org.apache.nifi:nifi-hikari-dbcp-service",
PkgPath: "nifi-hikari-dbcp-service-1.20.0.jar", PkgPath: "nifi-hikari-dbcp-service-1.20.0.jar",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.apache.nifi",
Namespace: "org.apache.nifi", Name: "nifi-hikari-dbcp-service",
Name: "nifi-hikari-dbcp-service", Version: "1.20.0",
Version: "1.20.0",
},
}, },
}, },
InstalledVersion: "1.20.0", InstalledVersion: "1.20.0",
@@ -1680,13 +1639,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "ruby-typeprof", Name: "ruby-typeprof",
Version: "0.20.1", Version: "0.20.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM,
Type: packageurl.TypeNPM, Name: "ruby-typeprof",
Name: "ruby-typeprof", Version: "0.20.1",
Version: "0.20.1",
},
FilePath: "usr/local/lib/ruby/gems/3.1.0/gems/typeprof-0.21.1/vscode/package.json",
}, },
}, },
Licenses: []string{"MIT"}, Licenses: []string{"MIT"},

View File

@@ -202,7 +202,7 @@ func parsePkgs(components []cdx.Component, seen map[string]struct{}) ([]ftypes.P
} }
// Skip unsupported package types // Skip unsupported package types
if purl.Class(pkgURL) == types.ClassUnknown { if pkgURL.Class() == types.ClassUnknown {
continue continue
} }
pkgs = append(pkgs, *pkg) pkgs = append(pkgs, *pkg)
@@ -290,11 +290,11 @@ func aggregatePkgs(libs []cdx.Component) ([]ftypes.PackageInfo, []ftypes.Applica
return nil, nil, xerrors.Errorf("failed to parse the component: %w", err) return nil, nil, xerrors.Errorf("failed to parse the component: %w", err)
} }
switch purl.Class(pkgURL) { switch pkgURL.Class() {
case types.ClassOSPkg: case types.ClassOSPkg:
osPkgMap[pkgURL.Type] = append(osPkgMap[pkgURL.Type], *pkg) osPkgMap[pkgURL.Type] = append(osPkgMap[pkgURL.Type], *pkg)
case types.ClassLangPkg: case types.ClassLangPkg:
langType := purl.LangType(pkgURL) langType := pkgURL.LangType()
langPkgMap[langType] = append(langPkgMap[langType], *pkg) langPkgMap[langType] = append(langPkgMap[langType], *pkg)
} }
} }
@@ -337,7 +337,7 @@ func toApplication(component cdx.Component) *ftypes.Application {
} }
} }
func toPackage(component cdx.Component) (*ftypes.PackageURL, *ftypes.Package, error) { func toPackage(component cdx.Component) (*purl.PackageURL, *ftypes.Package, error) {
if component.PackageURL == "" { if component.PackageURL == "" {
log.Logger.Warnf("Skip the component (BOM-Ref: %s) as the PURL is empty", component.BOMRef) log.Logger.Warnf("Skip the component (BOM-Ref: %s) as the PURL is empty", component.BOMRef)
return nil, nil, ErrPURLEmpty return nil, nil, ErrPURLEmpty
@@ -347,7 +347,7 @@ func toPackage(component cdx.Component) (*ftypes.PackageURL, *ftypes.Package, er
return nil, nil, xerrors.Errorf("failed to parse purl: %w", err) return nil, nil, xerrors.Errorf("failed to parse purl: %w", err)
} }
pkg := purl.ToPackage(p) pkg := p.Package()
// Trivy's marshall loses case-sensitivity in PURL used in SBOM for packages (Go, Npm, PyPI), // Trivy's marshall loses case-sensitivity in PURL used in SBOM for packages (Go, Npm, PyPI),
// so we have to use an original package name // so we have to use an original package name
pkg.Name = packageName(p.Type, pkg.Name, component) pkg.Name = packageName(p.Type, pkg.Name, component)
@@ -382,12 +382,9 @@ func toPackage(component cdx.Component) (*ftypes.PackageURL, *ftypes.Package, er
if pkg.FilePath != "" { if pkg.FilePath != "" {
p.FilePath = pkg.FilePath p.FilePath = pkg.FilePath
} }
pkg.Identifier = ftypes.PkgIdentifier{ pkg.Identifier.BOMRef = component.BOMRef
PURL: p,
BOMRef: component.BOMRef,
}
if purl.Class(p) == types.ClassOSPkg { if p.Class() == types.ClassOSPkg {
fillSrcPkg(pkg) fillSrcPkg(pkg)
} }

View File

@@ -40,17 +40,15 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
SrcVersion: "1.2.3-r0", SrcVersion: "1.2.3-r0",
Licenses: []string{"MIT"}, Licenses: []string{"MIT"},
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "musl",
Name: "musl", Version: "1.2.3-r0",
Version: "1.2.3-r0", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.16.0",
Value: "3.16.0",
},
}, },
}, },
}, },
@@ -72,13 +70,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/log", Name: "pear/log",
Version: "1.13.1", Version: "1.13.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "log",
Name: "log", Version: "1.13.1",
Version: "1.13.1",
},
}, },
BOMRef: "pkg:composer/pear/log@1.13.1", BOMRef: "pkg:composer/pear/log@1.13.1",
}, },
@@ -91,13 +87,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/pear_exception", Name: "pear/pear_exception",
Version: "v1.0.0", Version: "v1.0.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "pear_exception",
Name: "pear_exception", Version: "v1.0.0",
Version: "v1.0.0",
},
}, },
BOMRef: "pkg:composer/pear/pear_exception@v1.0.0", BOMRef: "pkg:composer/pear/pear_exception@v1.0.0",
}, },
@@ -115,13 +109,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "github.com/package-url/packageurl-go", Name: "github.com/package-url/packageurl-go",
Version: "v0.1.1-0.20220203205134-d70459300c8a", Version: "v0.1.1-0.20220203205134-d70459300c8a",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "github.com/package-url",
Namespace: "github.com/package-url", Name: "packageurl-go",
Name: "packageurl-go", Version: "v0.1.1-0.20220203205134-d70459300c8a",
Version: "v0.1.1-0.20220203205134-d70459300c8a",
},
}, },
BOMRef: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", BOMRef: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a",
}, },
@@ -138,13 +130,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
{ {
Name: "com.example:example", Name: "com.example:example",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "com.example",
Namespace: "com.example", Name: "example",
Name: "example", Version: "0.0.1",
Version: "0.0.1",
},
}, },
BOMRef: "pkg:maven/com.example/example@0.0.1", BOMRef: "pkg:maven/com.example/example@0.0.1",
}, },
@@ -161,14 +151,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
{ {
Name: "org.codehaus.mojo:child-project", Name: "org.codehaus.mojo:child-project",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.codehaus.mojo",
Namespace: "org.codehaus.mojo", Name: "child-project",
Name: "child-project", Version: "1.0",
Version: "1.0",
},
FilePath: "app/maven/target/child-project-1.0.jar",
}, },
BOMRef: "pkg:maven/org.codehaus.mojo/child-project@1.0?file_path=app%2Fmaven%2Ftarget%2Fchild-project-1.0.jar", BOMRef: "pkg:maven/org.codehaus.mojo/child-project@1.0?file_path=app%2Fmaven%2Ftarget%2Fchild-project-1.0.jar",
}, },
@@ -188,13 +175,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "bootstrap", Name: "bootstrap",
Version: "5.0.2", Version: "5.0.2",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM,
Type: packageurl.TypeNPM, Name: "bootstrap",
Name: "bootstrap", Version: "5.0.2",
Version: "5.0.2",
},
FilePath: "app/app/package.json",
}, },
BOMRef: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json", BOMRef: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json",
}, },
@@ -230,12 +214,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "docker", Name: "docker",
Version: "24.0.4", Version: "24.0.4",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Name: "docker",
Name: "docker", Version: "24.0.4",
Version: "24.0.4",
},
}, },
BOMRef: "pkg:golang/docker@24.0.4", BOMRef: "pkg:golang/docker@24.0.4",
}, },
@@ -253,12 +235,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "k8s.io/apiserver", Name: "k8s.io/apiserver",
Version: "1.27.4", Version: "1.27.4",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: purl.TypeK8s,
Type: purl.TypeK8s, Name: "k8s.io/apiserver",
Name: "k8s.io/apiserver", Version: "1.27.4",
Version: "1.27.4",
},
}, },
BOMRef: "pkg:k8s/k8s.io%2Fapiserver@1.27.4", BOMRef: "pkg:k8s/k8s.io%2Fapiserver@1.27.4",
}, },
@@ -267,12 +247,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "k8s.io/controller-manager", Name: "k8s.io/controller-manager",
Version: "1.27.4", Version: "1.27.4",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: purl.TypeK8s,
Type: purl.TypeK8s, Name: "k8s.io/controller-manager",
Name: "k8s.io/controller-manager", Version: "1.27.4",
Version: "1.27.4",
},
}, },
BOMRef: "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4", BOMRef: "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4",
}, },
@@ -281,12 +259,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "k8s.io/kube-proxy", Name: "k8s.io/kube-proxy",
Version: "1.27.4", Version: "1.27.4",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: purl.TypeK8s,
Type: purl.TypeK8s, Name: "k8s.io/kube-proxy",
Name: "k8s.io/kube-proxy", Version: "1.27.4",
Version: "1.27.4",
},
}, },
BOMRef: "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4", BOMRef: "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4",
}, },
@@ -295,12 +271,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "k8s.io/kube-scheduler", Name: "k8s.io/kube-scheduler",
Version: "1.27.4", Version: "1.27.4",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: purl.TypeK8s,
Type: purl.TypeK8s, Name: "k8s.io/kube-scheduler",
Name: "k8s.io/kube-scheduler", Version: "1.27.4",
Version: "1.27.4",
},
}, },
BOMRef: "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4", BOMRef: "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4",
}, },
@@ -309,12 +283,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "k8s.io/kubelet", Name: "k8s.io/kubelet",
Version: "1.27.4", Version: "1.27.4",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: purl.TypeK8s,
Type: purl.TypeK8s, Name: "k8s.io/kubelet",
Name: "k8s.io/kubelet", Version: "1.27.4",
Version: "1.27.4",
},
}, },
BOMRef: "pkg:k8s/k8s.io%2Fkubelet@1.27.4", BOMRef: "pkg:k8s/k8s.io%2Fkubelet@1.27.4",
}, },
@@ -323,12 +295,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "k8s.io/kubernetes", Name: "k8s.io/kubernetes",
Version: "1.27.4", Version: "1.27.4",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: purl.TypeK8s,
Type: purl.TypeK8s, Name: "k8s.io/kubernetes",
Name: "k8s.io/kubernetes", Version: "1.27.4",
Version: "1.27.4",
},
}, },
BOMRef: "pkg:k8s/k8s.io%2Fkubernetes@1.27.4", BOMRef: "pkg:k8s/k8s.io%2Fkubernetes@1.27.4",
}, },
@@ -362,17 +332,15 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
"GFDL-1.3", "GFDL-1.3",
}, },
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeDebian,
Type: packageurl.TypeDebian, Namespace: "ubuntu",
Namespace: "ubuntu", Name: "libc6",
Name: "libc6", Version: "2.35-0ubuntu3.1",
Version: "2.35-0ubuntu3.1", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "ubuntu-22.04",
Value: "ubuntu-22.04",
},
}, },
}, },
}, },
@@ -393,21 +361,19 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
SrcRelease: "1", SrcRelease: "1",
SrcEpoch: 1, SrcEpoch: 1,
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeDebian,
Type: packageurl.TypeDebian, Namespace: "ubuntu",
Namespace: "ubuntu", Name: "libcrypt1",
Name: "libcrypt1", Version: "4.4.27-1",
Version: "4.4.27-1", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "ubuntu-22.04",
Value: "ubuntu-22.04", },
}, {
{ Key: "epoch",
Key: "epoch", Value: "1",
Value: "1",
},
}, },
}, },
}, },
@@ -441,17 +407,15 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
SrcVersion: "1.2.3-r0", SrcVersion: "1.2.3-r0",
Licenses: []string{"MIT"}, Licenses: []string{"MIT"},
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "musl",
Name: "musl", Version: "1.2.3-r0",
Version: "1.2.3-r0", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.16.0",
Value: "3.16.0",
},
}, },
}, },
}, },
@@ -470,13 +434,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/log", Name: "pear/log",
Version: "1.13.1", Version: "1.13.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "log",
Name: "log", Version: "1.13.1",
Version: "1.13.1",
},
}, },
BOMRef: "pkg:composer/pear/log@1.13.1", BOMRef: "pkg:composer/pear/log@1.13.1",
}, },
@@ -487,13 +449,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/pear_exception", Name: "pear/pear_exception",
Version: "v1.0.0", Version: "v1.0.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "pear_exception",
Name: "pear_exception", Version: "v1.0.0",
Version: "v1.0.0",
},
}, },
BOMRef: "pkg:composer/pear/pear_exception@v1.0.0", BOMRef: "pkg:composer/pear/pear_exception@v1.0.0",
}, },
@@ -516,13 +476,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/log", Name: "pear/log",
Version: "1.13.1", Version: "1.13.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "log",
Name: "log", Version: "1.13.1",
Version: "1.13.1",
},
}, },
BOMRef: "pkg:composer/pear/log@1.13.1", BOMRef: "pkg:composer/pear/log@1.13.1",
}, },
@@ -545,13 +503,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/log", Name: "pear/log",
Version: "1.13.1", Version: "1.13.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "log",
Name: "log", Version: "1.13.1",
Version: "1.13.1",
},
}, },
BOMRef: "pkg:composer/pear/log@1.13.1", BOMRef: "pkg:composer/pear/log@1.13.1",
}, },
@@ -561,13 +517,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/pear_exception", Name: "pear/pear_exception",
Version: "v1.0.0", Version: "v1.0.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "pear_exception",
Name: "pear_exception", Version: "v1.0.0",
Version: "v1.0.0",
},
}, },
BOMRef: "pkg:composer/pear/pear_exception@v1.0.0", BOMRef: "pkg:composer/pear/pear_exception@v1.0.0",
}, },
@@ -590,13 +544,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/core", Name: "pear/core",
Version: "1.13.1", Version: "1.13.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "core",
Name: "core", Version: "1.13.1",
Version: "1.13.1",
},
}, },
BOMRef: "pkg:composer/pear/core@1.13.1", BOMRef: "pkg:composer/pear/core@1.13.1",
}, },
@@ -605,13 +557,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/log", Name: "pear/log",
Version: "1.13.1", Version: "1.13.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "log",
Name: "log", Version: "1.13.1",
Version: "1.13.1",
},
}, },
BOMRef: "pkg:composer/pear/log@1.13.1", BOMRef: "pkg:composer/pear/log@1.13.1",
}, },
@@ -621,13 +571,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/pear_exception", Name: "pear/pear_exception",
Version: "v1.0.0", Version: "v1.0.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "pear_exception",
Name: "pear_exception", Version: "v1.0.0",
Version: "v1.0.0",
},
}, },
BOMRef: "pkg:composer/pear/pear_exception@v1.0.0", BOMRef: "pkg:composer/pear/pear_exception@v1.0.0",
}, },
@@ -649,14 +597,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "org.springframework:spring-web", Name: "org.springframework:spring-web",
Version: "5.3.22", Version: "5.3.22",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.springframework",
Namespace: "org.springframework", Name: "spring-web",
Name: "spring-web", Version: "5.3.22",
Version: "5.3.22",
},
FilePath: "spring-web-5.3.22.jar",
}, },
BOMRef: "pkg:maven/org.springframework/spring-web@5.3.22?file_path=spring-web-5.3.22.jar", BOMRef: "pkg:maven/org.springframework/spring-web@5.3.22?file_path=spring-web-5.3.22.jar",
}, },

View File

@@ -62,21 +62,19 @@ func TestMarshaler_Marshal(t *testing.T) {
Epoch: 0, Epoch: 0,
Arch: "aarch64", Arch: "aarch64",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM,
Type: packageurl.TypeRPM, Namespace: "centos",
Namespace: "centos", Name: "binutils",
Name: "binutils", Version: "2.30-93.el8",
Version: "2.30-93.el8", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "arch",
Key: "arch", Value: "aarch64",
Value: "aarch64", },
}, {
{ Key: "distro",
Key: "distro", Value: "centos-8.3.2011",
Value: "centos-8.3.2011",
},
}, },
}, },
}, },
@@ -101,12 +99,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actionpack", Name: "actionpack",
Version: "7.0.1", Version: "7.0.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actionpack",
Name: "actionpack", Version: "7.0.1",
Version: "7.0.1",
},
}, },
}, },
}, },
@@ -114,12 +110,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actioncontroller", Name: "actioncontroller",
Version: "7.0.1", Version: "7.0.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actioncontroller",
Name: "actioncontroller", Version: "7.0.1",
Version: "7.0.1",
},
}, },
}, },
}, },
@@ -134,12 +128,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actionpack", Name: "actionpack",
Version: "7.0.1", Version: "7.0.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actionpack",
Name: "actionpack", Version: "7.0.1",
Version: "7.0.1",
},
}, },
}, },
}, },
@@ -351,25 +343,23 @@ func TestMarshaler_Marshal(t *testing.T) {
Epoch: 1, Epoch: 1,
Arch: "aarch64", Arch: "aarch64",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM,
Type: packageurl.TypeRPM, Namespace: "centos",
Namespace: "centos", Name: "acl",
Name: "acl", Version: "2.2.53-1.el8",
Version: "2.2.53-1.el8", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "arch",
Key: "arch", Value: "aarch64",
Value: "aarch64", },
}, {
{ Key: "distro",
Key: "distro", Value: "centos-8.3.2011",
Value: "centos-8.3.2011", },
}, {
{ Key: "epoch",
Key: "epoch", Value: "1",
Value: "1",
},
}, },
}, },
}, },
@@ -393,12 +383,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actionpack", Name: "actionpack",
Version: "7.0.1", Version: "7.0.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actionpack",
Name: "actionpack", Version: "7.0.1",
Version: "7.0.1",
},
}, },
}, },
Layer: ftypes.Layer{ Layer: ftypes.Layer{
@@ -411,12 +399,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actionpack", Name: "actionpack",
Version: "7.0.1", Version: "7.0.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actionpack",
Name: "actionpack", Version: "7.0.1",
Version: "7.0.1",
},
}, },
}, },
Layer: ftypes.Layer{ Layer: ftypes.Layer{
@@ -634,12 +620,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "actioncable", Name: "actioncable",
Version: "6.1.4.1", Version: "6.1.4.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGem,
Type: packageurl.TypeGem, Name: "actioncable",
Name: "actioncable", Version: "6.1.4.1",
Version: "6.1.4.1",
},
}, },
}, },
}, },
@@ -736,12 +720,10 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "ruby-typeprof", Name: "ruby-typeprof",
Version: "0.20.1", Version: "0.20.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM,
Type: packageurl.TypeNPM, Name: "ruby-typeprof",
Name: "ruby-typeprof", Version: "0.20.1",
Version: "0.20.1",
},
}, },
}, },
Licenses: []string{"MIT"}, Licenses: []string{"MIT"},
@@ -976,13 +958,11 @@ func TestMarshaler_Marshal(t *testing.T) {
Name: "golang.org/x/crypto", Name: "golang.org/x/crypto",
Version: "v0.0.1", Version: "v0.0.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "golang.org/x",
Namespace: "golang.org/x", Name: "crypto",
Name: "crypto", Version: "v0.0.1",
Version: "v0.0.1",
},
}, },
}, },
}, },

View File

@@ -177,12 +177,12 @@ func (s *SPDX) parsePackages(pkgs map[common.ElementID]*spdx.Package) error {
} else if err != nil { } else if err != nil {
return xerrors.Errorf("failed to parse package: %w", err) return xerrors.Errorf("failed to parse package: %w", err)
} }
switch purl.Class(pkgURL) { switch pkgURL.Class() {
case types.ClassOSPkg: case types.ClassOSPkg:
osPkgs = append(osPkgs, *pkg) osPkgs = append(osPkgs, *pkg)
case types.ClassLangPkg: case types.ClassLangPkg:
// Language-specific packages // Language-specific packages
pkgType := purl.LangType(pkgURL) pkgType := pkgURL.LangType()
app, ok := apps[pkgType] app, ok := apps[pkgType]
if !ok { if !ok {
app.Type = pkgType app.Type = pkgType
@@ -246,12 +246,13 @@ func parseOS(pkg spdx.Package) ftypes.OS {
} }
} }
func parsePkg(spdxPkg spdx.Package, packageFilePaths map[string]string) (*ftypes.Package, *ftypes.PackageURL, error) { func parsePkg(spdxPkg spdx.Package, packageFilePaths map[string]string) (*ftypes.Package, *purl.PackageURL, error) {
pkg, pkgURL, err := parseExternalReferences(spdxPkg.PackageExternalReferences) pkgURL, err := parseExternalReferences(spdxPkg.PackageExternalReferences)
if err != nil { if err != nil {
return nil, nil, xerrors.Errorf("external references error: %w", err) return nil, nil, xerrors.Errorf("external references error: %w", err)
} }
pkg := pkgURL.Package()
if spdxPkg.PackageLicenseDeclared != "NONE" { if spdxPkg.PackageLicenseDeclared != "NONE" {
pkg.Licenses = strings.Split(spdxPkg.PackageLicenseDeclared, ",") pkg.Licenses = strings.Split(spdxPkg.PackageLicenseDeclared, ",")
} }
@@ -278,7 +279,7 @@ func parsePkg(spdxPkg spdx.Package, packageFilePaths map[string]string) (*ftypes
return pkg, pkgURL, nil return pkg, pkgURL, nil
} }
func parseExternalReferences(refs []*spdx.PackageExternalReference) (*ftypes.Package, *ftypes.PackageURL, error) { func parseExternalReferences(refs []*spdx.PackageExternalReference) (*purl.PackageURL, error) {
for _, ref := range refs { for _, ref := range refs {
// Extract the package information from PURL // Extract the package information from PURL
if ref.RefType != RefTypePurl || ref.Category != CategoryPackageManager { if ref.RefType != RefTypePurl || ref.Category != CategoryPackageManager {
@@ -287,15 +288,11 @@ func parseExternalReferences(refs []*spdx.PackageExternalReference) (*ftypes.Pac
packageURL, err := purl.FromString(ref.Locator) packageURL, err := purl.FromString(ref.Locator)
if err != nil { if err != nil {
return nil, nil, xerrors.Errorf("failed to parse purl from string: %w", err) return nil, xerrors.Errorf("failed to parse purl from string: %w", err)
} }
pkg := purl.ToPackage(packageURL) return packageURL, nil
pkg.Identifier = ftypes.PkgIdentifier{
PURL: packageURL,
}
return pkg, packageURL, nil
} }
return nil, nil, errUnknownPackageFormat return nil, errUnknownPackageFormat
} }
func lookupAttributionTexts(attributionTexts []string, key string) string { func lookupAttributionTexts(attributionTexts []string, key string) string {

View File

@@ -40,17 +40,15 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
SrcVersion: "1.2.3-r0", SrcVersion: "1.2.3-r0",
Licenses: []string{"MIT"}, Licenses: []string{"MIT"},
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeApk,
Type: packageurl.TypeApk, Namespace: "alpine",
Namespace: "alpine", Name: "musl",
Name: "musl", Version: "1.2.3-r0",
Version: "1.2.3-r0", Qualifiers: packageurl.Qualifiers{
Qualifiers: packageurl.Qualifiers{ {
{ Key: "distro",
Key: "distro", Value: "3.16.0",
Value: "3.16.0",
},
}, },
}, },
}, },
@@ -71,13 +69,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/log", Name: "pear/log",
Version: "1.13.1", Version: "1.13.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "log",
Name: "log", Version: "1.13.1",
Version: "1.13.1",
},
}, },
}, },
Layer: ftypes.Layer{ Layer: ftypes.Layer{
@@ -89,13 +85,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/pear_exception", Name: "pear/pear_exception",
Version: "v1.0.0", Version: "v1.0.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "pear_exception",
Name: "pear_exception", Version: "v1.0.0",
Version: "v1.0.0",
},
}, },
}, },
Layer: ftypes.Layer{ Layer: ftypes.Layer{
@@ -112,13 +106,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "github.com/package-url/packageurl-go", Name: "github.com/package-url/packageurl-go",
Version: "v0.1.1-0.20220203205134-d70459300c8a", Version: "v0.1.1-0.20220203205134-d70459300c8a",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang,
Type: packageurl.TypeGolang, Namespace: "github.com/package-url",
Namespace: "github.com/package-url", Name: "packageurl-go",
Name: "packageurl-go", Version: "v0.1.1-0.20220203205134-d70459300c8a",
Version: "v0.1.1-0.20220203205134-d70459300c8a",
},
}, },
}, },
Layer: ftypes.Layer{ Layer: ftypes.Layer{
@@ -133,13 +125,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
{ {
Name: "org.codehaus.mojo:child-project", Name: "org.codehaus.mojo:child-project",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.codehaus.mojo",
Namespace: "org.codehaus.mojo", Name: "child-project",
Name: "child-project", Version: "1.0",
Version: "1.0",
},
}, },
}, },
Version: "1.0", Version: "1.0",
@@ -156,12 +146,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "bootstrap", Name: "bootstrap",
Version: "5.0.2", Version: "5.0.2",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM,
Type: packageurl.TypeNPM, Name: "bootstrap",
Name: "bootstrap", Version: "5.0.2",
Version: "5.0.2",
},
}, },
}, },
Licenses: []string{"MIT"}, Licenses: []string{"MIT"},
@@ -188,12 +176,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Version: "21.1.1", Version: "21.1.1",
Licenses: []string{"ISC"}, Licenses: []string{"ISC"},
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM,
Type: packageurl.TypeNPM, Name: "yargs-parser",
Name: "yargs-parser", Version: "21.1.1",
Version: "21.1.1",
},
}, },
}, },
FilePath: "node_modules/yargs-parser/package.json", FilePath: "node_modules/yargs-parser/package.json",
@@ -217,12 +203,10 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Version: "21.1.1", Version: "21.1.1",
Licenses: []string{"ISC"}, Licenses: []string{"ISC"},
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM,
Type: packageurl.TypeNPM, Name: "yargs-parser",
Name: "yargs-parser", Version: "21.1.1",
Version: "21.1.1",
},
}, },
}, },
FilePath: "node_modules/yargs-parser/package.json", FilePath: "node_modules/yargs-parser/package.json",
@@ -245,13 +229,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/log", Name: "pear/log",
Version: "1.13.1", Version: "1.13.1",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "log",
Name: "log", Version: "1.13.1",
Version: "1.13.1",
},
}, },
}, },
}, },
@@ -260,13 +242,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "pear/pear_exception", Name: "pear/pear_exception",
Version: "v1.0.0", Version: "v1.0.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer,
Type: packageurl.TypeComposer, Namespace: "pear",
Namespace: "pear", Name: "pear_exception",
Name: "pear_exception", Version: "v1.0.0",
Version: "v1.0.0",
},
}, },
}, },
}, },
@@ -288,13 +268,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "co.elastic.apm:apm-agent", Name: "co.elastic.apm:apm-agent",
Version: "1.36.0", Version: "1.36.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "co.elastic.apm",
Namespace: "co.elastic.apm", Name: "apm-agent",
Name: "apm-agent", Version: "1.36.0",
Version: "1.36.0",
},
}, },
}, },
}, },
@@ -303,13 +281,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
Name: "co.elastic.apm:apm-agent-cached-lookup-key", Name: "co.elastic.apm:apm-agent-cached-lookup-key",
Version: "1.36.0", Version: "1.36.0",
Identifier: ftypes.PkgIdentifier{ Identifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "co.elastic.apm",
Namespace: "co.elastic.apm", Name: "apm-agent-cached-lookup-key",
Name: "apm-agent-cached-lookup-key", Version: "1.36.0",
Version: "1.36.0",
},
}, },
}, },
}, },

View File

@@ -2,12 +2,12 @@ package vex
import ( import (
csaf "github.com/csaf-poc/csaf_distribution/v3/csaf" csaf "github.com/csaf-poc/csaf_distribution/v3/csaf"
"github.com/package-url/packageurl-go"
"github.com/samber/lo" "github.com/samber/lo"
"go.uber.org/zap" "go.uber.org/zap"
"golang.org/x/exp/slices"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/purl"
"github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/types"
) )
@@ -36,16 +36,16 @@ func (v *CSAF) Filter(vulns []types.DetectedVulnerability) []types.DetectedVulne
}) })
} }
func (v *CSAF) affected(vuln *csaf.Vulnerability, purl *ftypes.PackageURL) bool { func (v *CSAF) affected(vuln *csaf.Vulnerability, pkgURL *packageurl.PackageURL) bool {
if purl == nil || vuln.ProductStatus == nil { if pkgURL == nil || vuln.ProductStatus == nil {
return true return true
} }
var status Status var status Status
switch { switch {
case v.matchPURL(purl, vuln.ProductStatus.KnownNotAffected): case v.matchPURL(vuln.ProductStatus.KnownNotAffected, pkgURL):
status = StatusNotAffected status = StatusNotAffected
case v.matchPURL(purl, vuln.ProductStatus.Fixed): case v.matchPURL(vuln.ProductStatus.Fixed, pkgURL):
status = StatusFixed status = StatusFixed
} }
@@ -60,17 +60,24 @@ func (v *CSAF) affected(vuln *csaf.Vulnerability, purl *ftypes.PackageURL) bool
} }
// matchPURL returns true if the given PackageURL is found in the ProductTree. // matchPURL returns true if the given PackageURL is found in the ProductTree.
func (v *CSAF) matchPURL(purl *ftypes.PackageURL, products *csaf.Products) bool { func (v *CSAF) matchPURL(products *csaf.Products, pkgURL *packageurl.PackageURL) bool {
for _, product := range lo.FromPtr(products) { for _, product := range lo.FromPtr(products) {
helpers := v.advisory.ProductTree.CollectProductIdentificationHelpers(lo.FromPtr(product)) helpers := v.advisory.ProductTree.CollectProductIdentificationHelpers(lo.FromPtr(product))
purls := lo.FilterMap(helpers, func(helper *csaf.ProductIdentificationHelper, _ int) (string, bool) { purls := lo.FilterMap(helpers, func(helper *csaf.ProductIdentificationHelper, _ int) (*purl.PackageURL, bool) {
if helper == nil || helper.PURL == nil { if helper == nil || helper.PURL == nil {
return "", false return nil, false
} }
return string(*helper.PURL), true p, err := purl.FromString(string(*helper.PURL))
if err != nil {
v.logger.Errorw("Invalid PURL", zap.String("purl", string(*helper.PURL)), zap.Error(err))
return nil, false
}
return p, true
}) })
if slices.Contains(purls, purl.String()) { for _, p := range purls {
return true if p.Match(pkgURL) {
return true
}
} }
} }

View File

@@ -47,13 +47,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "spring-boot", PkgName: "spring-boot",
InstalledVersion: "2.6.0", InstalledVersion: "2.6.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.springframework.boot",
Namespace: "org.springframework.boot", Name: "spring-boot",
Name: "spring-boot", Version: "2.6.0",
Version: "2.6.0",
},
}, },
}, },
}, },
@@ -73,13 +71,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "spring-boot", PkgName: "spring-boot",
InstalledVersion: "2.6.0", InstalledVersion: "2.6.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.springframework.boot",
Namespace: "org.springframework.boot", Name: "spring-boot",
Name: "spring-boot", Version: "2.6.0",
Version: "2.6.0",
},
}, },
}, },
}, },
@@ -88,13 +84,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "spring-boot", PkgName: "spring-boot",
InstalledVersion: "2.6.0", InstalledVersion: "2.6.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.springframework.boot",
Namespace: "org.springframework.boot", Name: "spring-boot",
Name: "spring-boot", Version: "2.6.0",
Version: "2.6.0",
},
}, },
}, },
}, },
@@ -106,13 +100,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "spring-boot", PkgName: "spring-boot",
InstalledVersion: "2.6.0", InstalledVersion: "2.6.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.springframework.boot",
Namespace: "org.springframework.boot", Name: "spring-boot",
Name: "spring-boot", Version: "2.6.0",
Version: "2.6.0",
},
}, },
}, },
}, },
@@ -136,13 +128,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "jackson-databind", PkgName: "jackson-databind",
InstalledVersion: "2.8.0", InstalledVersion: "2.8.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "com.fasterxml.jackson.core",
Namespace: "com.fasterxml.jackson.core", Name: "jackson-databind",
Name: "jackson-databind", Version: "2.8.0",
Version: "2.8.0",
},
}, },
}, },
}, },
@@ -151,13 +141,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "jackson-databind", PkgName: "jackson-databind",
InstalledVersion: "2.8.0", InstalledVersion: "2.8.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "com.fasterxml.jackson.core",
Namespace: "com.fasterxml.jackson.core", Name: "jackson-databind",
Name: "jackson-databind", Version: "2.8.0",
Version: "2.8.0",
},
}, },
}, },
}, },
@@ -169,13 +157,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "jackson-databind", PkgName: "jackson-databind",
InstalledVersion: "2.8.0", InstalledVersion: "2.8.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "com.fasterxml.jackson.core",
Namespace: "com.fasterxml.jackson.core", Name: "jackson-databind",
Name: "jackson-databind", Version: "2.8.0",
Version: "2.8.0",
},
}, },
}, },
}, },
@@ -199,13 +185,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "jackson-databind", PkgName: "jackson-databind",
InstalledVersion: "2.8.0", InstalledVersion: "2.8.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "com.fasterxml.jackson.core",
Namespace: "com.fasterxml.jackson.core", Name: "jackson-databind",
Name: "jackson-databind", Version: "2.8.0",
Version: "2.8.0",
},
}, },
}, },
}, },
@@ -217,13 +201,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "jackson-databind", PkgName: "jackson-databind",
InstalledVersion: "2.8.0", InstalledVersion: "2.8.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "com.fasterxml.jackson.core",
Namespace: "com.fasterxml.jackson.core", Name: "jackson-databind",
Name: "jackson-databind", Version: "2.8.0",
Version: "2.8.0",
},
}, },
}, },
}, },
@@ -241,13 +223,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "spring-boot", PkgName: "spring-boot",
InstalledVersion: "2.6.0", InstalledVersion: "2.6.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.springframework.boot",
Namespace: "org.springframework.boot", Name: "spring-boot",
Name: "spring-boot", Version: "2.6.0",
Version: "2.6.0",
},
}, },
}, },
}, },
@@ -267,13 +247,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "def", PkgName: "def",
InstalledVersion: "1.0", InstalledVersion: "1.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.example.company",
Namespace: "org.example.company", Name: "def",
Name: "def", Version: "1.0",
Version: "1.0",
},
}, },
}, },
}, },
@@ -285,13 +263,11 @@ func TestVEX_Filter(t *testing.T) {
PkgName: "def", PkgName: "def",
InstalledVersion: "1.0", InstalledVersion: "1.0",
PkgIdentifier: ftypes.PkgIdentifier{ PkgIdentifier: ftypes.PkgIdentifier{
PURL: &ftypes.PackageURL{ PURL: &packageurl.PackageURL{
PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven,
Type: packageurl.TypeMaven, Namespace: "org.example.company",
Namespace: "org.example.company", Name: "def",
Name: "def", Version: "1.0",
Version: "1.0",
},
}, },
}, },
}, },