Files
trivy/pkg/scanner/library/composer/advisory.go
2019-08-18 22:22:54 -10:00

109 lines
2.4 KiB
Go

package composer
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/etcd-io/bbolt"
"github.com/aquasecurity/trivy/pkg/db"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/aquasecurity/trivy/pkg/vulnsrc/vulnerability"
"github.com/aquasecurity/trivy/pkg/git"
"gopkg.in/yaml.v2"
)
const (
dbURL = "https://github.com/FriendsOfPHP/security-advisories"
)
var (
repoPath = filepath.Join(utils.CacheDir(), "php-security-advisories")
)
type AdvisoryDB map[string][]Advisory
type Advisory struct {
Cve string
Title string
Link string
Reference string
Branches map[string]Branch
}
type Branch struct {
Versions []string
}
func (s *Scanner) UpdateDB() (err error) {
if _, err := git.CloneOrPull(dbURL, repoPath); err != nil {
return err
}
s.db, err = s.walk()
return err
}
func (s *Scanner) walk() (AdvisoryDB, error) {
advisoryDB := AdvisoryDB{}
var vulns []vulnerability.Vulnerability
err := filepath.Walk(repoPath, func(path string, info os.FileInfo, err error) error {
if info.IsDir() || !strings.HasPrefix(info.Name(), "CVE-") {
return nil
}
buf, err := ioutil.ReadFile(path)
if err != nil {
return err
}
advisory := Advisory{}
err = yaml.Unmarshal(buf, &advisory)
if err != nil {
return err
}
// for detecting vulnerabilities
advisories, ok := advisoryDB[advisory.Reference]
if !ok {
advisories = []Advisory{}
}
advisoryDB[advisory.Reference] = append(advisories, advisory)
vulnerabilityID := advisory.Cve
if vulnerabilityID == "" {
// e.g. CVE-2019-12139.yaml => CVE-2019-12139
vulnerabilityID = strings.TrimSuffix(info.Name(), ".yaml")
}
// for displaying vulnerability detail
vulns = append(vulns, vulnerability.Vulnerability{
ID: vulnerabilityID,
References: []string{advisory.Link},
Title: advisory.Title,
})
return nil
})
if err != nil {
return nil, xerrors.Errorf("error in file walk: %w", err)
}
if err = s.saveVulnerabilities(vulns); err != nil {
return nil, err
}
return advisoryDB, nil
}
func (s Scanner) saveVulnerabilities(vulns []vulnerability.Vulnerability) error {
return vulnerability.BatchUpdate(func(b *bbolt.Bucket) error {
for _, vuln := range vulns {
if err := db.Put(b, vuln.ID, vulnerability.PhpSecurityAdvisories, vuln); err != nil {
return xerrors.Errorf("failed to save %s vulnerability: %w", s.Type(), err)
}
}
return nil
})
}