github.com/khulnasoft-lab/tunnel-db@v0.0.0-20231117205118-74e1113bd007/pkg/vulnsrc/wolfi/wolfi.go (about)

     1  package wolfi
     2  
     3  import (
     4  	"encoding/json"
     5  	"io"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	bolt "go.etcd.io/bbolt"
    10  	"golang.org/x/xerrors"
    11  
    12  	"github.com/khulnasoft-lab/tunnel-db/pkg/db"
    13  	"github.com/khulnasoft-lab/tunnel-db/pkg/types"
    14  	"github.com/khulnasoft-lab/tunnel-db/pkg/utils"
    15  	"github.com/khulnasoft-lab/tunnel-db/pkg/vulnsrc/vulnerability"
    16  )
    17  
    18  const (
    19  	wolfiDir   = "wolfi"
    20  	distroName = "wolfi"
    21  )
    22  
    23  var (
    24  	source = types.DataSource{
    25  		ID:   vulnerability.Wolfi,
    26  		Name: "Wolfi Secdb",
    27  		URL:  "https://packages.wolfi.dev/os/security.json",
    28  	}
    29  )
    30  
    31  type VulnSrc struct {
    32  	dbc db.Operation
    33  }
    34  
    35  func NewVulnSrc() VulnSrc {
    36  	return VulnSrc{
    37  		dbc: db.Config{},
    38  	}
    39  }
    40  
    41  func (vs VulnSrc) Name() types.SourceID {
    42  	return source.ID
    43  }
    44  
    45  func (vs VulnSrc) Update(dir string) error {
    46  	rootDir := filepath.Join(dir, "vuln-list", wolfiDir)
    47  	var advisories []advisory
    48  	err := utils.FileWalk(rootDir, func(r io.Reader, path string) error {
    49  		var advisory advisory
    50  		if err := json.NewDecoder(r).Decode(&advisory); err != nil {
    51  			return xerrors.Errorf("failed to decode Wolfi advisory: %w", err)
    52  		}
    53  		advisories = append(advisories, advisory)
    54  		return nil
    55  	})
    56  	if err != nil {
    57  		return xerrors.Errorf("error in Wolfi walk: %w", err)
    58  	}
    59  
    60  	if err = vs.save(advisories); err != nil {
    61  		return xerrors.Errorf("error in Wolfi save: %w", err)
    62  	}
    63  
    64  	return nil
    65  }
    66  
    67  func (vs VulnSrc) save(advisories []advisory) error {
    68  	err := vs.dbc.BatchUpdate(func(tx *bolt.Tx) error {
    69  		for _, adv := range advisories {
    70  			bucket := distroName
    71  			if err := vs.dbc.PutDataSource(tx, bucket, source); err != nil {
    72  				return xerrors.Errorf("failed to put data source: %w", err)
    73  			}
    74  			if err := vs.saveSecFixes(tx, distroName, adv.PkgName, adv.Secfixes); err != nil {
    75  				return err
    76  			}
    77  		}
    78  		return nil
    79  	})
    80  	if err != nil {
    81  		return xerrors.Errorf("error in db batch update: %w", err)
    82  	}
    83  	return nil
    84  }
    85  
    86  func (vs VulnSrc) saveSecFixes(tx *bolt.Tx, platform, pkgName string, secfixes map[string][]string) error {
    87  	for fixedVersion, vulnIDs := range secfixes {
    88  		advisory := types.Advisory{
    89  			FixedVersion: fixedVersion,
    90  		}
    91  		for _, vulnID := range vulnIDs {
    92  			// See https://gitlab.alpinelinux.org/alpine/infra/docker/secdb/-/issues/3
    93  			// e.g. CVE-2017-2616 (+ regression fix)
    94  			ids := strings.Fields(vulnID)
    95  			for _, cveID := range ids {
    96  				cveID = strings.ReplaceAll(cveID, "CVE_", "CVE-")
    97  				if !strings.HasPrefix(cveID, "CVE-") {
    98  					continue
    99  				}
   100  				if err := vs.dbc.PutAdvisoryDetail(tx, cveID, pkgName, []string{platform}, advisory); err != nil {
   101  					return xerrors.Errorf("failed to save Wolfi advisory: %w", err)
   102  				}
   103  
   104  				// for optimization
   105  				if err := vs.dbc.PutVulnerabilityID(tx, cveID); err != nil {
   106  					return xerrors.Errorf("failed to save the vulnerability ID: %w", err)
   107  				}
   108  			}
   109  		}
   110  	}
   111  	return nil
   112  }
   113  
   114  func (vs VulnSrc) Get(_, pkgName string) ([]types.Advisory, error) {
   115  	bucket := distroName
   116  	advisories, err := vs.dbc.GetAdvisories(bucket, pkgName)
   117  	if err != nil {
   118  		return nil, xerrors.Errorf("failed to get Wolfi advisories: %w", err)
   119  	}
   120  	return advisories, nil
   121  }