Skip to content

Commit

Permalink
✨ properly retrieving, matching, and supplying 3rd party sbom-refs
Browse files Browse the repository at this point in the history
  • Loading branch information
acidjazz committed Dec 12, 2024
1 parent fbee082 commit 7e644b6
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 13 deletions.
71 changes: 63 additions & 8 deletions pkg/bill/bill.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bill

import (
"context"
"encoding/json"
"fmt"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/format"
Expand All @@ -17,10 +18,16 @@ import (
"github.com/vulncheck-oss/cli/pkg/session"
"github.com/vulncheck-oss/sdk-go"
"github.com/vulncheck-oss/sdk-go/pkg/client"
"io"
"os"
"strings"
)

type InputSbomRef struct {
SbomRef string
PURL string
}

func GetSBOM(dir string) (*sbom.SBOM, error) {
src, err := syft.GetSource(context.Background(), dir, nil)

Expand Down Expand Up @@ -64,22 +71,60 @@ func SaveSBOM(sbm *sbom.SBOM, file string) error {
return nil
}

func LoadSBOM(inputFile string) (*sbom.SBOM, error) {
func LoadSBOM(inputFile string) (*sbom.SBOM, []InputSbomRef, error) {
file, err := os.Open(inputFile)
if err != nil {
return nil, fmt.Errorf("unable to open SBOM file %s: %w", inputFile, err)
return nil, nil, fmt.Errorf("unable to open SBOM file %s: %w", inputFile, err)
}
defer file.Close()

// Read the entire file content
content, err := io.ReadAll(file)
if err != nil {
return nil, nil, fmt.Errorf("unable to read SBOM file %s: %w", inputFile, err)
}

// Parse JSON to extract bom-ref and purl
var rawSBOM map[string]interface{}
err = json.Unmarshal(content, &rawSBOM)
if err != nil {
return nil, nil, fmt.Errorf("unable to parse SBOM JSON from file %s: %w", inputFile, err)
}

var inputSbomRefs []InputSbomRef

// Extract bom-ref and purl from components
if components, ok := rawSBOM["components"].([]interface{}); ok {
for _, comp := range components {
if component, ok := comp.(map[string]interface{}); ok {
bomRef, bomRefOk := component["bom-ref"].(string)
purl, purlOk := component["purl"].(string)
if bomRefOk && purlOk {
inputSbomRefs = append(inputSbomRefs, InputSbomRef{
SbomRef: bomRef,
PURL: purl,
})
}
}
}
}

// Reset file pointer to the beginning for Syft to read
_, err = file.Seek(0, 0)
if err != nil {
return nil, nil, fmt.Errorf("unable to reset file pointer: %w", err)
}

// Decode SBOM using Syft
sbm, _, _, err := format.Decode(file)
if err != nil {
return nil, fmt.Errorf("unable to decode SBOM from file %s: %w", inputFile, err)
return nil, nil, fmt.Errorf("unable to decode SBOM from file %s: %w", inputFile, err)
}

return sbm, nil
return sbm, inputSbomRefs, nil
}

func GetPURLDetail(sbm *sbom.SBOM) []models.PurlDetail {
func GetPURLDetail(sbm *sbom.SBOM, inputRefs []InputSbomRef) []models.PurlDetail {

if sbm == nil {
return []models.PurlDetail{}
Expand All @@ -93,13 +138,23 @@ func GetPURLDetail(sbm *sbom.SBOM) []models.PurlDetail {
for i, l := range p.Locations.ToSlice() {
locations[i] = l.RealPath
}
purls = append(purls, models.PurlDetail{

purlDetail := models.PurlDetail{
Purl: p.PURL,
PackageType: string(p.Type),
Cataloger: p.FoundBy,
Locations: locations,
SbomRef: string(p.ID()),
})
}

for _, ref := range inputRefs {
if ref.PURL == p.PURL {
purlDetail.SbomRef = ref.SbomRef
break
}
}

purls = append(purls, purlDetail)

}
}
return purls
Expand Down
8 changes: 4 additions & 4 deletions pkg/cmd/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package scan

import (
"fmt"
"github.com/octoper/go-ray"
"github.com/vulncheck-oss/cli/pkg/bill"
"github.com/vulncheck-oss/cli/pkg/cache"
"time"
Expand Down Expand Up @@ -38,12 +37,12 @@ func Command() *cobra.Command {
Example: i18n.C.ScanExample,
RunE: func(cmd *cobra.Command, args []string) error {

ray.Ray(args)
if opts.SbomInput == "" && len(args) < 1 {
return ui.Error(i18n.C.ScanErrorDirectoryRequired)
}

var sbm *sbom.SBOM
var inputRefs []bill.InputSbomRef
var purls []models.PurlDetail
var vulns []models.ScanResultVulnerabilities

Expand All @@ -58,7 +57,8 @@ func Command() *cobra.Command {
Title: fmt.Sprintf("Loading SBOM from %s", opts.SbomInput),
Task: func(t *taskin.Task) error {
var err error
sbm, err = bill.LoadSBOM(opts.SbomInput)
sbm, inputRefs, err = bill.LoadSBOM(opts.SbomInput)

if err != nil {
return err
}
Expand Down Expand Up @@ -86,7 +86,7 @@ func Command() *cobra.Command {
{
Title: i18n.C.ScanExtractPurlStart,
Task: func(t *taskin.Task) error {
purls = bill.GetPURLDetail(sbm)
purls = bill.GetPURLDetail(sbm, inputRefs)
t.Title = fmt.Sprintf(i18n.C.ScanExtractPurlEnd, len(purls))
return nil
},
Expand Down
2 changes: 1 addition & 1 deletion pkg/models/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type PurlDetail struct {
PackageType string `json:"type"`
Cataloger string `json:"cataloger"`
Locations []string `json:"locations"`
SbomRef string `json:sbom_ref`
SbomRef string `json:"sbom_ref""`

Check failure on line 12 in pkg/models/scan.go

View workflow job for this annotation

GitHub Actions / lint

structtag: struct field tag `json:"sbom_ref""` not compatible with reflect.StructTag.Get: key:"value" pairs not separated by spaces (govet)

Check failure on line 12 in pkg/models/scan.go

View workflow job for this annotation

GitHub Actions / lint

structtag: struct field tag `json:"sbom_ref""` not compatible with reflect.StructTag.Get: key:"value" pairs not separated by spaces (govet)
}

type ScanResultVulnerabilities struct {
Expand Down

0 comments on commit 7e644b6

Please sign in to comment.