github.com/khulnasoft-lab/tunnel-db@v0.0.0-20231117205118-74e1113bd007/pkg/vulnsrc/bundler/bundler.go (about) 1 package bundler 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strings" 8 9 bolt "go.etcd.io/bbolt" 10 "golang.org/x/xerrors" 11 "gopkg.in/yaml.v2" 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/vulnsrc/bucket" 16 "github.com/khulnasoft-lab/tunnel-db/pkg/vulnsrc/vulnerability" 17 ) 18 19 const bundlerDir = "ruby-advisory-db" 20 21 var ( 22 source = types.DataSource{ 23 ID: vulnerability.RubySec, 24 Name: "Ruby Advisory Database", 25 URL: "https://github.com/rubysec/ruby-advisory-db", 26 } 27 28 bucketName = bucket.Name(vulnerability.RubyGems, source.Name) 29 ) 30 31 type RawAdvisory struct { 32 Gem string 33 Cve string 34 Osvdb string 35 Ghsa string 36 Title string 37 Url string 38 Description string 39 CvssV2 float64 `yaml:"cvss_v2"` 40 CvssV3 float64 `yaml:"cvss_v3"` 41 PatchedVersions []string `yaml:"patched_versions"` 42 UnaffectedVersions []string `yaml:"unaffected_versions"` 43 Related Related 44 } 45 46 type Advisory struct { 47 VulnerabilityID string `json:",omitempty"` 48 PatchedVersions []string `json:",omitempty"` 49 UnaffectedVersions []string `json:",omitempty"` 50 } 51 52 type Related struct { 53 Cve []string 54 Url []string 55 } 56 57 type VulnSrc struct { 58 dbc db.Operation 59 } 60 61 func NewVulnSrc() VulnSrc { 62 return VulnSrc{ 63 dbc: db.Config{}, 64 } 65 } 66 67 func (vs VulnSrc) Name() types.SourceID { 68 return source.ID 69 } 70 71 func (vs VulnSrc) Update(dir string) error { 72 repoPath := filepath.Join(dir, bundlerDir) 73 if err := vs.update(repoPath); err != nil { 74 return xerrors.Errorf("failed to update bundler vulnerabilities: %w", err) 75 } 76 return nil 77 } 78 79 func (vs VulnSrc) update(repoPath string) error { 80 root := filepath.Join(repoPath, "gems") 81 82 err := vs.dbc.BatchUpdate(func(tx *bolt.Tx) error { 83 if err := vs.dbc.PutDataSource(tx, bucketName, source); err != nil { 84 return xerrors.Errorf("failed to put data source: %w", err) 85 } 86 87 if err := vs.walk(tx, root); err != nil { 88 return xerrors.Errorf("failed to walk ruby advisories: %w", err) 89 } 90 return nil 91 }) 92 if err != nil { 93 return xerrors.Errorf("batch update failed: %w", err) 94 } 95 return nil 96 } 97 98 func (vs VulnSrc) walk(tx *bolt.Tx, root string) error { 99 return filepath.Walk(root, func(path string, info os.FileInfo, err error) error { 100 return vs.walkFunc(err, info, path, tx) 101 }) 102 } 103 104 func (vs VulnSrc) walkFunc(err error, info os.FileInfo, path string, tx *bolt.Tx) error { 105 if err != nil { 106 return err 107 } 108 if info.IsDir() { 109 return nil 110 } 111 if strings.HasPrefix(strings.ToUpper(info.Name()), "OSVDB") { 112 return nil 113 } 114 115 buf, err := os.ReadFile(path) 116 if err != nil { 117 return xerrors.Errorf("failed to read a file: %w", err) 118 } 119 120 advisory := RawAdvisory{} 121 err = yaml.Unmarshal(buf, &advisory) 122 if err != nil { 123 return xerrors.Errorf("failed to unmarshal YAML: %w", err) 124 } 125 if strings.Contains(strings.ToLower(advisory.Url), "osvdb.org") { 126 advisory.Url = "" 127 } 128 129 var vulnerabilityID string 130 if advisory.Cve != "" { 131 vulnerabilityID = fmt.Sprintf("CVE-%s", advisory.Cve) 132 } else if advisory.Ghsa != "" { 133 vulnerabilityID = fmt.Sprintf("GHSA-%s", advisory.Ghsa) 134 } else { 135 return nil 136 } 137 138 // for detecting vulnerabilities 139 a := types.Advisory{ 140 PatchedVersions: advisory.PatchedVersions, 141 UnaffectedVersions: advisory.UnaffectedVersions, 142 } 143 144 err = vs.dbc.PutAdvisoryDetail(tx, vulnerabilityID, advisory.Gem, []string{bucketName}, a) 145 if err != nil { 146 return xerrors.Errorf("failed to save ruby advisory: %w", err) 147 } 148 149 // for displaying vulnerability detail 150 vuln := types.VulnerabilityDetail{ 151 CvssScore: advisory.CvssV2, 152 CvssScoreV3: advisory.CvssV3, 153 References: append([]string{advisory.Url}, advisory.Related.Url...), 154 Title: advisory.Title, 155 Description: advisory.Description, 156 } 157 158 if err = vs.dbc.PutVulnerabilityDetail(tx, vulnerabilityID, source.ID, vuln); err != nil { 159 return xerrors.Errorf("failed to save ruby vulnerability detail: %w", err) 160 } 161 162 // for optimization 163 if err = vs.dbc.PutVulnerabilityID(tx, vulnerabilityID); err != nil { 164 return xerrors.Errorf("failed to save the vulnerability ID: %w", err) 165 } 166 return nil 167 }