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 }