Compare commits

..

1 Commits

Author SHA1 Message Date
knqyf263
3b8aedad58 Update README 2019-05-07 15:48:22 +09:00
14 changed files with 33 additions and 205 deletions

View File

@@ -2,16 +2,9 @@ defaults: &defaults
docker : docker :
- image: knqyf263/ci-trivy:latest - image: knqyf263/ci-trivy:latest
environment: environment:
CGO_ENABLED: "0" CGO_ENABLED: "1"
jobs: jobs:
test:
<<: *defaults
steps:
- checkout
- run:
name: Test
command: go test ./...
release: release:
<<: *defaults <<: *defaults
steps: steps:
@@ -41,7 +34,6 @@ workflows:
version: 2 version: 2
release: release:
jobs: jobs:
- test
- release: - release:
filters: filters:
branches: branches:

View File

@@ -1,12 +1,10 @@
<img src="imgs/logo.png" width="300"> # trivy
[![GitHub release](https://img.shields.io/github/release/knqyf263/trivy.svg)](https://github.com/knqyf263/trivy/releases/latest) [![GitHub release](https://img.shields.io/github/release/knqyf263/trivy.svg)](https://github.com/knqyf263/trivy/releases/latest)
[![CircleCI](https://circleci.com/gh/knqyf263/trivy.svg?style=svg)](https://circleci.com/gh/knqyf263/trivy) [![CircleCI](https://circleci.com/gh/knqyf263/trivy.svg?style=svg)](https://circleci.com/gh/knqyf263/trivy)
[![Go Report Card](https://goreportcard.com/badge/github.com/knqyf263/trivy)](https://goreportcard.com/report/github.com/knqyf263/trivy) [![Go Report Card](https://goreportcard.com/badge/github.com/knqyf263/trivy)](https://goreportcard.com/report/github.com/knqyf263/trivy)
[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/knqyf263/trivy/blob/master/LICENSE) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/knqyf263/trivy/blob/master/LICENSE)
A Simple and Comprehensive Vulnerability Scanner for Containers
# Abstract # Abstract
Scan containers Scan containers
@@ -139,9 +137,6 @@ $ trivy --clean alpine:3.8
---- ----
# Credits
Special thanks to [Tomoya Amachi](https://github.com/tomoyamachi)
# License # License
MIT MIT

2
go.mod
View File

@@ -37,5 +37,3 @@ require (
) )
replace github.com/genuinetools/reg => github.com/tomoyamachi/reg v0.16.2-0.20190418055600-c6010b917a55 replace github.com/genuinetools/reg => github.com/tomoyamachi/reg v0.16.2-0.20190418055600-c6010b917a55
replace github.com/olekukonko/tablewriter => github.com/knqyf263/tablewriter v0.0.2

2
go.sum
View File

@@ -128,8 +128,6 @@ github.com/knqyf263/go-version v1.1.1 h1:+MpcBC9b7rk5ihag8Y/FLG8get1H2GjniwKQ+9D
github.com/knqyf263/go-version v1.1.1/go.mod h1:0tBvHvOBSf5TqGNcY+/ih9o8qo3R16iZCpB9rP0D3VM= github.com/knqyf263/go-version v1.1.1/go.mod h1:0tBvHvOBSf5TqGNcY+/ih9o8qo3R16iZCpB9rP0D3VM=
github.com/knqyf263/nested v0.0.1 h1:Sv26CegUMhjt19zqbBKntjwESdxe5hxVPSk0+AKjdUc= github.com/knqyf263/nested v0.0.1 h1:Sv26CegUMhjt19zqbBKntjwESdxe5hxVPSk0+AKjdUc=
github.com/knqyf263/nested v0.0.1/go.mod h1:zwhsIhMkBg90DTOJQvxPkKIypEHPYkgWHs4gybdlUmk= github.com/knqyf263/nested v0.0.1/go.mod h1:zwhsIhMkBg90DTOJQvxPkKIypEHPYkgWHs4gybdlUmk=
github.com/knqyf263/tablewriter v0.0.2 h1:lGaBruL/oJt8FAlMVy9KU0oQ/6NXAJjvK7wBgZyc+Og=
github.com/knqyf263/tablewriter v0.0.2/go.mod h1:NDOJQAZxabBL3e13jQVktkvbr6bxXXPon8Lyh7fRPPc=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -1,16 +1,10 @@
package bundler package bundler
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"github.com/etcd-io/bbolt"
"github.com/knqyf263/trivy/pkg/db"
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/knqyf263/trivy/pkg/git" "github.com/knqyf263/trivy/pkg/git"
@@ -34,9 +28,6 @@ type Advisory struct {
Osvdb string Osvdb string
Title string Title string
Url string Url string
Description string
CvssV2 float64 `yaml:"cvss_v2"`
CvssV3 float64 `yaml:"cvss_v3"`
PatchedVersions []string `yaml:"patched_versions"` PatchedVersions []string `yaml:"patched_versions"`
UnaffectedVersions []string `yaml:"unaffected_versions"` UnaffectedVersions []string `yaml:"unaffected_versions"`
Related Related Related Related
@@ -51,15 +42,14 @@ func (s *Scanner) UpdateDB() (err error) {
if _, err := git.CloneOrPull(dbURL, repoPath); err != nil { if _, err := git.CloneOrPull(dbURL, repoPath); err != nil {
return xerrors.Errorf("error in %s security DB update: %w", s.Type(), err) return xerrors.Errorf("error in %s security DB update: %w", s.Type(), err)
} }
s.db, err = s.walk() s.db, err = walk()
return err return err
} }
func (s *Scanner) walk() (AdvisoryDB, error) { func walk() (AdvisoryDB, error) {
advisoryDB := AdvisoryDB{} advisoryDB := AdvisoryDB{}
root := filepath.Join(repoPath, "gems") root := filepath.Join(repoPath, "gems")
var vulns []vulnerability.Vulnerability
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if info.IsDir() { if info.IsDir() {
return nil return nil
@@ -75,48 +65,16 @@ func (s *Scanner) walk() (AdvisoryDB, error) {
return xerrors.Errorf("failed to unmarshal YAML: %w", err) return xerrors.Errorf("failed to unmarshal YAML: %w", err)
} }
// for detecting vulnerabilities
advisories, ok := advisoryDB[advisory.Gem] advisories, ok := advisoryDB[advisory.Gem]
if !ok { if !ok {
advisories = []Advisory{} advisories = []Advisory{}
} }
advisoryDB[advisory.Gem] = append(advisories, advisory) advisoryDB[advisory.Gem] = append(advisories, advisory)
// for displaying vulnerability detail
var vulnerabilityID string
if advisory.Cve != "" {
vulnerabilityID = fmt.Sprintf("CVE-%s", advisory.Cve)
} else if advisory.Osvdb != "" {
vulnerabilityID = fmt.Sprintf("OSVDB-%s", advisory.Osvdb)
}
vulns = append(vulns, vulnerability.Vulnerability{
ID: vulnerabilityID,
CvssScore: advisory.CvssV2,
CvssScoreV3: advisory.CvssV3,
References: append([]string{advisory.Url}, advisory.Related.Url...),
Title: advisory.Title,
Description: advisory.Description,
})
return nil return nil
}) })
if err != nil { if err != nil {
return nil, xerrors.Errorf("error in file walk: %w", err) return nil, xerrors.Errorf("error in file wakl: %w", err)
}
if err = s.saveVulnerabilities(vulns); err != nil {
return nil, err
} }
return advisoryDB, nil 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.RubySec, vuln); err != nil {
return xerrors.Errorf("failed to save %s vulnerability: %w", s.Type(), err)
}
}
return nil
})
}

View File

@@ -6,13 +6,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/etcd-io/bbolt"
"github.com/knqyf263/trivy/pkg/db"
"golang.org/x/xerrors"
"github.com/knqyf263/trivy/pkg/utils" "github.com/knqyf263/trivy/pkg/utils"
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
"github.com/knqyf263/trivy/pkg/git" "github.com/knqyf263/trivy/pkg/git"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@@ -44,13 +38,12 @@ func (s *Scanner) UpdateDB() (err error) {
if _, err := git.CloneOrPull(dbURL, repoPath); err != nil { if _, err := git.CloneOrPull(dbURL, repoPath); err != nil {
return err return err
} }
s.db, err = s.walk() s.db, err = walk()
return err return err
} }
func (s *Scanner) walk() (AdvisoryDB, error) { func walk() (AdvisoryDB, error) {
advisoryDB := AdvisoryDB{} advisoryDB := AdvisoryDB{}
var vulns []vulnerability.Vulnerability
err := filepath.Walk(repoPath, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(repoPath, func(path string, info os.FileInfo, err error) error {
if info.IsDir() || !strings.HasPrefix(info.Name(), "CVE-") { if info.IsDir() || !strings.HasPrefix(info.Name(), "CVE-") {
return nil return nil
@@ -65,39 +58,16 @@ func (s *Scanner) walk() (AdvisoryDB, error) {
if err != nil { if err != nil {
return err return err
} }
// for detecting vulnerabilities
advisories, ok := advisoryDB[advisory.Reference] advisories, ok := advisoryDB[advisory.Reference]
if !ok { if !ok {
advisories = []Advisory{} advisories = []Advisory{}
} }
advisoryDB[advisory.Reference] = append(advisories, advisory) advisoryDB[advisory.Reference] = append(advisories, advisory)
// for displaying vulnerability detail
vulns = append(vulns, vulnerability.Vulnerability{
ID: advisory.Cve,
References: []string{advisory.Link},
Title: advisory.Title,
})
return nil return nil
}) })
if err != 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 nil, err
} }
return advisoryDB, nil 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
})
}

View File

@@ -2,19 +2,12 @@ package npm
import ( import (
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"github.com/etcd-io/bbolt"
"github.com/knqyf263/trivy/pkg/db"
"golang.org/x/xerrors"
"github.com/knqyf263/trivy/pkg/utils" "github.com/knqyf263/trivy/pkg/utils"
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
"github.com/knqyf263/trivy/pkg/git" "github.com/knqyf263/trivy/pkg/git"
) )
@@ -36,7 +29,6 @@ type Advisory struct {
Cves []string Cves []string
VulnerableVersions string `json:"vulnerable_versions"` VulnerableVersions string `json:"vulnerable_versions"`
PatchedVersions string `json:"patched_versions"` PatchedVersions string `json:"patched_versions"`
Overview string
Recommendation string Recommendation string
References []string References []string
CvssScoreNumber json.Number `json:"cvss_score"` CvssScoreNumber json.Number `json:"cvss_score"`
@@ -47,13 +39,12 @@ func (s *Scanner) UpdateDB() (err error) {
if _, err := git.CloneOrPull(dbURL, repoPath); err != nil { if _, err := git.CloneOrPull(dbURL, repoPath); err != nil {
return err return err
} }
s.db, err = s.walk() s.db, err = walk()
return err return err
} }
func (s *Scanner) walk() (AdvisoryDB, error) { func walk() (AdvisoryDB, error) {
advisoryDB := AdvisoryDB{} advisoryDB := AdvisoryDB{}
var vulns []vulnerability.Vulnerability
err := filepath.Walk(filepath.Join(repoPath, "vuln"), func(path string, info os.FileInfo, err error) error { err := filepath.Walk(filepath.Join(repoPath, "vuln"), func(path string, info os.FileInfo, err error) error {
if info.IsDir() || !strings.HasSuffix(info.Name(), ".json") { if info.IsDir() || !strings.HasSuffix(info.Name(), ".json") {
return nil return nil
@@ -77,46 +68,16 @@ func (s *Scanner) walk() (AdvisoryDB, error) {
advisory.CvssScore = -1 advisory.CvssScore = -1
} }
// for detecting vulnerabilities
advisories, ok := advisoryDB[advisory.ModuleName] advisories, ok := advisoryDB[advisory.ModuleName]
if !ok { if !ok {
advisories = []Advisory{} advisories = []Advisory{}
} }
advisoryDB[advisory.ModuleName] = append(advisories, advisory) advisoryDB[advisory.ModuleName] = append(advisories, advisory)
// for displaying vulnerability detail
vulnerabilityIDs := advisory.Cves
if len(vulnerabilityIDs) == 0 {
vulnerabilityIDs = []string{fmt.Sprintf("NSWG-ECO-%d", advisory.ID)}
}
for _, vulnID := range vulnerabilityIDs {
vulns = append(vulns, vulnerability.Vulnerability{
ID: vulnID,
CvssScore: advisory.CvssScore,
References: advisory.References,
Title: advisory.Title,
Description: advisory.Overview,
})
}
return nil return nil
}) })
if err != 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 nil, err
} }
return advisoryDB, nil 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.NodejsSecurityWg, vuln); err != nil {
return xerrors.Errorf("failed to save %s vulnerability: %w", s.Type(), err)
}
}
return nil
})
}

View File

@@ -5,14 +5,9 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/etcd-io/bbolt"
"github.com/knqyf263/trivy/pkg/db"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/knqyf263/trivy/pkg/utils" "github.com/knqyf263/trivy/pkg/utils"
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
"github.com/knqyf263/trivy/pkg/git" "github.com/knqyf263/trivy/pkg/git"
) )
@@ -39,14 +34,14 @@ func (s *Scanner) UpdateDB() (err error) {
if _, err := git.CloneOrPull(dbURL, repoPath); err != nil { if _, err := git.CloneOrPull(dbURL, repoPath); err != nil {
return err return err
} }
s.db, err = s.parse() s.db, err = parse()
if err != nil { if err != nil {
return xerrors.Errorf("failed to parse python safety-db: %w", err) return xerrors.Errorf("failed to parse python safety-db: %w", err)
} }
return nil return nil
} }
func (s *Scanner) parse() (AdvisoryDB, error) { func parse() (AdvisoryDB, error) {
advisoryDB := AdvisoryDB{} advisoryDB := AdvisoryDB{}
f, err := os.Open(filepath.Join(repoPath, "data", "insecure_full.json")) f, err := os.Open(filepath.Join(repoPath, "data", "insecure_full.json"))
if err != nil { if err != nil {
@@ -54,39 +49,9 @@ func (s *Scanner) parse() (AdvisoryDB, error) {
} }
defer f.Close() defer f.Close()
// for detecting vulnerabilities
if err = json.NewDecoder(f).Decode(&advisoryDB); err != nil { if err = json.NewDecoder(f).Decode(&advisoryDB); err != nil {
return nil, err return nil, err
} }
// for displaying vulnerability detail
var vulns []vulnerability.Vulnerability
for _, advisories := range advisoryDB {
for _, advisory := range advisories {
vulnerabilityID := advisory.Cve
if vulnerabilityID == "" {
vulnerabilityID = advisory.ID
}
vulns = append(vulns, vulnerability.Vulnerability{
ID: vulnerabilityID,
Title: advisory.Advisory,
})
}
}
if err = s.saveVulnerabilities(vulns); err != nil {
return nil, err
}
return advisoryDB, nil 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.PythonSafetyDB, vuln); err != nil {
return xerrors.Errorf("failed to save %s vulnerability: %w", s.Type(), err)
}
}
return nil
})
}

View File

@@ -96,7 +96,7 @@ func scan(scanner Scanner, pkgs []ptypes.Library) ([]types.Vulnerability, error)
return nil, xerrors.Errorf("failed to update %s advisories: %w", scanner.Type(), err) return nil, xerrors.Errorf("failed to update %s advisories: %w", scanner.Type(), err)
} }
log.Logger.Infof("Detecting %s vulnerabilities...", scanner.Type()) log.Logger.Infof("Detect %s vulnerabilities", scanner.Type())
var vulnerabilities []types.Vulnerability var vulnerabilities []types.Vulnerability
for _, pkg := range pkgs { for _, pkg := range pkgs {
v, err := version.NewVersion(pkg.Version) v, err := version.NewVersion(pkg.Version)

View File

@@ -25,12 +25,6 @@ import (
"github.com/knqyf263/fanal/extractor" "github.com/knqyf263/fanal/extractor"
) )
var (
sources = []string{vulnerability.Nvd, vulnerability.RedHat, vulnerability.Debian,
vulnerability.DebianOVAL, vulnerability.Alpine, vulnerability.RubySec, vulnerability.PhpSecurityAdvisories,
vulnerability.NodejsSecurityWg, vulnerability.PythonSafetyDB}
)
func ScanImage(imageName, filePath string, severities []vulnerability.Severity) (report.Results, error) { func ScanImage(imageName, filePath string, severities []vulnerability.Severity) (report.Results, error) {
var results report.Results var results report.Results
var err error var err error
@@ -140,7 +134,8 @@ func getDetail(vulnID string) (vulnerability.Severity, string) {
} }
func getSeverity(details map[string]vulnerability.Vulnerability) vulnerability.Severity { func getSeverity(details map[string]vulnerability.Vulnerability) vulnerability.Severity {
for _, source := range sources { for _, source := range []string{vulnerability.Nvd, vulnerability.RedHat, vulnerability.Debian,
vulnerability.DebianOVAL, vulnerability.Alpine} {
d, ok := details[source] d, ok := details[source]
if !ok { if !ok {
continue continue
@@ -159,7 +154,8 @@ func getSeverity(details map[string]vulnerability.Vulnerability) vulnerability.S
} }
func getTitle(details map[string]vulnerability.Vulnerability) string { func getTitle(details map[string]vulnerability.Vulnerability) string {
for _, source := range sources { for _, source := range []string{vulnerability.Nvd, vulnerability.RedHat, vulnerability.Debian,
vulnerability.DebianOVAL, vulnerability.Alpine} {
d, ok := details[source] d, ok := details[source]
if !ok { if !ok {
continue continue

View File

@@ -2,17 +2,13 @@ package vulnerability
const ( const (
// Data source // Data source
Nvd = "nvd" Nvd = "nvd"
RedHat = "redhat" RedHat = "redhat"
Debian = "debian" Debian = "debian"
DebianOVAL = "debian-oval" DebianOVAL = "debian-oval"
Ubuntu = "ubuntu" Ubuntu = "ubuntu"
CentOS = "centos" CentOS = "centos"
Fedora = "fedora" Fedora = "fedora"
Amazon = "amazon" Amazon = "amazon"
Alpine = "alpine" Alpine = "alpine"
RubySec = "ruby-advisory-db"
PhpSecurityAdvisories = "php-security-advisories"
NodejsSecurityWg = "nodejs-security-wg"
PythonSafetyDB = "python-safety-db"
) )

View File

@@ -19,18 +19,18 @@ const (
var ( var (
SeverityNames = []string{ SeverityNames = []string{
"UNKNOWN",
"LOW",
"MEDIUM",
"HIGH",
"CRITICAL", "CRITICAL",
"HIGH",
"MEDIUM",
"LOW",
"UNKNOWN",
} }
SeverityColor = []func(a ...interface{}) string{ SeverityColor = []func(a ...interface{}) string{
color.New(color.FgCyan).SprintFunc(),
color.New(color.FgBlue).SprintFunc(),
color.New(color.FgYellow).SprintFunc(),
color.New(color.FgHiRed).SprintFunc(),
color.New(color.FgRed).SprintFunc(), color.New(color.FgRed).SprintFunc(),
color.New(color.FgHiRed).SprintFunc(),
color.New(color.FgYellow).SprintFunc(),
color.New(color.FgBlue).SprintFunc(),
color.New(color.FgCyan).SprintFunc(),
} }
) )

View File

@@ -13,7 +13,6 @@ const (
) )
type Vulnerability struct { type Vulnerability struct {
ID string // e.g. CVE-2019-8331, OSVDB-104365
CvssScore float64 CvssScore float64
CvssScoreV3 float64 CvssScoreV3 float64
Severity Severity Severity Severity