github.com/khulnasoft-lab/tunnel-db@v0.0.0-20231117205118-74e1113bd007/pkg/vulnsrc/glad/glad.go (about) 1 package glad 2 3 import ( 4 "encoding/json" 5 "io" 6 "log" 7 "path/filepath" 8 "strings" 9 10 bolt "go.etcd.io/bbolt" 11 "golang.org/x/text/cases" 12 "golang.org/x/text/language" 13 "golang.org/x/xerrors" 14 15 "github.com/khulnasoft-lab/tunnel-db/pkg/db" 16 "github.com/khulnasoft-lab/tunnel-db/pkg/types" 17 "github.com/khulnasoft-lab/tunnel-db/pkg/utils" 18 "github.com/khulnasoft-lab/tunnel-db/pkg/vulnsrc/bucket" 19 "github.com/khulnasoft-lab/tunnel-db/pkg/vulnsrc/vulnerability" 20 ) 21 22 const ( 23 // GitLab Advisory Database 24 gladDir = "glad" 25 26 // cf. https://gitlab.com/gitlab-org/security-products/gemnasium-db/-/tree/e4176fff52c027165ae5a79f5b1193090e2fbef0#package-slug-and-package-name 27 Conan packageType = "conan" 28 ) 29 30 var ( 31 supportedIDPrefixes = []string{ 32 "CVE", 33 "GHSA", 34 "GMS", 35 } 36 37 // Mapping between GLAD slug and Tunnel ecosystem 38 ecosystems = map[packageType]types.Ecosystem{ 39 Conan: vulnerability.Conan, 40 } 41 42 source = types.DataSource{ 43 ID: vulnerability.GLAD, 44 Name: "GitLab Advisory Database Community", 45 URL: "https://gitlab.com/gitlab-org/advisories-community", 46 } 47 ) 48 49 type packageType string 50 51 type VulnSrc struct { 52 dbc db.Operation 53 } 54 55 func NewVulnSrc() VulnSrc { 56 return VulnSrc{ 57 dbc: db.Config{}, 58 } 59 } 60 61 func (vs VulnSrc) Name() types.SourceID { 62 return source.ID 63 } 64 65 func (vs VulnSrc) Update(dir string) error { 66 for t := range ecosystems { 67 log.Printf(" Updating GitLab Advisory Database %s...", cases.Title(language.English).String(string(t))) 68 rootDir := filepath.Join(dir, "vuln-list", gladDir, string(t)) 69 if err := vs.update(t, rootDir); err != nil { 70 return xerrors.Errorf("update error: %w", err) 71 } 72 } 73 return nil 74 } 75 76 func (vs VulnSrc) update(pkgType packageType, rootDir string) error { 77 var glads []Advisory 78 err := utils.FileWalk(rootDir, func(r io.Reader, path string) error { 79 if !supportedIDs(filepath.Base(path)) { 80 return nil 81 } 82 83 var glad Advisory 84 if err := json.NewDecoder(r).Decode(&glad); err != nil { 85 return xerrors.Errorf("failed to decode GLAD: %w", err) 86 } 87 88 glads = append(glads, glad) 89 return nil 90 }) 91 if err != nil { 92 return xerrors.Errorf("walk error: %w", err) 93 } 94 95 if err = vs.save(pkgType, glads); err != nil { 96 return xerrors.Errorf("save error: %w", err) 97 } 98 99 return nil 100 } 101 102 func (vs VulnSrc) save(pkgType packageType, glads []Advisory) error { 103 err := vs.dbc.BatchUpdate(func(tx *bolt.Tx) error { 104 return vs.commit(tx, pkgType, glads) 105 }) 106 if err != nil { 107 return xerrors.Errorf("batch update error: %w", err) 108 } 109 return nil 110 } 111 112 func (vs VulnSrc) commit(tx *bolt.Tx, pkgType packageType, glads []Advisory) error { 113 for _, glad := range glads { 114 a := types.Advisory{ 115 VulnerableVersions: []string{glad.AffectedRange}, 116 PatchedVersions: glad.FixedVersions, 117 } 118 119 // e.g. "go/github.com/go-ldap/ldap" => "go", "github.com/go-ldap/ldap" 120 ss := strings.SplitN(glad.PackageSlug, "/", 2) 121 if len(ss) < 2 { 122 return xerrors.Errorf("failed to parse package slug: %s", glad.PackageSlug) 123 } 124 125 pkgName := ss[1] 126 ecosystem, ok := ecosystems[pkgType] 127 if !ok { 128 return xerrors.Errorf("failed to get ecosystem: %s", pkgType) 129 } 130 bucketName := bucket.Name(ecosystem, source.Name) 131 if err := vs.dbc.PutDataSource(tx, bucketName, source); err != nil { 132 return xerrors.Errorf("failed to put data source: %w", err) 133 } 134 135 if err := vs.dbc.PutAdvisoryDetail(tx, glad.Identifier, pkgName, []string{bucketName}, a); err != nil { 136 return xerrors.Errorf("failed to save GLAD advisory detail: %w", err) 137 } 138 139 // glad's cvss score is taken from NVD 140 vuln := types.VulnerabilityDetail{ 141 ID: glad.Identifier, 142 Severity: types.SeverityUnknown, 143 References: glad.Urls, 144 Title: glad.Title, 145 Description: glad.Description, 146 } 147 148 if err := vs.dbc.PutVulnerabilityDetail(tx, glad.Identifier, source.ID, vuln); err != nil { 149 return xerrors.Errorf("failed to save GLAD vulnerability detail: %w", err) 150 } 151 152 // for optimization 153 if err := vs.dbc.PutVulnerabilityID(tx, glad.Identifier); err != nil { 154 return xerrors.Errorf("failed to save the vulnerability ID: %w", err) 155 } 156 } 157 158 return nil 159 } 160 161 func supportedIDs(fileName string) bool { 162 for _, prefix := range supportedIDPrefixes { 163 if strings.HasPrefix(fileName, prefix) { 164 return true 165 } 166 } 167 return false 168 }