Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76ee7291d6 | ||
|
|
d31f09035e | ||
|
|
8d7c2e6d2a | ||
|
|
9269a305fb | ||
|
|
073b315737 | ||
|
|
47c46fbe17 | ||
|
|
39572968bb | ||
|
|
4383764cae | ||
|
|
e0ef0563ce | ||
|
|
d9cf2c487d | ||
|
|
58bf4b21e7 | ||
|
|
e95c619eaa | ||
|
|
cd04c0bdb2 | ||
|
|
fd74926e76 | ||
|
|
f82ff5a4fd | ||
|
|
fa72bef8d4 | ||
|
|
2f7f1f8e83 | ||
|
|
90d083489b | ||
|
|
295cd29aeb | ||
|
|
1c844aad64 | ||
|
|
e0cd18e264 | ||
|
|
9f9faf2215 | ||
|
|
3907a60b33 | ||
|
|
e85e961af6 | ||
|
|
61cbae2697 | ||
|
|
2d512c5e47 | ||
|
|
936297a6b2 | ||
|
|
ad0f9e8cba | ||
|
|
4d20d3f543 | ||
|
|
c3e5227992 | ||
|
|
ff39445db2 | ||
|
|
77e9b0a6d1 |
@@ -1 +1,2 @@
|
||||
.circleci
|
||||
imgs
|
||||
|
||||
30
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<!--
|
||||
You do NOT have to include this information if this is a FEATURE REQUEST
|
||||
|
||||
If this is a BUG REPORT, provide key information from your environment:
|
||||
-->
|
||||
|
||||
**Description**
|
||||
|
||||
<!--
|
||||
Briefly describe the problem you are having in a few paragraphs.
|
||||
-->
|
||||
|
||||
**Steps to reproduce the issue:**
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**What did you expect to happen?**
|
||||
|
||||
|
||||
**What happened instead?**
|
||||
|
||||
|
||||
**Output of `trivy -v`:**
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
**Additional details (base image name, container registry info...):**
|
||||
@@ -11,4 +11,4 @@ RUN apk --no-cache add ca-certificates git
|
||||
COPY --from=builder /trivy /usr/local/bin/trivy
|
||||
RUN chmod +x /usr/local/bin/trivy
|
||||
|
||||
CMD ["trivy"]
|
||||
ENTRYPOINT ["trivy"]
|
||||
|
||||
@@ -89,20 +89,26 @@ OPTIONS:
|
||||
Name: "refresh",
|
||||
Usage: "refresh DB (usually used after version update of trivy)",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "auto-refresh",
|
||||
Usage: "refresh DB automatically when updating version of trivy",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "debug, d",
|
||||
Usage: "debug mode",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cache-dir",
|
||||
Usage: "cache directory",
|
||||
},
|
||||
}
|
||||
|
||||
app.Action = func(c *cli.Context) error {
|
||||
return pkg.Run(c)
|
||||
}
|
||||
app.Action = pkg.Run
|
||||
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
if log.Logger != nil {
|
||||
log.Logger.Fatal(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
6
go.mod
@@ -11,9 +11,9 @@ require (
|
||||
github.com/genuinetools/reg v0.16.0
|
||||
github.com/gliderlabs/ssh v0.1.3 // indirect
|
||||
github.com/golang/protobuf v1.3.1 // indirect
|
||||
github.com/knqyf263/fanal v0.0.0-20190514052804-ca40e6cb0e1a
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20170509080151-9865fe14d09b
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190511063217-d5d543bfc261
|
||||
github.com/knqyf263/fanal v0.0.0-20190521154631-a2dde7e171c6
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190521150559-1ef8521d17a0
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
|
||||
github.com/knqyf263/go-version v1.1.1
|
||||
github.com/mattn/go-colorable v0.1.1 // indirect
|
||||
|
||||
12
go.sum
@@ -114,12 +114,12 @@ github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/knqyf263/berkeleydb v0.0.0-20190501065933-fafe01fb9662/go.mod h1:bu1CcN4tUtoRcI/B/RFHhxMNKFHVq/c3SV+UTyduoXg=
|
||||
github.com/knqyf263/fanal v0.0.0-20190514052804-ca40e6cb0e1a h1:2zG9YY77/Nv+dMcAA3EzRwoUWP0cWmQIuAumhEYZtNQ=
|
||||
github.com/knqyf263/fanal v0.0.0-20190514052804-ca40e6cb0e1a/go.mod h1:HTp1oNm2dPtIooJCspQHukx37GjPpj5DHuqlebTp4TI=
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20170509080151-9865fe14d09b h1:DiDMmSwuY27PJxA2Gs0+uI/bQ/ehKARaGXRdlp+wFis=
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20170509080151-9865fe14d09b/go.mod h1:o8sgWoz3JADecfc/cTYD92/Et1yMqMy0utV1z+VaZao=
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190511063217-d5d543bfc261 h1:RPgPsbEsYj6LuOjZnKl2DvbfodNWRuWKZfWJkrD7l8s=
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190511063217-d5d543bfc261/go.mod h1:gSiqSkOFPstUZu/qZ4wnNJS69PtQQnPl397vxKHJ5mQ=
|
||||
github.com/knqyf263/fanal v0.0.0-20190521154631-a2dde7e171c6 h1:qfIU7I6yo7zWpqqj0Zxt3iWY51N5D3BFUXdMjKjrAXU=
|
||||
github.com/knqyf263/fanal v0.0.0-20190521154631-a2dde7e171c6/go.mod h1:guPOH3Sfj5M4j/LvCOoWmuYCXnjReDIwJO+S89Fje1E=
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d h1:X4cedH4Kn3JPupAwwWuo4AzYp16P0OyLO9d7OnMZc/c=
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d/go.mod h1:o8sgWoz3JADecfc/cTYD92/Et1yMqMy0utV1z+VaZao=
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190521150559-1ef8521d17a0 h1:DOQ2UbTciy48dV9vpZ25BOiShrWIWZwBdMOy7SD1Wow=
|
||||
github.com/knqyf263/go-dep-parser v0.0.0-20190521150559-1ef8521d17a0/go.mod h1:gSiqSkOFPstUZu/qZ4wnNJS69PtQQnPl397vxKHJ5mQ=
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936 h1:HDjRqotkViMNcGMGicb7cgxklx8OwnjtCBmyWEqrRvM=
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
|
||||
github.com/knqyf263/go-rpmdb v0.0.0-20190501070121-10a1c42a10dc/go.mod h1:MrSSvdMpTSymaQWk1yFr9sxFSyQmKMj6jkbvGrchBV8=
|
||||
|
||||
BIN
imgs/alpine.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 12 KiB |
BIN
imgs/centos_include_unfixable.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
imgs/centos_only_fixable.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
imgs/logo.png
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 9.8 KiB |
BIN
imgs/usage1.png
Normal file
|
After Width: | Height: | Size: 315 KiB |
BIN
imgs/usage2.png
Normal file
|
After Width: | Height: | Size: 215 KiB |
24
pkg/db/db.go
@@ -15,11 +15,11 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
db *bolt.DB
|
||||
dbDir = filepath.Join(utils.CacheDir(), "db")
|
||||
db *bolt.DB
|
||||
)
|
||||
|
||||
func Init() (err error) {
|
||||
dbDir := filepath.Join(utils.CacheDir(), "db")
|
||||
if err = os.MkdirAll(dbDir, 0700); err != nil {
|
||||
return xerrors.Errorf("failed to mkdir: %w", err)
|
||||
}
|
||||
@@ -33,10 +33,26 @@ func Init() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Close() error {
|
||||
if err := db.Close(); err != nil {
|
||||
return xerrors.Errorf("failed to close DB: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Reset() error {
|
||||
if err := Close(); err != nil {
|
||||
return xerrors.Errorf("failed to reset DB: %w", err)
|
||||
}
|
||||
|
||||
dbDir := filepath.Join(utils.CacheDir(), "db")
|
||||
if err := os.RemoveAll(dbDir); err != nil {
|
||||
return xerrors.Errorf("failed to reset DB: %w", err)
|
||||
}
|
||||
|
||||
if err := Init(); err != nil {
|
||||
return xerrors.Errorf("failed to reset DB: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -89,9 +105,7 @@ func Put(root *bolt.Bucket, nestedBucket, key string, value interface{}) error {
|
||||
return nested.Put([]byte(key), v)
|
||||
}
|
||||
func BatchUpdate(fn func(tx *bolt.Tx) error) error {
|
||||
err := db.Batch(func(tx *bolt.Tx) error {
|
||||
return fn(tx)
|
||||
})
|
||||
err := db.Batch(fn)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error in batch update: %w", err)
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func CloneOrPull(url, repoPath string) (map[string]struct{}, error) {
|
||||
}
|
||||
log.Logger.Debug("remove an existed directory")
|
||||
|
||||
suffix := " The first time will take a while..."
|
||||
suffix := " It will take a while for the first time..."
|
||||
s := utils.NewSpinner(suffix)
|
||||
s.Start()
|
||||
defer s.Stop()
|
||||
|
||||
@@ -6,9 +6,13 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var Logger *zap.SugaredLogger
|
||||
var (
|
||||
Logger *zap.SugaredLogger
|
||||
debugOption bool
|
||||
)
|
||||
|
||||
func InitLogger(debug bool) (err error) {
|
||||
debugOption = debug
|
||||
Logger, err = newLogger(debug)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error in new logger: %w", err)
|
||||
@@ -29,8 +33,8 @@ func newLogger(debug bool) (*zap.SugaredLogger, error) {
|
||||
Level: level,
|
||||
Encoding: "console",
|
||||
Development: debug,
|
||||
DisableStacktrace: !debug,
|
||||
DisableCaller: !debug,
|
||||
DisableStacktrace: true,
|
||||
DisableCaller: true,
|
||||
EncoderConfig: zapcore.EncoderConfig{
|
||||
TimeKey: "Time",
|
||||
LevelKey: "Level",
|
||||
@@ -53,3 +57,10 @@ func newLogger(debug bool) (*zap.SugaredLogger, error) {
|
||||
|
||||
return logger.Sugar(), nil
|
||||
}
|
||||
|
||||
func Fatal(err error) {
|
||||
if debugOption {
|
||||
Logger.Fatalf("%+v", err)
|
||||
}
|
||||
Logger.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
@@ -16,8 +17,8 @@ import (
|
||||
type Results []Result
|
||||
|
||||
type Result struct {
|
||||
FileName string `json:"file"`
|
||||
Vulnerabilities []vulnerability.DetectedVulnerability
|
||||
FileName string `json:"Target"`
|
||||
Vulnerabilities []vulnerability.DetectedVulnerability `json:"Vulnerabilities"`
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
@@ -50,8 +51,12 @@ func (tw TableWriter) write(result Result) {
|
||||
if len(splittedTitle) >= 12 {
|
||||
title = strings.Join(splittedTitle[:12], " ") + "..."
|
||||
}
|
||||
table.Append([]string{v.PkgName, v.VulnerabilityID, vulnerability.ColorizeSeverity(v.Severity),
|
||||
v.InstalledVersion, v.FixedVersion, title})
|
||||
if tw.Output == os.Stdout {
|
||||
table.Append([]string{v.PkgName, v.VulnerabilityID, vulnerability.ColorizeSeverity(v.Severity),
|
||||
v.InstalledVersion, v.FixedVersion, title})
|
||||
} else {
|
||||
table.Append([]string{v.PkgName, v.VulnerabilityID, v.Severity, v.InstalledVersion, v.FixedVersion, title})
|
||||
}
|
||||
}
|
||||
|
||||
var results []string
|
||||
@@ -79,11 +84,7 @@ type JsonWriter struct {
|
||||
}
|
||||
|
||||
func (jw JsonWriter) Write(results Results) error {
|
||||
out := map[string][]vulnerability.DetectedVulnerability{}
|
||||
for _, result := range results {
|
||||
out[result.FileName] = result.Vulnerabilities
|
||||
}
|
||||
output, err := json.MarshalIndent(out, "", " ")
|
||||
output, err := json.MarshalIndent(results, "", " ")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to marshal json: %w", err)
|
||||
}
|
||||
|
||||
108
pkg/run.go
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/genuinetools/reg/registry"
|
||||
"github.com/knqyf263/fanal/cache"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/utils"
|
||||
@@ -25,13 +26,21 @@ import (
|
||||
func Run(c *cli.Context) (err error) {
|
||||
cliVersion := c.App.Version
|
||||
|
||||
utils.Quiet = c.Bool("quiet")
|
||||
debug := c.Bool("debug")
|
||||
if err = log.InitLogger(debug); err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
|
||||
cacheDir := c.String("cache-dir")
|
||||
if cacheDir != "" {
|
||||
utils.SetCacheDir(cacheDir)
|
||||
}
|
||||
|
||||
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
|
||||
|
||||
if c.Bool("reset") {
|
||||
reset := c.Bool("reset")
|
||||
if reset {
|
||||
log.Logger.Info("Resetting...")
|
||||
if err = cache.Clear(); err != nil {
|
||||
return xerrors.New("failed to remove image layer cache")
|
||||
@@ -42,21 +51,65 @@ func Run(c *cli.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.Bool("clear-cache") {
|
||||
clearCache := c.Bool("clear-cache")
|
||||
if clearCache {
|
||||
log.Logger.Info("Removing image caches...")
|
||||
if err = cache.Clear(); err != nil {
|
||||
return xerrors.New("failed to remove image layer cache")
|
||||
}
|
||||
}
|
||||
|
||||
refresh := c.Bool("refresh")
|
||||
args := c.Args()
|
||||
var noTarget bool
|
||||
filePath := c.String("input")
|
||||
if filePath == "" && len(args) == 0 {
|
||||
log.Logger.Info(`trivy" requires at least 1 argument or --input option.`)
|
||||
cli.ShowAppHelpAndExit(c, 1)
|
||||
noTarget = true
|
||||
if !reset && !clearCache && !refresh {
|
||||
log.Logger.Info(`trivy" requires at least 1 argument or --input option.`)
|
||||
cli.ShowAppHelpAndExit(c, 1)
|
||||
}
|
||||
}
|
||||
|
||||
utils.Quiet = c.Bool("quiet")
|
||||
autoRefresh := c.Bool("auto-refresh")
|
||||
skipUpdate := c.Bool("skip-update")
|
||||
if (refresh || autoRefresh) && skipUpdate {
|
||||
return xerrors.New("The --skip-update option can not be specified with the --refresh or --auto-refresh option")
|
||||
}
|
||||
|
||||
if err = db.Init(); err != nil {
|
||||
return xerrors.Errorf("error in vulnerability DB initialize: %w", err)
|
||||
}
|
||||
|
||||
needRefresh := false
|
||||
dbVersion := db.GetVersion()
|
||||
if dbVersion != "" && dbVersion != cliVersion {
|
||||
if !refresh && !autoRefresh {
|
||||
return xerrors.New("Detected version update of trivy. Please try again with --refresh or --auto-refresh option")
|
||||
}
|
||||
needRefresh = true
|
||||
}
|
||||
|
||||
if refresh || needRefresh {
|
||||
log.Logger.Info("Refreshing DB...")
|
||||
if err = db.Reset(); err != nil {
|
||||
return xerrors.Errorf("error in refresh DB: %w", err)
|
||||
}
|
||||
}
|
||||
if !skipUpdate {
|
||||
if err = vulnsrc.Update(); err != nil {
|
||||
return xerrors.Errorf("error in vulnerability DB update: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = db.SetVersion(cliVersion); err != nil {
|
||||
return xerrors.Errorf("unexpected error: %w", err)
|
||||
}
|
||||
|
||||
// When specifying no image name and file name
|
||||
if noTarget {
|
||||
return nil
|
||||
}
|
||||
|
||||
o := c.String("output")
|
||||
output := os.Stdout
|
||||
@@ -76,40 +129,29 @@ func Run(c *cli.Context) (err error) {
|
||||
severities = append(severities, severity)
|
||||
}
|
||||
|
||||
if c.Bool("refresh") {
|
||||
log.Logger.Info("Resetting DB...")
|
||||
if err = db.Reset(); err != nil {
|
||||
return xerrors.Errorf("error in refresh DB: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = db.Init(); err != nil {
|
||||
return xerrors.Errorf("error in vulnerability DB initialize: %w", err)
|
||||
}
|
||||
|
||||
dbVersion := db.GetVersion()
|
||||
if dbVersion != "" && dbVersion != cliVersion {
|
||||
log.Logger.Fatal("Detected version update of trivy. Please try again with --refresh option")
|
||||
}
|
||||
|
||||
if !c.Bool("skip-update") {
|
||||
if err = vulnsrc.Update(); err != nil {
|
||||
return xerrors.Errorf("error in vulnerability DB update: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
ignoreUnfixed := c.Bool("ignore-unfixed")
|
||||
|
||||
var imageName string
|
||||
if filePath == "" {
|
||||
imageName = args[0]
|
||||
}
|
||||
|
||||
// Check whether 'latest' tag is used
|
||||
if imageName != "" {
|
||||
image, err := registry.ParseImage(imageName)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("invalid image: %w", err)
|
||||
}
|
||||
if image.Tag == "latest" && !clearCache {
|
||||
log.Logger.Warn("You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed")
|
||||
}
|
||||
}
|
||||
|
||||
vulns, err := scanner.ScanImage(imageName, filePath)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error in image scan: %w", err)
|
||||
}
|
||||
|
||||
var results report.Results
|
||||
ignoreUnfixed := c.Bool("ignore-unfixed")
|
||||
for path, vuln := range vulns {
|
||||
results = append(results, report.Result{
|
||||
FileName: path,
|
||||
@@ -118,23 +160,19 @@ func Run(c *cli.Context) (err error) {
|
||||
}
|
||||
|
||||
var writer report.Writer
|
||||
switch c.String("format") {
|
||||
switch format := c.String("format"); format {
|
||||
case "table":
|
||||
writer = &report.TableWriter{Output: output}
|
||||
case "json":
|
||||
writer = &report.JsonWriter{Output: output}
|
||||
default:
|
||||
xerrors.New("unknown format")
|
||||
return xerrors.Errorf("unknown format: %v", format)
|
||||
}
|
||||
|
||||
if err = writer.Write(results); err != nil {
|
||||
return xerrors.Errorf("failed to write results: %w", err)
|
||||
}
|
||||
|
||||
if err = db.SetVersion(cliVersion); err != nil {
|
||||
return xerrors.Errorf("unexpected error: %w", err)
|
||||
}
|
||||
|
||||
exitCode := c.Int("exit-code")
|
||||
if exitCode != 0 {
|
||||
for _, result := range results {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package npm
|
||||
package node
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,30 +1,33 @@
|
||||
package npm
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
version "github.com/knqyf263/go-version"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/knqyf263/go-dep-parser/pkg/npm"
|
||||
ptypes "github.com/knqyf263/go-dep-parser/pkg/types"
|
||||
"github.com/knqyf263/go-version"
|
||||
"github.com/knqyf263/go-dep-parser/pkg/yarn"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
scannerType = "npm"
|
||||
ScannerTypeNpm = "npm"
|
||||
ScannerTypeYarn = "yarn"
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
db AdvisoryDB
|
||||
db AdvisoryDB
|
||||
scannerType string
|
||||
}
|
||||
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{}
|
||||
func NewScanner(scannerType string) *Scanner {
|
||||
return &Scanner{scannerType: scannerType}
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(pkgName string, pkgVer *version.Version) ([]vulnerability.DetectedVulnerability, error) {
|
||||
@@ -72,12 +75,28 @@ func (s *Scanner) Detect(pkgName string, pkgVer *version.Version) ([]vulnerabili
|
||||
}
|
||||
|
||||
func (s *Scanner) ParseLockfile(f *os.File) ([]ptypes.Library, error) {
|
||||
if s.Type() == ScannerTypeNpm {
|
||||
return s.parseNpm(f)
|
||||
}
|
||||
return s.parseYarn(f)
|
||||
}
|
||||
|
||||
func (s *Scanner) parseNpm(f *os.File) ([]ptypes.Library, error) {
|
||||
libs, err := npm.Parse(f)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid package-lock.json format: %w", err)
|
||||
}
|
||||
return libs, nil
|
||||
}
|
||||
func (s *Scanner) Type() string {
|
||||
return scannerType
|
||||
|
||||
func (s *Scanner) parseYarn(f *os.File) ([]ptypes.Library, error) {
|
||||
libs, err := yarn.Parse(f)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid yarn.lock format: %w", err)
|
||||
}
|
||||
return libs, nil
|
||||
}
|
||||
|
||||
func (s *Scanner) Type() string {
|
||||
return s.scannerType
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package pipenv
|
||||
package python
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package pipenv
|
||||
package python
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -9,21 +9,24 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/knqyf263/go-dep-parser/pkg/pipenv"
|
||||
"github.com/knqyf263/go-dep-parser/pkg/poetry"
|
||||
ptypes "github.com/knqyf263/go-dep-parser/pkg/types"
|
||||
"github.com/knqyf263/go-version"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
scannerType = "pipenv"
|
||||
ScannerTypePipenv = "pipenv"
|
||||
ScannerTypePoetry = "poetry"
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
db AdvisoryDB
|
||||
db AdvisoryDB
|
||||
scannerType string
|
||||
}
|
||||
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{}
|
||||
func NewScanner(scannerType string) *Scanner {
|
||||
return &Scanner{scannerType: scannerType}
|
||||
}
|
||||
|
||||
func (s *Scanner) Detect(pkgName string, pkgVer *version.Version) ([]vulnerability.DetectedVulnerability, error) {
|
||||
@@ -63,12 +66,28 @@ func createFixedVersions(specs []string) string {
|
||||
}
|
||||
|
||||
func (s *Scanner) ParseLockfile(f *os.File) ([]ptypes.Library, error) {
|
||||
if s.Type() == ScannerTypePipenv {
|
||||
return s.parsePipenv(f)
|
||||
}
|
||||
return s.parsePoetry(f)
|
||||
}
|
||||
|
||||
func (s *Scanner) parsePipenv(f *os.File) ([]ptypes.Library, error) {
|
||||
libs, err := pipenv.Parse(f)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid Pipfile.lock format: %w", err)
|
||||
}
|
||||
return libs, nil
|
||||
}
|
||||
func (s *Scanner) Type() string {
|
||||
return scannerType
|
||||
|
||||
func (s *Scanner) parsePoetry(f *os.File) ([]ptypes.Library, error) {
|
||||
libs, err := poetry.Parse(f)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid poetry.lock format: %w", err)
|
||||
}
|
||||
return libs, nil
|
||||
}
|
||||
|
||||
func (s *Scanner) Type() string {
|
||||
return s.scannerType
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
_ "github.com/knqyf263/fanal/analyzer/library/composer"
|
||||
_ "github.com/knqyf263/fanal/analyzer/library/npm"
|
||||
_ "github.com/knqyf263/fanal/analyzer/library/pipenv"
|
||||
_ "github.com/knqyf263/fanal/analyzer/library/poetry"
|
||||
_ "github.com/knqyf263/fanal/analyzer/library/yarn"
|
||||
"github.com/knqyf263/fanal/extractor"
|
||||
ptypes "github.com/knqyf263/go-dep-parser/pkg/types"
|
||||
"github.com/knqyf263/go-version"
|
||||
@@ -19,8 +21,8 @@ import (
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/bundler"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/cargo"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/composer"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/npm"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/pipenv"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/node"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library/python"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
@@ -41,9 +43,13 @@ func NewScanner(filename string) Scanner {
|
||||
case "composer.lock":
|
||||
scanner = composer.NewScanner()
|
||||
case "package-lock.json":
|
||||
scanner = npm.NewScanner()
|
||||
scanner = node.NewScanner(node.ScannerTypeNpm)
|
||||
case "yarn.lock":
|
||||
scanner = node.NewScanner(node.ScannerTypeYarn)
|
||||
case "Pipfile.lock":
|
||||
scanner = pipenv.NewScanner()
|
||||
scanner = python.NewScanner(python.ScannerTypePipenv)
|
||||
case "poetry.lock":
|
||||
scanner = python.NewScanner(python.ScannerTypePoetry)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@@ -69,9 +75,7 @@ func Scan(files extractor.FileMap) (map[string][]vulnerability.DetectedVulnerabi
|
||||
return nil, xerrors.Errorf("failed to scan %s vulnerabilities: %w", scanner.Type(), err)
|
||||
}
|
||||
|
||||
if len(vulns) != 0 {
|
||||
vulnerabilities[string(path)] = vulns
|
||||
}
|
||||
vulnerabilities[string(path)] = vulns
|
||||
}
|
||||
return vulnerabilities, nil
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
_ "github.com/knqyf263/fanal/analyzer/command/apk"
|
||||
fos "github.com/knqyf263/fanal/analyzer/os"
|
||||
_ "github.com/knqyf263/fanal/analyzer/os/alpine"
|
||||
_ "github.com/knqyf263/fanal/analyzer/os/amazonlinux"
|
||||
_ "github.com/knqyf263/fanal/analyzer/os/debianbase"
|
||||
_ "github.com/knqyf263/fanal/analyzer/os/opensuse"
|
||||
_ "github.com/knqyf263/fanal/analyzer/os/redhatbase"
|
||||
_ "github.com/knqyf263/fanal/analyzer/pkg/apk"
|
||||
_ "github.com/knqyf263/fanal/analyzer/pkg/dpkg"
|
||||
@@ -41,7 +43,8 @@ func Scan(files extractor.FileMap) (string, string, []vulnerability.DetectedVuln
|
||||
case fos.RedHat, fos.CentOS:
|
||||
s = redhat.NewScanner()
|
||||
default:
|
||||
return "", "", nil, xerrors.New("unsupported os")
|
||||
log.Logger.Warnf("unsupported os : %s", os.Family)
|
||||
return "", "", nil, nil
|
||||
}
|
||||
pkgs, err := analyzer.GetPackages(files)
|
||||
if err != nil {
|
||||
|
||||
@@ -6,22 +6,13 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
|
||||
"github.com/genuinetools/reg/registry"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/log"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
|
||||
|
||||
"github.com/knqyf263/trivy/pkg/scanner/ospkg"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/knqyf263/fanal/analyzer"
|
||||
"github.com/knqyf263/fanal/extractor"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/library"
|
||||
"github.com/knqyf263/trivy/pkg/scanner/ospkg"
|
||||
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func ScanImage(imageName, filePath string) (map[string][]vulnerability.DetectedVulnerability, error) {
|
||||
@@ -29,14 +20,6 @@ func ScanImage(imageName, filePath string) (map[string][]vulnerability.DetectedV
|
||||
results := map[string][]vulnerability.DetectedVulnerability{}
|
||||
ctx := context.Background()
|
||||
|
||||
image, err := registry.ParseImage(imageName)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid image: %w", err)
|
||||
}
|
||||
if image.Tag == "latest" {
|
||||
log.Logger.Warn("You should avoid using the :latest tag as it is cached. You need to specify '--clean' option when :latest image is changed")
|
||||
}
|
||||
|
||||
var target string
|
||||
var files extractor.FileMap
|
||||
if imageName != "" {
|
||||
@@ -65,8 +48,10 @@ func ScanImage(imageName, filePath string) (map[string][]vulnerability.DetectedV
|
||||
return nil, xerrors.Errorf("failed to scan image: %w", err)
|
||||
|
||||
}
|
||||
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
|
||||
results[imageDetail] = osVulns
|
||||
if osFamily != "" {
|
||||
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
|
||||
results[imageDetail] = osVulns
|
||||
}
|
||||
|
||||
libVulns, err := library.Scan(files)
|
||||
if err != nil {
|
||||
|
||||
@@ -12,15 +12,24 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var cacheDir string
|
||||
|
||||
func CacheDir() string {
|
||||
cacheDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
cacheDir = os.TempDir()
|
||||
if cacheDir == "" {
|
||||
var err error
|
||||
cacheDir, err = os.UserCacheDir()
|
||||
if err != nil {
|
||||
cacheDir = os.TempDir()
|
||||
}
|
||||
}
|
||||
dir := filepath.Join(cacheDir, "trivy")
|
||||
return dir
|
||||
}
|
||||
|
||||
func SetCacheDir(cd string) {
|
||||
cacheDir = cd
|
||||
}
|
||||
|
||||
func FileWalk(root string, targetFiles map[string]struct{}, walkFn func(r io.Reader, path string) error) error {
|
||||
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
|
||||
@@ -89,17 +89,16 @@ func getDetail(vulnID string) (Severity, string, string, []string) {
|
||||
|
||||
func getSeverity(details map[string]Vulnerability) Severity {
|
||||
for _, source := range sources {
|
||||
d, ok := details[source]
|
||||
if !ok {
|
||||
switch d, ok := details[source]; {
|
||||
case !ok:
|
||||
continue
|
||||
}
|
||||
if d.CvssScore > 0 {
|
||||
case d.CvssScore > 0:
|
||||
return scoreToSeverity(d.CvssScore)
|
||||
} else if d.CvssScoreV3 > 0 {
|
||||
case d.CvssScoreV3 > 0:
|
||||
return scoreToSeverity(d.CvssScoreV3)
|
||||
} else if d.Severity != 0 {
|
||||
case d.Severity != 0:
|
||||
return d.Severity
|
||||
} else if d.SeverityV3 != 0 {
|
||||
case d.SeverityV3 != 0:
|
||||
return d.SeverityV3
|
||||
}
|
||||
}
|
||||
@@ -151,14 +150,16 @@ func getReferences(details map[string]Vulnerability) []string {
|
||||
}
|
||||
|
||||
func scoreToSeverity(score float64) Severity {
|
||||
if score >= 9.0 {
|
||||
switch {
|
||||
case score >= 9.0:
|
||||
return SeverityCritical
|
||||
} else if score >= 7.0 {
|
||||
case score >= 7.0:
|
||||
return SeverityHigh
|
||||
} else if score >= 4.0 {
|
||||
case score >= 4.0:
|
||||
return SeverityMedium
|
||||
} else if score > 0.0 {
|
||||
case score > 0.0:
|
||||
return SeverityLow
|
||||
default:
|
||||
return SeverityUnknown
|
||||
}
|
||||
return SeverityUnknown
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func Update() (err error) {
|
||||
return xerrors.Errorf("error in Alpine OVAL update: %w", err)
|
||||
}
|
||||
|
||||
//Update RedHat
|
||||
// Update RedHat
|
||||
log.Logger.Info("Updating RedHat data...")
|
||||
if err = redhat.Update(dir, updatedFiles); err != nil {
|
||||
return xerrors.Errorf("error in RedHat update: %w", err)
|
||||
@@ -65,7 +65,7 @@ func Update() (err error) {
|
||||
return xerrors.Errorf("error in Debian OVAL update: %w", err)
|
||||
}
|
||||
|
||||
//Update Ubuntu
|
||||
// Update Ubuntu
|
||||
log.Logger.Info("Updating Ubuntu data...")
|
||||
if err = ubuntu.Update(dir, updatedFiles); err != nil {
|
||||
return xerrors.Errorf("error in Ubuntu update: %w", err)
|
||||
|
||||