func (o *debian) scanVulnInfos(upgradablePacks []models.PackageInfo, meta *cache.Meta) (models.VulnInfos, error) { type strarray []string resChan := make(chan struct { models.PackageInfo strarray }, len(upgradablePacks)) errChan := make(chan error, len(upgradablePacks)) reqChan := make(chan models.PackageInfo, len(upgradablePacks)) defer close(resChan) defer close(errChan) defer close(reqChan) go func() { for _, pack := range upgradablePacks { reqChan <- pack } }() timeout := time.After(30 * 60 * time.Second) concurrency := 10 tasks := util.GenWorkers(concurrency) for range upgradablePacks { tasks <- func() { select { case pack := <-reqChan: func(p models.PackageInfo) { changelog := o.getChangelogCache(meta, p) if 0 < len(changelog) { cveIDs := o.getCveIDFromChangelog(changelog, p.Name, p.Version) resChan <- struct { models.PackageInfo strarray }{p, cveIDs} return } // if the changelog is not in cache or failed to get from local cache, // get the changelog of the package via internet. // After that, store it in the cache. if cveIDs, err := o.scanPackageCveIDs(p); err != nil { errChan <- err } else { resChan <- struct { models.PackageInfo strarray }{p, cveIDs} } }(pack) } } } // { CVE ID: [packageInfo] } cvePackages := make(map[string][]models.PackageInfo) errs := []error{} for i := 0; i < len(upgradablePacks); i++ { select { case pair := <-resChan: pack := pair.PackageInfo cveIDs := pair.strarray for _, cveID := range cveIDs { cvePackages[cveID] = appendPackIfMissing(cvePackages[cveID], pack) } o.log.Infof("(%d/%d) Scanned %s-%s : %s", i+1, len(upgradablePacks), pair.Name, pair.PackageInfo.Version, cveIDs) case err := <-errChan: errs = append(errs, err) case <-timeout: errs = append(errs, fmt.Errorf("Timeout scanPackageCveIDs")) } } if 0 < len(errs) { return nil, fmt.Errorf("%v", errs) } var cveIDs []string for k := range cvePackages { cveIDs = append(cveIDs, k) } o.log.Debugf("%d Cves are found. cves: %v", len(cveIDs), cveIDs) var vinfos models.VulnInfos for k, v := range cvePackages { vinfos = append(vinfos, models.VulnInfo{ CveID: k, Packages: v, }) } // Update meta package information of changelog cache to the latest one. meta.Packs = upgradablePacks if err := cache.DB.RefreshMeta(*meta); err != nil { return nil, err } return vinfos, nil }