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

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