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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/models/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ type PackageInfo struct {
OSPackageName string `json:"os_package_name,omitempty"`
Version string `json:"version"`
Ecosystem string `json:"ecosystem"`
PURL string `json:"purl,omitempty"`
Commit string `json:"commit,omitempty"`
Deprecated bool `json:"deprecated,omitempty"`
ImageOrigin *ImageOriginDetails `json:"image_origin_details,omitempty"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"package": {
"name": "pkg-1",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-1@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -51,7 +52,8 @@
"package": {
"name": "pkg-3",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-3@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -95,7 +97,8 @@
"package": {
"name": "pkg-1",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-1@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -126,7 +129,8 @@
"package": {
"name": "pkg-2",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-2@1.0.0"
}
}
]
Expand All @@ -141,7 +145,8 @@
"package": {
"name": "pkg-3",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-3@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -185,7 +190,8 @@
"package": {
"name": "pkg-1",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-1@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -228,7 +234,8 @@
"package": {
"name": "pkg-3",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-3@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -281,7 +288,8 @@
"package": {
"name": "pkg-1",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-1@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -316,7 +324,8 @@
"package": {
"name": "pkg-2",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-2@1.0.0"
},
"licenses": [
"MIT"
Expand All @@ -334,7 +343,8 @@
"package": {
"name": "pkg-3",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-3@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -387,7 +397,8 @@
"package": {
"name": "pkg-1",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-1@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -430,7 +441,8 @@
"package": {
"name": "pkg-3",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-3@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -480,7 +492,8 @@
"package": {
"name": "pkg-1",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-1@1.0.0"
},
"groups": [
{
Expand Down Expand Up @@ -515,7 +528,8 @@
"package": {
"name": "pkg-2",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-2@1.0.0"
},
"licenses": [
"MIT"
Expand All @@ -533,7 +547,8 @@
"package": {
"name": "pkg-3",
"version": "1.0.0",
"ecosystem": "npm"
"ecosystem": "npm",
"purl": "pkg:npm/pkg-3@1.0.0"
},
"groups": [
{
Expand Down
4 changes: 4 additions & 0 deletions pkg/osvscanner/vulnerability_result.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"sort"
"strings"

"github.com/google/osv-scalibr/converter"
"github.com/google/osv-scalibr/extractor/filesystem/sbom/cdx"
cdxmeta "github.com/google/osv-scalibr/extractor/filesystem/sbom/cdx/metadata"
"github.com/google/osv-scalibr/inventory/vex"
Expand Down Expand Up @@ -59,6 +60,9 @@ func buildVulnerabilityResults(
pkg.Package.Ecosystem = imodels.Ecosystem(p).String()
pkg.Package.OSPackageName = imodels.OSPackageName(p)
pkg.Package.Deprecated = p.Deprecated
if packageURL := converter.ToPURL(p); packageURL != nil {
pkg.Package.PURL = packageURL.String()
}

if pkg.Package.Deprecated {
includePackage = true
Expand Down
69 changes: 69 additions & 0 deletions pkg/osvscanner/vulnerability_result_internal_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package osvscanner

import (
"encoding/json"
"testing"

"github.com/google/osv-scalibr/extractor"
Expand Down Expand Up @@ -67,6 +68,74 @@ func makeScanResults() *results.ScanResults {
return scanResults
}

func Test_assembleResult_PURL(t *testing.T) {
t.Parallel()

scanResults := &results.ScanResults{
Inventory: inventory.Inventory{
Packages: []*extractor.Package{
{
Name: "pkg-with-purl",
PURLType: purl.TypeNPM,
Plugins: []string{packagelockjson.Name},
Version: "1.0.0",
Location: extractor.LocationFromPath("dir/package-lock.json"),
},
{
Name: "pkg-without-purl",
Plugins: []string{packagelockjson.Name},
Version: "1.0.0",
Location: extractor.LocationFromPath("dir/package-lock.json"),
},
},
},
ConfigManager: config.Manager{},
}

got := buildVulnerabilityResults(ScannerActions{ShowAllPackages: true}, scanResults)
if len(got.Results) != 1 {
t.Fatalf("got %d results, want 1", len(got.Results))
}
if len(got.Results[0].Packages) != 2 {
t.Fatalf("got %d packages, want 2", len(got.Results[0].Packages))
}

packageIndexes := make(map[string]int, len(got.Results[0].Packages))
for i, pkg := range got.Results[0].Packages {
packageIndexes[pkg.Package.Name] = i
}

withPURLIndex, ok := packageIndexes["pkg-with-purl"]
if !ok {
t.Fatal("missing package pkg-with-purl")
}
withPURL := got.Results[0].Packages[withPURLIndex].Package
if withPURL.PURL != "pkg:npm/pkg-with-purl@1.0.0" {
t.Errorf("PURL = %q, want %q", withPURL.PURL, "pkg:npm/pkg-with-purl@1.0.0")
}

withoutPURLIndex, ok := packageIndexes["pkg-without-purl"]
if !ok {
t.Fatal("missing package pkg-without-purl")
}
withoutPURL := got.Results[0].Packages[withoutPURLIndex].Package
if withoutPURL.PURL != "" {
t.Errorf("PURL = %q, want empty", withoutPURL.PURL)
}

withoutPURLJSON, err := json.Marshal(withoutPURL)
if err != nil {
t.Fatalf("json.Marshal() error = %v", err)
}
var withoutPURLFields map[string]any
if err := json.Unmarshal(withoutPURLJSON, &withoutPURLFields); err != nil {
t.Fatalf("json.Unmarshal() error = %v", err)
}
if _, ok := withoutPURLFields["purl"]; ok {
t.Errorf("json.Marshal() = %s, want no purl field", withoutPURLJSON)
}
}

func Test_assembleResult(t *testing.T) {
t.Parallel()
type args struct {
Expand Down
Loading