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

     1  package chainguard
     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  	chainguardDir = "chainguard"
    20  	distroName    = "chainguard"
    21  )
    22  
    23  var (
    24  	source = types.DataSource{
    25  		ID:   vulnerability.Chainguard,
    26  		Name: "Chainguard Security Data",
    27  		URL:  "https://packages.cgr.dev/chainguard/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", chainguardDir)
    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 Chainguard advisory: %w", err)
    52  		}
    53  		advisories = append(advisories, advisory)
    54  		return nil
    55  	})
    56  	if err != nil {
    57  		return xerrors.Errorf("error in Chainguard walk: %w", err)
    58  	}
    59  
    60  	if err = vs.save(advisories); err != nil {
    61  		return xerrors.Errorf("error in Chainguard 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  
    92  		for _, vulnID := range vulnIDs {
    93  			if !strings.HasPrefix(vulnID, "CVE-") {
    94  				continue
    95  			}
    96  
    97  			if err := vs.dbc.PutAdvisoryDetail(tx, vulnID, pkgName, []string{platform}, advisory); err != nil {
    98  				return xerrors.Errorf("failed to save Chainguard advisory: %w", err)
    99  			}
   100  
   101  			// for optimization
   102  			if err := vs.dbc.PutVulnerabilityID(tx, vulnID); err != nil {
   103  				return xerrors.Errorf("failed to save the vulnerability ID: %w", err)
   104  			}
   105  		}
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  func (vs VulnSrc) Get(_, pkgName string) ([]types.Advisory, error) {
   112  	bucket := distroName
   113  	advisories, err := vs.dbc.GetAdvisories(bucket, pkgName)
   114  	if err != nil {
   115  		return nil, xerrors.Errorf("failed to get Chainguard advisories: %w", err)
   116  	}
   117  	return advisories, nil
   118  }