mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 07:40:48 -08:00
Add linter check support (#679)
* add linter supports * add only minor version * use latest version * Fix println with format issue * Fix test * Fix tests * For slice with unknown length, preallocating the array * fix code-coverage * Removed linter rules * Reverting linter fixes, adding TODO for later * Ignore linter error for import * Remove another err var. * Ignore shadow error * Fixes * Fix issue * Add back goimports local-prefixes * Update local prefixes * Removed extra spaces and merge the imports * more refactoring * Update photon.go Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
This commit is contained in:
12
.github/workflows/test.yaml
vendored
12
.github/workflows/test.yaml
vendored
@@ -1,6 +1,17 @@
|
||||
name: Test
|
||||
on: pull_request
|
||||
jobs:
|
||||
golangci:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
version: v1.31
|
||||
args: --deadline=30m
|
||||
|
||||
integration:
|
||||
name: Integration Test
|
||||
runs-on: ubuntu-latest
|
||||
@@ -34,3 +45,4 @@ jobs:
|
||||
with:
|
||||
version: latest
|
||||
args: release --snapshot --rm-dist --skip-publish
|
||||
|
||||
|
||||
71
.golangci.yaml
Normal file
71
.golangci.yaml
Normal file
@@ -0,0 +1,71 @@
|
||||
linters-settings:
|
||||
errcheck:
|
||||
check-type-assertions: true
|
||||
check-blank: true
|
||||
govet:
|
||||
check-shadowing: false
|
||||
gofmt:
|
||||
simplify: false
|
||||
golint:
|
||||
min-confidence: 0
|
||||
gocyclo:
|
||||
min-complexity: 10
|
||||
maligned:
|
||||
suggest-new: true
|
||||
dupl:
|
||||
threshold: 100
|
||||
goconst:
|
||||
min-len: 3
|
||||
min-occurrences: 3
|
||||
misspell:
|
||||
locale: US
|
||||
goimports:
|
||||
local-prefixes: github.com/aquasecurity
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- structcheck
|
||||
- ineffassign
|
||||
- typecheck
|
||||
- govet
|
||||
- errcheck
|
||||
- varcheck
|
||||
- deadcode
|
||||
- golint
|
||||
- gosec
|
||||
- unconvert
|
||||
- goconst
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
- maligned
|
||||
- misspell
|
||||
|
||||
run:
|
||||
skip-files:
|
||||
- ".*._mock.go$"
|
||||
- ".*._test.go$"
|
||||
- "integration/*"
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
- linters:
|
||||
- gosec
|
||||
text: "G304: Potential file inclusion"
|
||||
- linters:
|
||||
- gosec
|
||||
text: "Deferring unsafe method"
|
||||
- linters:
|
||||
- errcheck
|
||||
text: "Close` is not checked"
|
||||
- linters:
|
||||
- errcheck
|
||||
text: "os.*` is not checked"
|
||||
- linters:
|
||||
- golint
|
||||
text: "a blank import should be only in a main or test package"
|
||||
exclude:
|
||||
- "should have a package comment, unless it's in another file for this package"
|
||||
exclude-use-default: false
|
||||
max-same-issues: 0
|
||||
2
go.mod
2
go.mod
@@ -34,4 +34,4 @@ require (
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f
|
||||
)
|
||||
)
|
||||
2
go.sum
2
go.sum
@@ -748,4 +748,4 @@ moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
@@ -15,12 +15,14 @@ import (
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
// RegistryConfig holds the config for docker registry
|
||||
type RegistryConfig struct {
|
||||
URL *url.URL
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// GetAuthConfig returns the docker registry authConfig
|
||||
func (c RegistryConfig) GetAuthConfig() types.AuthConfig {
|
||||
return types.AuthConfig{
|
||||
Username: c.Username,
|
||||
@@ -29,6 +31,7 @@ func (c RegistryConfig) GetAuthConfig() types.AuthConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// GetRegistryAuth returns the json encoded docker registry auth
|
||||
func (c RegistryConfig) GetRegistryAuth() (string, error) {
|
||||
authConfig := types.AuthConfig{
|
||||
Username: c.Username,
|
||||
@@ -41,10 +44,12 @@ func (c RegistryConfig) GetRegistryAuth() (string, error) {
|
||||
return base64.URLEncoding.EncodeToString(encodedJSON), nil
|
||||
}
|
||||
|
||||
// Docker returns docker client
|
||||
type Docker struct {
|
||||
cli *client.Client
|
||||
}
|
||||
|
||||
// New is the factory method to return docker client
|
||||
func New() (Docker, error) {
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
if err != nil {
|
||||
@@ -73,7 +78,7 @@ func (d Docker) ReplicateImage(ctx context.Context, imageRef, imagePath string,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil {
|
||||
if _, err = io.Copy(ioutil.Discard, resp.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/vulnerability"
|
||||
)
|
||||
|
||||
// VersionInfo holds the trivy DB version Info
|
||||
type VersionInfo struct {
|
||||
Version string `json:",omitempty"`
|
||||
VulnerabilityDB *db.Metadata `json:",omitempty"`
|
||||
@@ -250,6 +251,7 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// NewApp is the factory method to return Trivy CLI
|
||||
func NewApp(version string) *cli.App {
|
||||
cli.VersionPrinter = func(c *cli.Context) {
|
||||
showVersion(c.String("cache-dir"), c.String("format"), c.App.Version, c.App.Writer)
|
||||
@@ -307,7 +309,7 @@ func setHidden(flags []cli.Flag, hidden bool) []cli.Flag {
|
||||
func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer) {
|
||||
var dbMeta *db.Metadata
|
||||
|
||||
metadata, _ := tdb.NewMetadata(afero.NewOsFs(), cacheDir).Get()
|
||||
metadata, _ := tdb.NewMetadata(afero.NewOsFs(), cacheDir).Get() // nolint: errcheck
|
||||
if !metadata.UpdatedAt.IsZero() && !metadata.NextUpdate.IsZero() && metadata.Version != 0 {
|
||||
dbMeta = &db.Metadata{
|
||||
Version: metadata.Version,
|
||||
@@ -319,7 +321,7 @@ func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer)
|
||||
|
||||
switch outputFormat {
|
||||
case "json":
|
||||
b, _ := json.Marshal(VersionInfo{
|
||||
b, _ := json.Marshal(VersionInfo{ // nolint: errcheck
|
||||
Version: version,
|
||||
VulnerabilityDB: dbMeta,
|
||||
})
|
||||
@@ -345,6 +347,7 @@ func showVersion(cacheDir, outputFormat, version string, outputWriter io.Writer)
|
||||
}
|
||||
}
|
||||
|
||||
// NewImageCommand is the factory method to add image command
|
||||
func NewImageCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "image",
|
||||
@@ -356,6 +359,7 @@ func NewImageCommand() *cli.Command {
|
||||
}
|
||||
}
|
||||
|
||||
// NewFilesystemCommand is the factory method to add filesystem command
|
||||
func NewFilesystemCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "filesystem",
|
||||
@@ -389,6 +393,7 @@ func NewFilesystemCommand() *cli.Command {
|
||||
}
|
||||
}
|
||||
|
||||
// NewRepositoryCommand is the factory method to add repository command
|
||||
func NewRepositoryCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "repository",
|
||||
@@ -422,6 +427,7 @@ func NewRepositoryCommand() *cli.Command {
|
||||
}
|
||||
}
|
||||
|
||||
// NewClientCommand is the factory method to add client command
|
||||
func NewClientCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "client",
|
||||
@@ -465,6 +471,7 @@ func NewClientCommand() *cli.Command {
|
||||
}
|
||||
}
|
||||
|
||||
// NewServerCommand is the factory method to add server command
|
||||
func NewServerCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "server",
|
||||
|
||||
@@ -109,3 +109,12 @@ Vulnerability DB:
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCommands(t *testing.T) {
|
||||
NewApp("test")
|
||||
NewClientCommand()
|
||||
NewFilesystemCommand()
|
||||
NewImageCommand()
|
||||
NewRepositoryCommand()
|
||||
NewServerCommand()
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/internal/config"
|
||||
)
|
||||
|
||||
// Config holds the artifact config
|
||||
type Config struct {
|
||||
config.GlobalConfig
|
||||
config.ArtifactConfig
|
||||
@@ -22,6 +23,7 @@ type Config struct {
|
||||
autoRefresh bool
|
||||
}
|
||||
|
||||
// New is the factory method to return config
|
||||
func New(c *cli.Context) (Config, error) {
|
||||
gc, err := config.NewGlobalConfig(c)
|
||||
if err != nil {
|
||||
@@ -41,6 +43,7 @@ func New(c *cli.Context) (Config, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Init initializes the artifact config
|
||||
func (c *Config) Init(image bool) error {
|
||||
if err := c.ReportConfig.Init(c.Logger); err != nil {
|
||||
return err
|
||||
@@ -53,7 +56,7 @@ func (c *Config) Init(image bool) error {
|
||||
}
|
||||
|
||||
// --clear-cache, --download-db-only and --reset don't conduct the scan
|
||||
if c.ClearCache || c.DownloadDBOnly || c.Reset {
|
||||
if c.skipScan() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -69,3 +72,10 @@ func (c *Config) Init(image bool) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) skipScan() bool {
|
||||
if c.ClearCache || c.DownloadDBOnly || c.Reset {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ func filesystemScanner(ctx context.Context, dir string, ac cache.ArtifactCache,
|
||||
return s, cleanup, nil
|
||||
}
|
||||
|
||||
// FilesystemRun runs scan on filesystem
|
||||
func FilesystemRun(cliCtx *cli.Context) error {
|
||||
c, err := config.New(cliCtx)
|
||||
if err != nil {
|
||||
|
||||
@@ -30,6 +30,7 @@ func dockerScanner(ctx context.Context, imageName string, ac cache.ArtifactCache
|
||||
return s, cleanup, nil
|
||||
}
|
||||
|
||||
// ImageRun runs scan on docker image
|
||||
func ImageRun(cliCtx *cli.Context) error {
|
||||
c, err := config.New(cliCtx)
|
||||
if err != nil {
|
||||
|
||||
@@ -21,6 +21,7 @@ func repositoryScanner(ctx context.Context, dir string, ac cache.ArtifactCache,
|
||||
return s, cleanup, nil
|
||||
}
|
||||
|
||||
// RepositoryRun runs scan on repository
|
||||
func RepositoryRun(cliCtx *cli.Context) error {
|
||||
c, err := config.New(cliCtx)
|
||||
if err != nil {
|
||||
|
||||
@@ -19,9 +19,12 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
)
|
||||
|
||||
// InitializeScanner type to define initialize function signature
|
||||
type InitializeScanner func(context.Context, string, cache.ArtifactCache, cache.LocalArtifactCache, time.Duration) (
|
||||
scanner.Scanner, func(), error)
|
||||
|
||||
// nolint: gocyclo
|
||||
// TODO: refactror and fix cyclometic complexity
|
||||
func run(c config.Config, initializeScanner InitializeScanner) error {
|
||||
if err := log.InitLogger(c.Debug, c.Quiet); err != nil {
|
||||
l.Fatal(err)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/internal/config"
|
||||
)
|
||||
|
||||
// Config holds the Trivy client config
|
||||
type Config struct {
|
||||
config.GlobalConfig
|
||||
config.ArtifactConfig
|
||||
@@ -25,6 +26,7 @@ type Config struct {
|
||||
CustomHeaders http.Header
|
||||
}
|
||||
|
||||
// New is the factory method for Config
|
||||
func New(c *cli.Context) (Config, error) {
|
||||
gc, err := config.NewGlobalConfig(c)
|
||||
if err != nil {
|
||||
@@ -43,6 +45,7 @@ func New(c *cli.Context) (Config, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Init initializes the config
|
||||
func (c *Config) Init() (err error) {
|
||||
// --clear-cache doesn't conduct the scan
|
||||
if c.ClearCache {
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
)
|
||||
|
||||
// Run runs the scan
|
||||
func Run(cliCtx *cli.Context) error {
|
||||
c, err := config.New(cliCtx)
|
||||
if err != nil {
|
||||
@@ -25,6 +26,8 @@ func Run(cliCtx *cli.Context) error {
|
||||
return run(c)
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
// TODO: refactror and fix cyclometic complexity
|
||||
func run(c config.Config) (err error) {
|
||||
if err = log.InitLogger(c.Debug, c.Quiet); err != nil {
|
||||
return xerrors.Errorf("failed to initialize a logger: %w", err)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// ArtifactConfig holds the config for a artifact scanning
|
||||
type ArtifactConfig struct {
|
||||
Input string
|
||||
Timeout time.Duration
|
||||
@@ -24,6 +25,7 @@ type ArtifactConfig struct {
|
||||
Target string
|
||||
}
|
||||
|
||||
// NewArtifactConfig is the factory method to return artifact config
|
||||
func NewArtifactConfig(c *cli.Context) ArtifactConfig {
|
||||
return ArtifactConfig{
|
||||
Input: c.String("input"),
|
||||
@@ -34,10 +36,11 @@ func NewArtifactConfig(c *cli.Context) ArtifactConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// Init initialize the CLI context for artifact scanning
|
||||
func (c *ArtifactConfig) Init(ctx *cli.Context, logger *zap.SugaredLogger) (err error) {
|
||||
if c.Input == "" && ctx.Args().Len() == 0 {
|
||||
logger.Debug(`trivy requires at least 1 argument or --input option`)
|
||||
_ = cli.ShowSubcommandHelp(ctx)
|
||||
_ = cli.ShowSubcommandHelp(ctx) // nolint: errcheck
|
||||
os.Exit(0)
|
||||
} else if ctx.Args().Len() > 1 {
|
||||
logger.Error(`multiple targets cannot be specified`)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// DBConfig holds the config for trivy DB
|
||||
type DBConfig struct {
|
||||
Reset bool
|
||||
DownloadDBOnly bool
|
||||
@@ -13,6 +14,7 @@ type DBConfig struct {
|
||||
NoProgress bool
|
||||
}
|
||||
|
||||
// NewDBConfig is the factory method to return the DBConfig
|
||||
func NewDBConfig(c *cli.Context) DBConfig {
|
||||
return DBConfig{
|
||||
Reset: c.Bool("reset"),
|
||||
@@ -23,6 +25,7 @@ func NewDBConfig(c *cli.Context) DBConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// Init initialize the DBConfig
|
||||
func (c *DBConfig) Init() (err error) {
|
||||
if c.SkipUpdate && c.DownloadDBOnly {
|
||||
return xerrors.New("--skip-update and --download-db-only options can not be specified both")
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
// GlobalConfig holds the global config for trivy
|
||||
type GlobalConfig struct {
|
||||
Context *cli.Context
|
||||
Logger *zap.SugaredLogger
|
||||
@@ -18,6 +19,7 @@ type GlobalConfig struct {
|
||||
CacheDir string
|
||||
}
|
||||
|
||||
// NewGlobalConfig is the factory method to return GlobalConfig
|
||||
func NewGlobalConfig(c *cli.Context) (GlobalConfig, error) {
|
||||
quiet := c.Bool("quiet")
|
||||
debug := c.Bool("debug")
|
||||
|
||||
@@ -7,11 +7,13 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// ImageConfig holds the config for scanning images
|
||||
type ImageConfig struct {
|
||||
ScanRemovedPkgs bool
|
||||
ListAllPkgs bool
|
||||
}
|
||||
|
||||
// NewImageConfig is the factory method to return imageConfig
|
||||
func NewImageConfig(c *cli.Context) ImageConfig {
|
||||
return ImageConfig{
|
||||
ScanRemovedPkgs: c.Bool("removed-pkgs"),
|
||||
@@ -19,6 +21,7 @@ func NewImageConfig(c *cli.Context) ImageConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes the imageConfig
|
||||
func (c *ImageConfig) Init(args cli.Args, logger *zap.SugaredLogger) (err error) {
|
||||
imageName := args.First()
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
)
|
||||
|
||||
// ReportConfig holds the config for reporting scan results
|
||||
type ReportConfig struct {
|
||||
Format string
|
||||
Template string
|
||||
@@ -31,6 +32,7 @@ type ReportConfig struct {
|
||||
Severities []dbTypes.Severity
|
||||
}
|
||||
|
||||
// NewReportConfig is the factory method to return ReportConfig
|
||||
func NewReportConfig(c *cli.Context) ReportConfig {
|
||||
return ReportConfig{
|
||||
output: c.String("output"),
|
||||
@@ -46,6 +48,7 @@ func NewReportConfig(c *cli.Context) ReportConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes the ReportConfig
|
||||
func (c *ReportConfig) Init(logger *zap.SugaredLogger) (err error) {
|
||||
if c.Template != "" {
|
||||
if c.Format == "" {
|
||||
|
||||
@@ -15,20 +15,24 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
)
|
||||
|
||||
// SuperSet binds cache dependencies
|
||||
var SuperSet = wire.NewSet(
|
||||
cache.NewFSCache,
|
||||
wire.Bind(new(cache.LocalArtifactCache), new(cache.FSCache)),
|
||||
NewCache,
|
||||
)
|
||||
|
||||
// Cache implements the local cache
|
||||
type Cache struct {
|
||||
client cache.LocalArtifactCache
|
||||
}
|
||||
|
||||
// NewCache is the factory method for Cache
|
||||
func NewCache(client cache.LocalArtifactCache) Cache {
|
||||
return Cache{client: client}
|
||||
}
|
||||
|
||||
// Reset resets the cache
|
||||
func (c Cache) Reset() (err error) {
|
||||
if err := c.ClearDB(); err != nil {
|
||||
return xerrors.Errorf("failed to clear the database: %w", err)
|
||||
@@ -39,6 +43,7 @@ func (c Cache) Reset() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearDB clears the DB cache
|
||||
func (c Cache) ClearDB() (err error) {
|
||||
log.Logger.Info("Removing DB file...")
|
||||
if err = os.RemoveAll(utils.CacheDir()); err != nil {
|
||||
@@ -47,6 +52,7 @@ func (c Cache) ClearDB() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearImages clears the cache images
|
||||
func (c Cache) ClearImages() error {
|
||||
log.Logger.Info("Removing image caches...")
|
||||
if err := c.client.Clear(); err != nil {
|
||||
@@ -55,6 +61,7 @@ func (c Cache) ClearImages() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DownloadDB downloads the DB
|
||||
func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) error {
|
||||
client := initializeDBClient(cacheDir, quiet)
|
||||
ctx := context.Background()
|
||||
@@ -66,7 +73,7 @@ func DownloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) erro
|
||||
if needsUpdate {
|
||||
log.Logger.Info("Need to update DB")
|
||||
log.Logger.Info("Downloading DB...")
|
||||
if err := client.Download(ctx, cacheDir, light); err != nil {
|
||||
if err = client.Download(ctx, cacheDir, light); err != nil {
|
||||
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
|
||||
}
|
||||
if err = client.UpdateMetadata(cacheDir); err != nil {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/aquasecurity/trivy/internal/config"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/aquasecurity/trivy/internal/config"
|
||||
)
|
||||
|
||||
// Config holds the Trivy config
|
||||
type Config struct {
|
||||
config.GlobalConfig
|
||||
config.DBConfig
|
||||
@@ -14,10 +16,10 @@ type Config struct {
|
||||
TokenHeader string
|
||||
}
|
||||
|
||||
// New is the factory method to return cofig
|
||||
func New(c *cli.Context) Config {
|
||||
// the error is ignored because logger is unnecessary
|
||||
gc, _ := config.NewGlobalConfig(c)
|
||||
|
||||
gc, _ := config.NewGlobalConfig(c) // nolint: errcheck
|
||||
return Config{
|
||||
GlobalConfig: gc,
|
||||
DBConfig: config.NewDBConfig(c),
|
||||
@@ -28,6 +30,7 @@ func New(c *cli.Context) Config {
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes the DB config
|
||||
func (c *Config) Init() (err error) {
|
||||
if err := c.DBConfig.Init(); err != nil {
|
||||
return err
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
)
|
||||
|
||||
// Run runs the scan
|
||||
func Run(ctx *cli.Context) error {
|
||||
return run(config.New(ctx))
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func debianEOL() {
|
||||
if len(fields) < 6 && fields[0] != "" {
|
||||
fmt.Printf("\"%s\": time.Date(3000, 1, 1, 23, 59, 59, 0, time.UTC),\n", fields[0])
|
||||
} else if len(fields) == 6 {
|
||||
eol, _ := time.Parse("2006-1-2", fields[5])
|
||||
eol, _ := time.Parse("2006-1-2", fields[5]) // nolint: errcheck
|
||||
fmt.Printf("\"%s\": time.Date(%d, %d, %d, 23, 59, 59, 0, time.UTC),\n", fields[0], eol.Year(), eol.Month(), eol.Day())
|
||||
}
|
||||
}
|
||||
@@ -49,8 +49,7 @@ func ubuntuEOL() {
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
fields := strings.Split(line, ",")
|
||||
|
||||
eol, _ := time.Parse("2006-1-2", fields[len(fields)-1])
|
||||
eol, _ := time.Parse("2006-1-2", fields[len(fields)-1]) // nolint: errcheck
|
||||
fmt.Printf("\"%s\": time.Date(%d, %d, %d, 23, 59, 59, 0, time.UTC),\n", strings.Fields(fields[0])[0], eol.Year(), eol.Month(), eol.Day())
|
||||
}
|
||||
}
|
||||
|
||||
10
pkg/cache/remote.go
vendored
10
pkg/cache/remote.go
vendored
@@ -13,35 +13,41 @@ import (
|
||||
rpcCache "github.com/aquasecurity/trivy/rpc/cache"
|
||||
)
|
||||
|
||||
// RemoteCache implements remote cache
|
||||
type RemoteCache struct {
|
||||
ctx context.Context // for custom header
|
||||
client rpcCache.Cache
|
||||
}
|
||||
|
||||
// RemoteURL to hold remote host
|
||||
type RemoteURL string
|
||||
|
||||
// NewRemoteCache is the factory method for RemoteCache
|
||||
func NewRemoteCache(url RemoteURL, customHeaders http.Header) cache.ArtifactCache {
|
||||
ctx := client.WithCustomHeaders(context.Background(), customHeaders)
|
||||
c := rpcCache.NewCacheProtobufClient(string(url), &http.Client{})
|
||||
return &RemoteCache{ctx: ctx, client: c}
|
||||
}
|
||||
|
||||
// PutArtifact sends artifact to remote client
|
||||
func (c RemoteCache) PutArtifact(imageID string, imageInfo types.ArtifactInfo) error {
|
||||
_, err := c.client.PutArtifact(c.ctx, rpc.ConvertToRpcArtifactInfo(imageID, imageInfo))
|
||||
_, err := c.client.PutArtifact(c.ctx, rpc.ConvertToRPCArtifactInfo(imageID, imageInfo))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to store cache on the server: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PutBlob sends blobInfo to remote client
|
||||
func (c RemoteCache) PutBlob(diffID string, layerInfo types.BlobInfo) error {
|
||||
_, err := c.client.PutBlob(c.ctx, rpc.ConvertToRpcBlobInfo(diffID, layerInfo))
|
||||
_, err := c.client.PutBlob(c.ctx, rpc.ConvertToRPCBlobInfo(diffID, layerInfo))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unable to store cache on the server: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MissingBlobs fetches missing blobs from RemoteCache
|
||||
func (c RemoteCache) MissingBlobs(imageID string, layerIDs []string) (bool, []string, error) {
|
||||
layers, err := c.client.MissingBlobs(c.ctx, rpc.ConvertToMissingBlobsRequest(imageID, layerIDs))
|
||||
if err != nil {
|
||||
|
||||
47
pkg/db/db.go
47
pkg/db/db.go
@@ -24,8 +24,11 @@ const (
|
||||
lightDB = "trivy-light.db.gz"
|
||||
|
||||
metadataFile = "metadata.json"
|
||||
|
||||
gb = 1024 * 1024 * 1024
|
||||
)
|
||||
|
||||
// SuperSet binds the dependencies
|
||||
var SuperSet = wire.NewSet(
|
||||
// indicator.ProgressBar
|
||||
indicator.NewProgressBar,
|
||||
@@ -51,6 +54,7 @@ var SuperSet = wire.NewSet(
|
||||
wire.Bind(new(Operation), new(Client)),
|
||||
)
|
||||
|
||||
// Operation defines the DB operations
|
||||
type Operation interface {
|
||||
NeedsUpdate(cliVersion string, skip, light bool) (need bool, err error)
|
||||
Download(ctx context.Context, cacheDir string, light bool) (err error)
|
||||
@@ -62,6 +66,7 @@ type dbOperation interface {
|
||||
StoreMetadata(metadata db.Metadata, dir string) (err error)
|
||||
}
|
||||
|
||||
// Client implements DB operations
|
||||
type Client struct {
|
||||
dbc dbOperation
|
||||
githubClient github.Operation
|
||||
@@ -70,6 +75,7 @@ type Client struct {
|
||||
metadata Metadata
|
||||
}
|
||||
|
||||
// NewClient is the factory method for DB client
|
||||
func NewClient(dbc dbOperation, githubClient github.Operation, pb indicator.ProgressBar, clock clock.Clock, metadata Metadata) Client {
|
||||
return Client{
|
||||
dbc: dbc,
|
||||
@@ -80,6 +86,7 @@ func NewClient(dbc dbOperation, githubClient github.Operation, pb indicator.Prog
|
||||
}
|
||||
}
|
||||
|
||||
// NeedsUpdate check is DB needs update
|
||||
func (c Client) NeedsUpdate(cliVersion string, light, skip bool) (bool, error) {
|
||||
dbType := db.TypeFull
|
||||
if light {
|
||||
@@ -103,18 +110,11 @@ func (c Client) NeedsUpdate(cliVersion string, light, skip bool) (bool, error) {
|
||||
}
|
||||
|
||||
if skip {
|
||||
if db.SchemaVersion != metadata.Version {
|
||||
log.Logger.Error("The local DB is old and needs to be updated")
|
||||
return false, xerrors.New("--skip-update cannot be specified with the old DB")
|
||||
} else if metadata.Type != dbType {
|
||||
if dbType == db.TypeFull {
|
||||
log.Logger.Error("The local DB is a lightweight DB. You have to download a full DB")
|
||||
} else {
|
||||
log.Logger.Error("The local DB is a full DB. You have to download a lightweight DB")
|
||||
}
|
||||
return false, xerrors.New("--skip-update cannot be specified with the different schema DB")
|
||||
if err = c.validate(dbType, metadata); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
if db.SchemaVersion == metadata.Version && metadata.Type == dbType &&
|
||||
@@ -125,6 +125,22 @@ func (c Client) NeedsUpdate(cliVersion string, light, skip bool) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (c Client) validate(dbType db.Type, metadata db.Metadata) error {
|
||||
if db.SchemaVersion != metadata.Version {
|
||||
log.Logger.Error("The local DB is old and needs to be updated")
|
||||
return xerrors.New("--skip-update cannot be specified with the old DB")
|
||||
} else if metadata.Type != dbType {
|
||||
if dbType == db.TypeFull {
|
||||
log.Logger.Error("The local DB is a lightweight DB. You have to download a full DB")
|
||||
} else {
|
||||
log.Logger.Error("The local DB is a full DB. You have to download a lightweight DB")
|
||||
}
|
||||
return xerrors.New("--skip-update cannot be specified with the different schema DB")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Download downloads the DB file
|
||||
func (c Client) Download(ctx context.Context, cacheDir string, light bool) error {
|
||||
// Remove the metadata file before downloading DB
|
||||
if err := c.metadata.Delete(); err != nil {
|
||||
@@ -145,7 +161,6 @@ func (c Client) Download(ctx context.Context, cacheDir string, light bool) error
|
||||
bar := c.pb.Start(int64(size))
|
||||
barReader := bar.NewProxyReader(rc)
|
||||
defer bar.Finish()
|
||||
|
||||
gr, err := gzip.NewReader(barReader)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("invalid gzip file: %w", err)
|
||||
@@ -164,13 +179,15 @@ func (c Client) Download(ctx context.Context, cacheDir string, light bool) error
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err = io.Copy(file, gr); err != nil {
|
||||
limited := io.LimitReader(gr, 2*gb)
|
||||
if _, err = io.Copy(file, limited); err != nil {
|
||||
return xerrors.Errorf("failed to save DB file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateMetadata updates the DB metadata
|
||||
func (c Client) UpdateMetadata(cacheDir string) error {
|
||||
log.Logger.Debug("Updating database metadata...")
|
||||
|
||||
@@ -192,11 +209,13 @@ func (c Client) UpdateMetadata(cacheDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Metadata defines the file meta
|
||||
type Metadata struct { // TODO: Move all Metadata things to trivy-db repo
|
||||
fs afero.Fs
|
||||
filePath string
|
||||
}
|
||||
|
||||
// NewMetadata is the factory method for file Metadata
|
||||
func NewMetadata(fs afero.Fs, cacheDir string) Metadata {
|
||||
filePath := MetadataPath(cacheDir)
|
||||
return Metadata{
|
||||
@@ -205,13 +224,14 @@ func NewMetadata(fs afero.Fs, cacheDir string) Metadata {
|
||||
}
|
||||
}
|
||||
|
||||
// MetadataPath returns the metaData file path
|
||||
func MetadataPath(cacheDir string) string {
|
||||
dbPath := db.Path(cacheDir)
|
||||
dbDir := filepath.Dir(dbPath)
|
||||
return filepath.Join(dbDir, metadataFile)
|
||||
}
|
||||
|
||||
// DeleteMetadata deletes the file of database metadata
|
||||
// Delete deletes the file of database metadata
|
||||
func (m Metadata) Delete() error {
|
||||
if err := m.fs.Remove(m.filePath); err != nil {
|
||||
return xerrors.Errorf("unable to remove the metadata file: %w", err)
|
||||
@@ -219,6 +239,7 @@ func (m Metadata) Delete() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the file metadata
|
||||
func (m Metadata) Get() (db.Metadata, error) {
|
||||
f, err := m.fs.Open(m.filePath)
|
||||
if err != nil {
|
||||
|
||||
@@ -19,6 +19,7 @@ type Advisory struct {
|
||||
comparer comparer
|
||||
}
|
||||
|
||||
// NewAdvisory is the factory method of Advisory
|
||||
func NewAdvisory(lang string) *Advisory {
|
||||
return &Advisory{
|
||||
lang: lang,
|
||||
|
||||
@@ -11,20 +11,24 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
// VulnSrc defines the operation on bundler vulnerability
|
||||
type VulnSrc interface {
|
||||
Get(pkgName string) ([]bundlerSrc.Advisory, error)
|
||||
}
|
||||
|
||||
// Advisory implements the bundler VulnSrc
|
||||
type Advisory struct {
|
||||
vs VulnSrc
|
||||
}
|
||||
|
||||
// NewAdvisory is the factory method to return bundler.Advisory
|
||||
func NewAdvisory() *Advisory {
|
||||
return &Advisory{
|
||||
vs: bundlerSrc.NewVulnSrc(),
|
||||
}
|
||||
}
|
||||
|
||||
// DetectVulnerabilities scans and returns Vulnerability in bundler
|
||||
func (a *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
|
||||
advisories, err := a.vs.Get(pkgName)
|
||||
if err != nil {
|
||||
|
||||
@@ -52,11 +52,12 @@ func TestScanner_Detect(t *testing.T) {
|
||||
}
|
||||
|
||||
versionStr := "1.9.25-x64-mingw32"
|
||||
v, _ := semver.NewVersion(versionStr)
|
||||
v, err := semver.NewVersion(versionStr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
vulns, err := s.DetectVulnerabilities("ffi", v)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(vulns))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,24 +3,27 @@ package cargo
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cargoSrc "github.com/aquasecurity/trivy-db/pkg/vulnsrc/cargo"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"golang.org/x/xerrors"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
// Advisory encapsulates the cargo vulnerability scanner
|
||||
type Advisory struct {
|
||||
vs cargoSrc.VulnSrc
|
||||
}
|
||||
|
||||
// NewAdvisory is the factory method to return cargo Scanner
|
||||
func NewAdvisory() *Advisory {
|
||||
return &Advisory{
|
||||
vs: cargoSrc.NewVulnSrc(),
|
||||
}
|
||||
}
|
||||
|
||||
// DetectVulnerabilities scans and returns the cargo vulnerabilities
|
||||
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
|
||||
advisories, err := s.vs.Get(pkgName)
|
||||
if err != nil {
|
||||
|
||||
@@ -14,16 +14,19 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
)
|
||||
|
||||
// Advisory encapsulates composer.VulnSrc
|
||||
type Advisory struct {
|
||||
vs composerSrc.VulnSrc
|
||||
}
|
||||
|
||||
// NewAdvisory is the factory method of Advisory
|
||||
func NewAdvisory() *Advisory {
|
||||
return &Advisory{
|
||||
vs: composerSrc.NewVulnSrc(),
|
||||
}
|
||||
}
|
||||
|
||||
// DetectVulnerabilities returns the vulnerabilities in a package
|
||||
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
|
||||
ref := fmt.Sprintf("composer://%s", pkgName)
|
||||
advisories, err := s.vs.Get(ref)
|
||||
|
||||
@@ -4,19 +4,17 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
|
||||
"github.com/google/wire"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
|
||||
"github.com/google/wire"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
// SuperSet binds the dependencies for library scan
|
||||
var SuperSet = wire.NewSet(
|
||||
wire.Struct(new(DriverFactory)),
|
||||
wire.Bind(new(Factory), new(DriverFactory)),
|
||||
@@ -24,18 +22,22 @@ var SuperSet = wire.NewSet(
|
||||
wire.Bind(new(Operation), new(Detector)),
|
||||
)
|
||||
|
||||
// Operation defines library scan operations
|
||||
type Operation interface {
|
||||
Detect(imageName string, filePath string, created time.Time, pkgs []ftypes.LibraryInfo) (vulns []types.DetectedVulnerability, err error)
|
||||
}
|
||||
|
||||
// Detector implements driverFactory
|
||||
type Detector struct {
|
||||
driverFactory Factory
|
||||
}
|
||||
|
||||
// NewDetector is the factory method for detector
|
||||
func NewDetector(factory Factory) Detector {
|
||||
return Detector{driverFactory: factory}
|
||||
}
|
||||
|
||||
// Detect scans and returns vulnerabilities of library
|
||||
func (d Detector) Detect(_, filePath string, _ time.Time, pkgs []ftypes.LibraryInfo) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Debugf("Detecting library vulnerabilities, path: %s", filePath)
|
||||
driver, err := d.driverFactory.NewDriver(filepath.Base(filePath))
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
ecosystem "github.com/aquasecurity/trivy-db/pkg/vulnsrc/ghsa"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/library/bundler"
|
||||
@@ -13,9 +15,9 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/detector/library/node"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/library/python"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// Factory defines library operations
|
||||
type Factory interface {
|
||||
NewDriver(filename string) (Driver, error)
|
||||
}
|
||||
@@ -24,8 +26,10 @@ type advisory interface {
|
||||
DetectVulnerabilities(string, *semver.Version) ([]types.DetectedVulnerability, error)
|
||||
}
|
||||
|
||||
// DriverFactory implements Factory
|
||||
type DriverFactory struct{}
|
||||
|
||||
// NewDriver factory method for driver
|
||||
func (d DriverFactory) NewDriver(filename string) (Driver, error) {
|
||||
// TODO: use DI
|
||||
var driver Driver
|
||||
@@ -46,28 +50,31 @@ func (d DriverFactory) NewDriver(filename string) (Driver, error) {
|
||||
return driver, nil
|
||||
}
|
||||
|
||||
// Driver implements the advisory
|
||||
type Driver struct {
|
||||
lang string
|
||||
advisories []advisory
|
||||
}
|
||||
|
||||
// NewDriver is the factory method from drier
|
||||
func NewDriver(lang string, advisories ...advisory) Driver {
|
||||
return Driver{lang: lang, advisories: advisories}
|
||||
}
|
||||
|
||||
// Detect scans and returns vulnerabilities
|
||||
func (d *Driver) Detect(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
|
||||
var detectedVulnerabilities []types.DetectedVulnerability
|
||||
uniqVulnIdMap := make(map[string]struct{})
|
||||
uniqVulnIDMap := make(map[string]struct{})
|
||||
for _, d := range append(d.advisories, NewAdvisory(d.lang)) {
|
||||
vulns, err := d.DetectVulnerabilities(pkgName, pkgVer)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to detect vulnerabilities: %w", err)
|
||||
}
|
||||
for _, vuln := range vulns {
|
||||
if _, ok := uniqVulnIdMap[vuln.VulnerabilityID]; ok {
|
||||
if _, ok := uniqVulnIDMap[vuln.VulnerabilityID]; ok {
|
||||
continue
|
||||
}
|
||||
uniqVulnIdMap[vuln.VulnerabilityID] = struct{}{}
|
||||
uniqVulnIDMap[vuln.VulnerabilityID] = struct{}{}
|
||||
detectedVulnerabilities = append(detectedVulnerabilities, vuln)
|
||||
}
|
||||
}
|
||||
@@ -75,6 +82,7 @@ func (d *Driver) Detect(pkgName string, pkgVer *semver.Version) ([]types.Detecte
|
||||
return detectedVulnerabilities, nil
|
||||
}
|
||||
|
||||
// Type returns the driver lang
|
||||
func (d *Driver) Type() string {
|
||||
return d.lang
|
||||
}
|
||||
|
||||
@@ -11,20 +11,24 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
// VulnSrc defines the operations on vulnerability source
|
||||
type VulnSrc interface {
|
||||
Get(pkgName string) ([]ghsa.Advisory, error)
|
||||
}
|
||||
|
||||
// Advisory implements VulnSrc
|
||||
type Advisory struct {
|
||||
vs VulnSrc
|
||||
}
|
||||
|
||||
// NewAdvisory is the factory method to return advisory
|
||||
func NewAdvisory(ecosystem ghsa.Ecosystem) *Advisory {
|
||||
return &Advisory{
|
||||
vs: ghsa.NewVulnSrc(ecosystem),
|
||||
}
|
||||
}
|
||||
|
||||
// DetectVulnerabilities scans package for vulnerabilities
|
||||
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
|
||||
advisories, err := s.vs.Get(pkgName)
|
||||
if err != nil {
|
||||
|
||||
@@ -12,16 +12,19 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
// Advisory encapsulate Node vulnerability source
|
||||
type Advisory struct {
|
||||
vs node.VulnSrc
|
||||
}
|
||||
|
||||
// NewAdvisory is the factory method for Node Advisory
|
||||
func NewAdvisory() *Advisory {
|
||||
return &Advisory{
|
||||
vs: node.NewVulnSrc(),
|
||||
}
|
||||
}
|
||||
|
||||
// DetectVulnerabilities scans and return vulnerability using Node package scanner
|
||||
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
|
||||
replacer := strings.NewReplacer(".alpha", "-alpha", ".beta", "-beta", ".rc", "-rc", " <", ", <", " >", ", >")
|
||||
advisories, err := s.vs.Get(pkgName)
|
||||
|
||||
@@ -3,25 +3,27 @@ package python
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/python"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/python"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
// Advisory encapsulates the python vulnerability scanner
|
||||
type Advisory struct {
|
||||
vs python.VulnSrc
|
||||
}
|
||||
|
||||
// NewAdvisory is the factory method to reutrn Python Advisory
|
||||
func NewAdvisory() *Advisory {
|
||||
return &Advisory{
|
||||
vs: python.NewVulnSrc(),
|
||||
}
|
||||
}
|
||||
|
||||
// DetectVulnerabilities scans and returns pythin vulnerabilities
|
||||
func (s *Advisory) DetectVulnerabilities(pkgName string, pkgVer *semver.Version) ([]types.DetectedVulnerability, error) {
|
||||
advisories, err := s.vs.Get(pkgName)
|
||||
if err != nil {
|
||||
|
||||
@@ -41,16 +41,19 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Scanner implements the Alpine scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
}
|
||||
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{
|
||||
vs: alpine.NewVulnSrc(),
|
||||
}
|
||||
}
|
||||
|
||||
// Detect vulnerabilities in package using Alpine scanner
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Alpine vulnerabilities...")
|
||||
if strings.Count(osVer, ".") > 1 {
|
||||
@@ -94,6 +97,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
return vulns, nil
|
||||
}
|
||||
|
||||
// IsSupportedVersion checks the OSFamily can be scanned using Alpine scanner
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
now := time.Now()
|
||||
return s.isSupportedVersion(now, osFamily, osVer)
|
||||
|
||||
@@ -15,11 +15,13 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
// Scanner to scan amazon vulnerabilities
|
||||
type Scanner struct {
|
||||
l *zap.SugaredLogger
|
||||
ac dbTypes.VulnSrc
|
||||
}
|
||||
|
||||
// NewScanner is the factory method to return Amazon scanner
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{
|
||||
l: log.Logger,
|
||||
@@ -27,6 +29,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
// Detect scans the packages using amazon scanner
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Amazon Linux vulnerabilities...")
|
||||
|
||||
@@ -77,6 +80,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
return vulns, nil
|
||||
}
|
||||
|
||||
// IsSupportedVersion checks if os can be scanned using amazon scanner
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -40,11 +40,13 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Scanner implements the Debian scanner
|
||||
type Scanner struct {
|
||||
ovalVs dbTypes.VulnSrc
|
||||
vs dbTypes.VulnSrc
|
||||
}
|
||||
|
||||
// NewScanner is the factory method to return Scanner
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{
|
||||
ovalVs: debianoval.NewVulnSrc(),
|
||||
@@ -52,6 +54,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
// Detect scans and return vulnerabilities using Debian scanner
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Debian vulnerabilities...")
|
||||
|
||||
@@ -78,7 +81,8 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
}
|
||||
|
||||
for _, adv := range advisories {
|
||||
fixedVersion, err := version.NewVersion(adv.FixedVersion)
|
||||
var fixedVersion version.Version
|
||||
fixedVersion, err = version.NewVersion(adv.FixedVersion)
|
||||
if err != nil {
|
||||
log.Logger.Debugf("failed to parse Debian package version: %w", err)
|
||||
continue
|
||||
@@ -115,6 +119,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
return vulns, nil
|
||||
}
|
||||
|
||||
// IsSupportedVersion checks is OSFamily can be scanned using Debian
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
now := time.Now()
|
||||
return s.isSupportedVersion(now, osFamily, osVer)
|
||||
|
||||
@@ -21,25 +21,31 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrUnsupportedOS defines error for unsupported OS
|
||||
ErrUnsupportedOS = xerrors.New("unsupported os")
|
||||
|
||||
// SuperSet binds dependencies for OS scan
|
||||
SuperSet = wire.NewSet(
|
||||
wire.Struct(new(Detector)),
|
||||
wire.Bind(new(Operation), new(Detector)),
|
||||
)
|
||||
)
|
||||
|
||||
// Operation defines operation of OSpkg scan
|
||||
type Operation interface {
|
||||
Detect(string, string, string, time.Time, []ftypes.Package) ([]types.DetectedVulnerability, bool, error)
|
||||
}
|
||||
|
||||
// Driver defines operations for OS package scan
|
||||
type Driver interface {
|
||||
Detect(string, []ftypes.Package) ([]types.DetectedVulnerability, error)
|
||||
IsSupportedVersion(string, string) bool
|
||||
}
|
||||
|
||||
// Detector implements Operation
|
||||
type Detector struct{}
|
||||
|
||||
// Detect detects the vulnerabilities
|
||||
func (d Detector) Detect(_, osFamily, osName string, _ time.Time, pkgs []ftypes.Package) ([]types.DetectedVulnerability, bool, error) {
|
||||
driver := newDriver(osFamily, osName)
|
||||
if driver == nil {
|
||||
@@ -56,31 +62,31 @@ func (d Detector) Detect(_, osFamily, osName string, _ time.Time, pkgs []ftypes.
|
||||
return vulns, eosl, nil
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
// TODO: fix cyclometic complexity by removing default
|
||||
func newDriver(osFamily, osName string) Driver {
|
||||
// TODO: use DI and change struct names
|
||||
var d Driver
|
||||
switch osFamily {
|
||||
case fos.Alpine:
|
||||
d = alpine.NewScanner()
|
||||
return alpine.NewScanner()
|
||||
case fos.Debian:
|
||||
d = debian.NewScanner()
|
||||
return debian.NewScanner()
|
||||
case fos.Ubuntu:
|
||||
d = ubuntu.NewScanner()
|
||||
return ubuntu.NewScanner()
|
||||
case fos.RedHat, fos.CentOS:
|
||||
d = redhat.NewScanner()
|
||||
return redhat.NewScanner()
|
||||
case fos.Amazon:
|
||||
d = amazon.NewScanner()
|
||||
return amazon.NewScanner()
|
||||
case fos.Oracle:
|
||||
d = oracle.NewScanner()
|
||||
return oracle.NewScanner()
|
||||
case fos.OpenSUSELeap:
|
||||
d = suse.NewScanner(suse.OpenSUSE)
|
||||
return suse.NewScanner(suse.OpenSUSE)
|
||||
case fos.SLES:
|
||||
d = suse.NewScanner(suse.SUSEEnterpriseLinux)
|
||||
return suse.NewScanner(suse.SUSEEnterpriseLinux)
|
||||
case fos.Photon:
|
||||
d = photon.NewScanner()
|
||||
return photon.NewScanner()
|
||||
default:
|
||||
log.Logger.Warnf("unsupported os : %s", osFamily)
|
||||
return nil
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
@@ -4,18 +4,16 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
oracleoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/oracle-oval"
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
oracleoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/oracle-oval"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
"k8s.io/utils/clock"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -32,11 +30,13 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Scanner implements oracle vulnerability scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
// NewScanner is the factory method to return oracle vulnerabilities
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{
|
||||
vs: oracleoval.NewVulnSrc(),
|
||||
@@ -44,6 +44,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
// Detect scans and return vulnerability in Oracle scanner
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Oracle Linux vulnerabilities...")
|
||||
|
||||
@@ -81,6 +82,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
return vulns, nil
|
||||
}
|
||||
|
||||
// IsSupportedVersion checks is OSFamily can be scanned with Oracle scanner
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
if strings.Count(osVer, ".") > 0 {
|
||||
osVer = osVer[:strings.Index(osVer, ".")]
|
||||
|
||||
@@ -1,31 +1,30 @@
|
||||
package photon
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/photon"
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/photon"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
"k8s.io/utils/clock"
|
||||
)
|
||||
|
||||
var (
|
||||
eolDates = map[string]time.Time{}
|
||||
)
|
||||
// EOL can't be found for photon https://github.com/vmware/photon/issues/1031
|
||||
//var (
|
||||
// eolDates = map[string]time.Time{}
|
||||
//)
|
||||
|
||||
// Scanner implements Photon scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{
|
||||
vs: photon.NewVulnSrc(),
|
||||
@@ -33,6 +32,7 @@ func NewScanner() *Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
// Detect scans and returns vulnerabilities using photon scanner
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Photon Linux vulnerabilities...")
|
||||
log.Logger.Debugf("Photon Linux: os version: %s", osVer)
|
||||
@@ -64,6 +64,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
return vulns, nil
|
||||
}
|
||||
|
||||
// IsSupportedVersion checks is OSFamily can be scanned
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -4,14 +4,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/redhat"
|
||||
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer/os"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/redhat"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
@@ -37,16 +36,19 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Scanner implements the Redhat scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
}
|
||||
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{
|
||||
vs: redhat.NewVulnSrc(),
|
||||
}
|
||||
}
|
||||
|
||||
// Detect scans and returns redhat vulenrabilities
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting RHEL/CentOS vulnerabilities...")
|
||||
if strings.Count(osVer, ".") > 0 {
|
||||
@@ -102,6 +104,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
return vulns, nil
|
||||
}
|
||||
|
||||
// IsSupportedVersion checks is OSFamily can be scanned with Redhat scanner
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
now := time.Now()
|
||||
return s.isSupportedVersion(now, osFamily, osVer)
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
|
||||
fos "github.com/aquasecurity/fanal/analyzer/os"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
@@ -13,7 +15,6 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -52,20 +53,24 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Scanner implements suse scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
clock clock.Clock
|
||||
family string
|
||||
vs dbTypes.VulnSrc
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
type SUSEType int
|
||||
// Type to define SUSE type
|
||||
type Type int
|
||||
|
||||
const (
|
||||
SUSEEnterpriseLinux SUSEType = iota
|
||||
// SUSEEnterpriseLinux is Linux Enterprise version
|
||||
SUSEEnterpriseLinux Type = iota
|
||||
// OpenSUSE for open versions
|
||||
OpenSUSE
|
||||
)
|
||||
|
||||
func NewScanner(t SUSEType) *Scanner {
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner(t Type) *Scanner {
|
||||
switch t {
|
||||
case SUSEEnterpriseLinux:
|
||||
return &Scanner{
|
||||
@@ -81,6 +86,7 @@ func NewScanner(t SUSEType) *Scanner {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Detect scans and returns the vulnerabilities
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting SUSE vulnerabilities...")
|
||||
log.Logger.Debugf("SUSE: os version: %s", osVer)
|
||||
@@ -112,6 +118,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
return vulns, nil
|
||||
}
|
||||
|
||||
// IsSupportedVersion checks if OSFamily can be scanned using SUSE scanner
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
var eolDate time.Time
|
||||
var ok bool
|
||||
|
||||
@@ -51,16 +51,19 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Scanner implements the Ubuntu scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
}
|
||||
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{
|
||||
vs: ubuntu.NewVulnSrc(),
|
||||
}
|
||||
}
|
||||
|
||||
// Detect scans and returns the vulnerabilities
|
||||
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
|
||||
log.Logger.Info("Detecting Ubuntu vulnerabilities...")
|
||||
log.Logger.Debugf("ubuntu: os version: %s", osVer)
|
||||
@@ -108,6 +111,7 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
return vulns, nil
|
||||
}
|
||||
|
||||
// IsSupportedVersion checks is OSFamily can be scanned using Ubuntu scanner
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
now := time.Now()
|
||||
return s.isSupportedVersion(now, osFamily, osVer)
|
||||
|
||||
@@ -10,11 +10,12 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/google/go-github/v28/github"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -22,11 +23,13 @@ const (
|
||||
repo = "trivy-db"
|
||||
)
|
||||
|
||||
// RepositoryInterface defines the operations on repository
|
||||
type RepositoryInterface interface {
|
||||
ListReleases(ctx context.Context, opt *github.ListOptions) ([]*github.RepositoryRelease, *github.Response, error)
|
||||
DownloadAsset(ctx context.Context, id int64) (io.ReadCloser, string, error)
|
||||
}
|
||||
|
||||
// Repository implements RepositoryInterface
|
||||
type Repository struct {
|
||||
repository *github.RepositoriesService
|
||||
git *github.GitService
|
||||
@@ -34,22 +37,27 @@ type Repository struct {
|
||||
repoName string
|
||||
}
|
||||
|
||||
// ListReleases returns all github releases on repository
|
||||
func (r Repository) ListReleases(ctx context.Context, opt *github.ListOptions) ([]*github.RepositoryRelease, *github.Response, error) {
|
||||
return r.repository.ListReleases(ctx, r.owner, r.repoName, opt)
|
||||
}
|
||||
|
||||
// DownloadAsset returns reader object of downloaded object
|
||||
func (r Repository) DownloadAsset(ctx context.Context, id int64) (io.ReadCloser, string, error) {
|
||||
return r.repository.DownloadReleaseAsset(ctx, r.owner, r.repoName, id)
|
||||
}
|
||||
|
||||
// Operation defines the file operations
|
||||
type Operation interface {
|
||||
DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error)
|
||||
}
|
||||
|
||||
// Client implements RepositoryInterface
|
||||
type Client struct {
|
||||
Repository RepositoryInterface
|
||||
}
|
||||
|
||||
// NewClient is the factory method to return Client for RepositoryInterface operations
|
||||
func NewClient() Client {
|
||||
var client *http.Client
|
||||
githubToken := os.Getenv("GITHUB_TOKEN")
|
||||
@@ -73,6 +81,7 @@ func NewClient() Client {
|
||||
}
|
||||
}
|
||||
|
||||
// DownloadDB returns reader object of file content
|
||||
func (c Client) DownloadDB(ctx context.Context, fileName string) (io.ReadCloser, int, error) {
|
||||
options := github.ListOptions{}
|
||||
releases, _, err := c.Repository.ListReleases(ctx, &options)
|
||||
@@ -120,7 +129,7 @@ func (c Client) downloadAsset(ctx context.Context, asset github.ReleaseAsset, fi
|
||||
}
|
||||
|
||||
log.Logger.Debugf("asset URL: %s", url)
|
||||
resp, err := http.Get(url)
|
||||
resp, err := http.Get(url) // nolint: gosec
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
return nil, 0, xerrors.Errorf("unable to download the asset via URL: %w", err)
|
||||
}
|
||||
|
||||
@@ -6,14 +6,17 @@ import (
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
)
|
||||
|
||||
// ProgressBar exports method to track the progress of jobs
|
||||
type ProgressBar struct {
|
||||
quiet bool
|
||||
}
|
||||
|
||||
// NewProgressBar is the factory method to return progressBar object
|
||||
func NewProgressBar(quiet bool) ProgressBar {
|
||||
return ProgressBar{quiet: quiet}
|
||||
}
|
||||
|
||||
// Start starts the progress tracking
|
||||
func (p ProgressBar) Start(total int64) Bar {
|
||||
if p.quiet {
|
||||
return Bar{}
|
||||
@@ -22,16 +25,20 @@ func (p ProgressBar) Start(total int64) Bar {
|
||||
return Bar{bar: bar}
|
||||
}
|
||||
|
||||
// Bar is the proxy progress bar
|
||||
type Bar struct {
|
||||
bar *pb.ProgressBar
|
||||
}
|
||||
|
||||
// NewProxyReader is the factory method to track the progress
|
||||
func (b Bar) NewProxyReader(r io.Reader) io.Reader {
|
||||
if b.bar == nil {
|
||||
return r
|
||||
}
|
||||
return b.bar.NewProxyReader(r)
|
||||
}
|
||||
|
||||
// Finish finishes the progress tracking
|
||||
func (b Bar) Finish() {
|
||||
if b.bar == nil {
|
||||
return
|
||||
|
||||
@@ -9,10 +9,12 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// Logger is the global variable for logging
|
||||
Logger *zap.SugaredLogger
|
||||
debugOption bool
|
||||
)
|
||||
|
||||
// InitLogger initialize the logger variable
|
||||
func InitLogger(debug, disable bool) (err error) {
|
||||
debugOption = debug
|
||||
Logger, err = NewLogger(debug, disable)
|
||||
@@ -23,6 +25,7 @@ func InitLogger(debug, disable bool) (err error) {
|
||||
|
||||
}
|
||||
|
||||
// NewLogger is the factory method to return the instance of logger
|
||||
func NewLogger(debug, disable bool) (*zap.SugaredLogger, error) {
|
||||
// First, define our level-handling logic.
|
||||
errorPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||||
@@ -78,6 +81,7 @@ func NewLogger(debug, disable bool) (*zap.SugaredLogger, error) {
|
||||
return logger.Sugar(), nil
|
||||
}
|
||||
|
||||
// Fatal for logging fatal errors
|
||||
func Fatal(err error) {
|
||||
if debugOption {
|
||||
Logger.Fatalf("%+v", err)
|
||||
|
||||
@@ -13,19 +13,22 @@ import (
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
// Now returns the current time
|
||||
var Now = time.Now
|
||||
|
||||
// Results to hold list of Result
|
||||
type Results []Result
|
||||
|
||||
// Result to hold image scan results
|
||||
type Result struct {
|
||||
Target string `json:"Target"`
|
||||
Type string `json:"Type,omitempty"`
|
||||
@@ -33,13 +36,14 @@ type Result struct {
|
||||
Vulnerabilities []types.DetectedVulnerability `json:"Vulnerabilities"`
|
||||
}
|
||||
|
||||
// WriteResults writes the result to output, format as passed in argument
|
||||
func WriteResults(format string, output io.Writer, severities []dbTypes.Severity, results Results, outputTemplate string, light bool) error {
|
||||
var writer Writer
|
||||
switch format {
|
||||
case "table":
|
||||
writer = &TableWriter{Output: output, Light: light, Severities: severities}
|
||||
case "json":
|
||||
writer = &JsonWriter{Output: output}
|
||||
writer = &JSONWriter{Output: output}
|
||||
case "template":
|
||||
var err error
|
||||
if writer, err = NewTemplateWriter(output, outputTemplate); err != nil {
|
||||
@@ -55,22 +59,28 @@ func WriteResults(format string, output io.Writer, severities []dbTypes.Severity
|
||||
return nil
|
||||
}
|
||||
|
||||
// Writer defines the result write operation
|
||||
type Writer interface {
|
||||
Write(Results) error
|
||||
}
|
||||
|
||||
// TableWriter implements Writer and output in tabular form
|
||||
type TableWriter struct {
|
||||
Severities []dbTypes.Severity
|
||||
Output io.Writer
|
||||
Light bool
|
||||
}
|
||||
|
||||
// Write writes the result on standard output
|
||||
func (tw TableWriter) Write(results Results) error {
|
||||
for _, result := range results {
|
||||
tw.write(result)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
// TODO: refactror and fix cyclometic complexity
|
||||
func (tw TableWriter) write(result Result) {
|
||||
table := tablewriter.NewWriter(tw.Output)
|
||||
header := []string{"Library", "Vulnerability ID", "Severity", "Installed Version", "Fixed Version"}
|
||||
@@ -134,11 +144,13 @@ func (tw TableWriter) write(result Result) {
|
||||
return
|
||||
}
|
||||
|
||||
type JsonWriter struct {
|
||||
// JSONWriter implements result Writer
|
||||
type JSONWriter struct {
|
||||
Output io.Writer
|
||||
}
|
||||
|
||||
func (jw JsonWriter) Write(results Results) error {
|
||||
// Write writes the results in JSON format
|
||||
func (jw JSONWriter) Write(results Results) error {
|
||||
output, err := json.MarshalIndent(results, "", " ")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to marshal json: %w", err)
|
||||
@@ -150,11 +162,13 @@ func (jw JsonWriter) Write(results Results) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TemplateWriter write result in custom format defined by user's template
|
||||
type TemplateWriter struct {
|
||||
Output io.Writer
|
||||
Template *template.Template
|
||||
}
|
||||
|
||||
// NewTemplateWriter is the factory method to return TemplateWriter object
|
||||
func NewTemplateWriter(output io.Writer, outputTemplate string) (*TemplateWriter, error) {
|
||||
if strings.HasPrefix(outputTemplate, "@") {
|
||||
buf, err := ioutil.ReadFile(strings.TrimPrefix(outputTemplate, "@"))
|
||||
@@ -197,6 +211,7 @@ func NewTemplateWriter(output io.Writer, outputTemplate string) (*TemplateWriter
|
||||
return &TemplateWriter{Output: output, Template: tmpl}, nil
|
||||
}
|
||||
|
||||
// Write writes result
|
||||
func (tw TemplateWriter) Write(results Results) error {
|
||||
err := tw.Template.Execute(tw.Output, results)
|
||||
if err != nil {
|
||||
|
||||
@@ -175,7 +175,7 @@ func TestReportWriter_JSON(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
||||
jw := report.JsonWriter{}
|
||||
jw := report.JSONWriter{}
|
||||
jsonWritten := bytes.Buffer{}
|
||||
jw.Output = &jsonWritten
|
||||
|
||||
|
||||
@@ -16,28 +16,35 @@ import (
|
||||
rpc "github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
|
||||
// SuperSet binds the dependencies for RPC client
|
||||
var SuperSet = wire.NewSet(
|
||||
NewProtobufClient,
|
||||
NewScanner,
|
||||
)
|
||||
|
||||
// RemoteURL for RPC remote host
|
||||
type RemoteURL string
|
||||
|
||||
// NewProtobufClient is the factory method to return RPC scanner
|
||||
func NewProtobufClient(remoteURL RemoteURL) rpc.Scanner {
|
||||
return rpc.NewScannerProtobufClient(string(remoteURL), &http.Client{})
|
||||
}
|
||||
|
||||
// CustomHeaders for holding HTTP headers
|
||||
type CustomHeaders http.Header
|
||||
|
||||
// Scanner implements the RPC scanner
|
||||
type Scanner struct {
|
||||
customHeaders CustomHeaders
|
||||
client rpc.Scanner
|
||||
}
|
||||
|
||||
// NewScanner is the factory method to return RPC Scanner
|
||||
func NewScanner(customHeaders CustomHeaders, s rpc.Scanner) Scanner {
|
||||
return Scanner{customHeaders: customHeaders, client: s}
|
||||
}
|
||||
|
||||
// Scan scans the image
|
||||
func (s Scanner) Scan(target string, imageID string, layerIDs []string, options types.ScanOptions) (report.Results, *ftypes.OS, bool, error) {
|
||||
ctx := WithCustomHeaders(context.Background(), http.Header(s.customHeaders))
|
||||
|
||||
@@ -58,5 +65,5 @@ func (s Scanner) Scan(target string, imageID string, layerIDs []string, options
|
||||
return nil, nil, false, xerrors.Errorf("failed to detect vulnerabilities via RPC: %w", err)
|
||||
}
|
||||
|
||||
return r.ConvertFromRpcResults(res.Results), r.ConvertFromRpcOS(res.Os), res.Eosl, nil
|
||||
return r.ConvertFromRPCResults(res.Results), r.ConvertFromRPCOS(res.Os), res.Eosl, nil
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
// WithCustomHeaders adds custom headers to request headers
|
||||
func WithCustomHeaders(ctx context.Context, customHeaders http.Header) context.Context {
|
||||
// Attach the headers to a context
|
||||
ctxWithToken, err := twirp.WithHTTPRequestHeaders(ctx, customHeaders)
|
||||
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
"github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
|
||||
func ConvertToRpcPkgs(pkgs []ftypes.Package) []*common.Package {
|
||||
// ConvertToRPCPkgs returns the list of RPC package objects
|
||||
func ConvertToRPCPkgs(pkgs []ftypes.Package) []*common.Package {
|
||||
var rpcPkgs []*common.Package
|
||||
for _, pkg := range pkgs {
|
||||
rpcPkgs = append(rpcPkgs, &common.Package{
|
||||
@@ -32,7 +33,8 @@ func ConvertToRpcPkgs(pkgs []ftypes.Package) []*common.Package {
|
||||
return rpcPkgs
|
||||
}
|
||||
|
||||
func ConvertFromRpcPkgs(rpcPkgs []*common.Package) []ftypes.Package {
|
||||
// ConvertFromRPCPkgs returns list of Fanal package objects
|
||||
func ConvertFromRPCPkgs(rpcPkgs []*common.Package) []ftypes.Package {
|
||||
var pkgs []ftypes.Package
|
||||
for _, pkg := range rpcPkgs {
|
||||
pkgs = append(pkgs, ftypes.Package{
|
||||
@@ -50,7 +52,8 @@ func ConvertFromRpcPkgs(rpcPkgs []*common.Package) []ftypes.Package {
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func ConvertFromRpcLibraries(rpcLibs []*common.Library) []ftypes.LibraryInfo {
|
||||
// ConvertFromRPCLibraries returns list of Fanal library
|
||||
func ConvertFromRPCLibraries(rpcLibs []*common.Library) []ftypes.LibraryInfo {
|
||||
var libs []ftypes.LibraryInfo
|
||||
for _, l := range rpcLibs {
|
||||
libs = append(libs, ftypes.LibraryInfo{
|
||||
@@ -63,7 +66,8 @@ func ConvertFromRpcLibraries(rpcLibs []*common.Library) []ftypes.LibraryInfo {
|
||||
return libs
|
||||
}
|
||||
|
||||
func ConvertToRpcLibraries(libs []deptypes.Library) []*common.Library {
|
||||
// ConvertToRPCLibraries returns list of libraries
|
||||
func ConvertToRPCLibraries(libs []deptypes.Library) []*common.Library {
|
||||
var rpcLibs []*common.Library
|
||||
for _, l := range libs {
|
||||
rpcLibs = append(rpcLibs, &common.Library{
|
||||
@@ -74,7 +78,8 @@ func ConvertToRpcLibraries(libs []deptypes.Library) []*common.Library {
|
||||
return rpcLibs
|
||||
}
|
||||
|
||||
func ConvertFromRpcVulns(rpcVulns []*common.Vulnerability) []types.DetectedVulnerability {
|
||||
// ConvertFromRPCVulns returns converted vulnerability from common vulnerability format
|
||||
func ConvertFromRPCVulns(rpcVulns []*common.Vulnerability) []types.DetectedVulnerability {
|
||||
var vulns []types.DetectedVulnerability
|
||||
for _, vuln := range rpcVulns {
|
||||
severity := dbTypes.Severity(vuln.Severity)
|
||||
@@ -94,7 +99,8 @@ func ConvertFromRpcVulns(rpcVulns []*common.Vulnerability) []types.DetectedVulne
|
||||
return vulns
|
||||
}
|
||||
|
||||
func ConvertToRpcVulns(vulns []types.DetectedVulnerability) []*common.Vulnerability {
|
||||
// ConvertToRPCVulns returns common.Vulnerability
|
||||
func ConvertToRPCVulns(vulns []types.DetectedVulnerability) []*common.Vulnerability {
|
||||
var rpcVulns []*common.Vulnerability
|
||||
for _, vuln := range vulns {
|
||||
severity, err := dbTypes.NewSeverity(vuln.Severity)
|
||||
@@ -132,9 +138,9 @@ func ConvertToRpcVulns(vulns []types.DetectedVulnerability) []*common.Vulnerabil
|
||||
return rpcVulns
|
||||
}
|
||||
|
||||
func ConvertFromRpcResults(rpcResults []*scanner.Result) []report.Result {
|
||||
// ConvertFromRPCResults converts scannel.Result to report.Result
|
||||
func ConvertFromRPCResults(rpcResults []*scanner.Result) []report.Result {
|
||||
var results []report.Result
|
||||
|
||||
for _, result := range rpcResults {
|
||||
var vulns []types.DetectedVulnerability
|
||||
for _, vuln := range result.Vulnerabilities {
|
||||
@@ -178,7 +184,8 @@ func ConvertFromRpcResults(rpcResults []*scanner.Result) []report.Result {
|
||||
return results
|
||||
}
|
||||
|
||||
func ConvertFromRpcOS(rpcOS *common.OS) *ftypes.OS {
|
||||
// ConvertFromRPCOS converts common.OS to fanal.OS
|
||||
func ConvertFromRPCOS(rpcOS *common.OS) *ftypes.OS {
|
||||
if rpcOS == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -188,55 +195,60 @@ func ConvertFromRpcOS(rpcOS *common.OS) *ftypes.OS {
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertFromRpcPackageInfos(rpcPkgInfos []*common.PackageInfo) []ftypes.PackageInfo {
|
||||
// ConvertFromRPCPackageInfos converts common.PackageInfo to fanal.PackageInfo
|
||||
func ConvertFromRPCPackageInfos(rpcPkgInfos []*common.PackageInfo) []ftypes.PackageInfo {
|
||||
var pkgInfos []ftypes.PackageInfo
|
||||
for _, rpcPkgInfo := range rpcPkgInfos {
|
||||
pkgInfos = append(pkgInfos, ftypes.PackageInfo{
|
||||
FilePath: rpcPkgInfo.FilePath,
|
||||
Packages: ConvertFromRpcPkgs(rpcPkgInfo.Packages),
|
||||
Packages: ConvertFromRPCPkgs(rpcPkgInfo.Packages),
|
||||
})
|
||||
}
|
||||
return pkgInfos
|
||||
}
|
||||
|
||||
func ConvertFromRpcApplications(rpcApps []*common.Application) []ftypes.Application {
|
||||
// ConvertFromRPCApplications converts common.Application to fanal.Application
|
||||
func ConvertFromRPCApplications(rpcApps []*common.Application) []ftypes.Application {
|
||||
var apps []ftypes.Application
|
||||
for _, rpcApp := range rpcApps {
|
||||
apps = append(apps, ftypes.Application{
|
||||
Type: rpcApp.Type,
|
||||
FilePath: rpcApp.FilePath,
|
||||
Libraries: ConvertFromRpcLibraries(rpcApp.Libraries),
|
||||
Libraries: ConvertFromRPCLibraries(rpcApp.Libraries),
|
||||
})
|
||||
}
|
||||
return apps
|
||||
}
|
||||
|
||||
func ConvertFromRpcPutArtifactRequest(req *cache.PutArtifactRequest) ftypes.ArtifactInfo {
|
||||
created, _ := ptypes.Timestamp(req.ArtifactInfo.Created)
|
||||
// ConvertFromRPCPutArtifactRequest converts cache.PutArtifactRequest to fanal.PutArtifactRequest
|
||||
func ConvertFromRPCPutArtifactRequest(req *cache.PutArtifactRequest) ftypes.ArtifactInfo {
|
||||
created, _ := ptypes.Timestamp(req.ArtifactInfo.Created) // nolint: errcheck
|
||||
return ftypes.ArtifactInfo{
|
||||
SchemaVersion: int(req.ArtifactInfo.SchemaVersion),
|
||||
Architecture: req.ArtifactInfo.Architecture,
|
||||
Created: created,
|
||||
DockerVersion: req.ArtifactInfo.DockerVersion,
|
||||
OS: req.ArtifactInfo.Os,
|
||||
HistoryPackages: ConvertFromRpcPkgs(req.ArtifactInfo.HistoryPackages),
|
||||
HistoryPackages: ConvertFromRPCPkgs(req.ArtifactInfo.HistoryPackages),
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertFromRpcPutBlobRequest(req *cache.PutBlobRequest) ftypes.BlobInfo {
|
||||
// ConvertFromRPCPutBlobRequest returns ftypes.BlobInfo
|
||||
func ConvertFromRPCPutBlobRequest(req *cache.PutBlobRequest) ftypes.BlobInfo {
|
||||
return ftypes.BlobInfo{
|
||||
SchemaVersion: int(req.BlobInfo.SchemaVersion),
|
||||
Digest: req.BlobInfo.Digest,
|
||||
DiffID: req.BlobInfo.DiffId,
|
||||
OS: ConvertFromRpcOS(req.BlobInfo.Os),
|
||||
PackageInfos: ConvertFromRpcPackageInfos(req.BlobInfo.PackageInfos),
|
||||
Applications: ConvertFromRpcApplications(req.BlobInfo.Applications),
|
||||
OS: ConvertFromRPCOS(req.BlobInfo.Os),
|
||||
PackageInfos: ConvertFromRPCPackageInfos(req.BlobInfo.PackageInfos),
|
||||
Applications: ConvertFromRPCApplications(req.BlobInfo.Applications),
|
||||
OpaqueDirs: req.BlobInfo.OpaqueDirs,
|
||||
WhiteoutFiles: req.BlobInfo.WhiteoutFiles,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToRpcOS(fos *ftypes.OS) *common.OS {
|
||||
// ConvertToRPCOS returns common.OS
|
||||
func ConvertToRPCOS(fos *ftypes.OS) *common.OS {
|
||||
if fos == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -246,7 +258,8 @@ func ConvertToRpcOS(fos *ftypes.OS) *common.OS {
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToRpcArtifactInfo(imageID string, imageInfo ftypes.ArtifactInfo) *cache.PutArtifactRequest {
|
||||
// ConvertToRPCArtifactInfo returns PutArtifactRequest
|
||||
func ConvertToRPCArtifactInfo(imageID string, imageInfo ftypes.ArtifactInfo) *cache.PutArtifactRequest {
|
||||
t, err := ptypes.TimestampProto(imageInfo.Created)
|
||||
if err != nil {
|
||||
log.Logger.Warnf("invalid timestamp: %s", err)
|
||||
@@ -260,17 +273,18 @@ func ConvertToRpcArtifactInfo(imageID string, imageInfo ftypes.ArtifactInfo) *ca
|
||||
Created: t,
|
||||
DockerVersion: imageInfo.DockerVersion,
|
||||
Os: imageInfo.OS,
|
||||
HistoryPackages: ConvertToRpcPkgs(imageInfo.HistoryPackages),
|
||||
HistoryPackages: ConvertToRPCPkgs(imageInfo.HistoryPackages),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBlobRequest {
|
||||
// ConvertToRPCBlobInfo returns PutBlobRequest
|
||||
func ConvertToRPCBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBlobRequest {
|
||||
var packageInfos []*common.PackageInfo
|
||||
for _, pkgInfo := range layerInfo.PackageInfos {
|
||||
packageInfos = append(packageInfos, &common.PackageInfo{
|
||||
FilePath: pkgInfo.FilePath,
|
||||
Packages: ConvertToRpcPkgs(pkgInfo.Packages),
|
||||
Packages: ConvertToRPCPkgs(pkgInfo.Packages),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -282,7 +296,6 @@ func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBl
|
||||
Name: lib.Library.Name,
|
||||
Version: lib.Library.Version,
|
||||
})
|
||||
|
||||
}
|
||||
applications = append(applications, &common.Application{
|
||||
Type: app.Type,
|
||||
@@ -297,7 +310,7 @@ func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBl
|
||||
SchemaVersion: ftypes.BlobJSONSchemaVersion,
|
||||
Digest: layerInfo.Digest,
|
||||
DiffId: layerInfo.DiffID,
|
||||
Os: ConvertToRpcOS(layerInfo.OS),
|
||||
Os: ConvertToRPCOS(layerInfo.OS),
|
||||
PackageInfos: packageInfos,
|
||||
Applications: applications,
|
||||
OpaqueDirs: layerInfo.OpaqueDirs,
|
||||
@@ -306,6 +319,7 @@ func ConvertToRpcBlobInfo(diffID string, layerInfo ftypes.BlobInfo) *cache.PutBl
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertToMissingBlobsRequest returns MissingBlobsRequest object
|
||||
func ConvertToMissingBlobsRequest(imageID string, layerIDs []string) *cache.MissingBlobsRequest {
|
||||
return &cache.MissingBlobsRequest{
|
||||
ArtifactId: imageID,
|
||||
@@ -313,7 +327,8 @@ func ConvertToMissingBlobsRequest(imageID string, layerIDs []string) *cache.Miss
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToRpcScanResponse(results report.Results, os *ftypes.OS, eosl bool) *scanner.ScanResponse {
|
||||
// ConvertToRPCScanResponse converts report.Result to ScanResponse
|
||||
func ConvertToRPCScanResponse(results report.Results, os *ftypes.OS, eosl bool) *scanner.ScanResponse {
|
||||
rpcOS := &common.OS{}
|
||||
if os != nil {
|
||||
rpcOS.Family = os.Family
|
||||
@@ -324,7 +339,7 @@ func ConvertToRpcScanResponse(results report.Results, os *ftypes.OS, eosl bool)
|
||||
for _, result := range results {
|
||||
rpcResults = append(rpcResults, &scanner.Result{
|
||||
Target: result.Target,
|
||||
Vulnerabilities: ConvertToRpcVulns(result.Vulnerabilities),
|
||||
Vulnerabilities: ConvertToRPCVulns(result.Vulnerabilities),
|
||||
Type: result.Type,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func TestConvertToRpcPkgs(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := ConvertToRpcPkgs(tt.args.pkgs)
|
||||
got := ConvertToRPCPkgs(tt.args.pkgs)
|
||||
assert.Equal(t, tt.want, got, tt.name)
|
||||
})
|
||||
}
|
||||
@@ -113,7 +113,7 @@ func TestConvertFromRpcPkgs(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := ConvertFromRpcPkgs(tt.args.rpcPkgs)
|
||||
got := ConvertFromRPCPkgs(tt.args.rpcPkgs)
|
||||
assert.Equal(t, tt.want, got, tt.name)
|
||||
})
|
||||
}
|
||||
@@ -144,7 +144,7 @@ func TestConvertFromRpcLibraries(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := ConvertFromRpcLibraries(tt.args.rpcLibs)
|
||||
got := ConvertFromRPCLibraries(tt.args.rpcLibs)
|
||||
assert.Equal(t, got, tt.want, tt.name)
|
||||
})
|
||||
}
|
||||
@@ -175,7 +175,7 @@ func TestConvertToRpcLibraries(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := ConvertToRpcLibraries(tt.args.libs)
|
||||
got := ConvertToRPCLibraries(tt.args.libs)
|
||||
assert.Equal(t, got, tt.want, tt.name)
|
||||
})
|
||||
}
|
||||
@@ -224,7 +224,7 @@ func TestConvertFromRpcVulns(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := ConvertFromRpcVulns(tt.args.rpcVulns)
|
||||
got := ConvertFromRPCVulns(tt.args.rpcVulns)
|
||||
assert.Equal(t, got, tt.want, tt.name)
|
||||
})
|
||||
}
|
||||
@@ -337,7 +337,7 @@ func TestConvertToRpcVulns(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := ConvertToRpcVulns(tt.args.vulns)
|
||||
got := ConvertToRPCVulns(tt.args.vulns)
|
||||
assert.Equal(t, got, tt.want, tt.name)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,15 +3,17 @@ package rpc
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/twitchtv/twirp"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
maxRetries = 10
|
||||
)
|
||||
|
||||
// Retry executes the function again using backoff until maxRetries or success
|
||||
func Retry(f func() error) error {
|
||||
operation := func() error {
|
||||
err := f()
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
proto "github.com/aquasecurity/trivy/rpc/detector"
|
||||
)
|
||||
|
||||
// SuperSet binds the dependencies for library RPC server
|
||||
var SuperSet = wire.NewSet(
|
||||
detector.SuperSet,
|
||||
vulnerability.SuperSet,
|
||||
@@ -26,13 +27,14 @@ type Server struct {
|
||||
vulnClient vulnerability.Operation
|
||||
}
|
||||
|
||||
// NewServer is the facotry method for Server
|
||||
func NewServer(detector detector.Operation, vulnClient vulnerability.Operation) *Server {
|
||||
return &Server{detector: detector, vulnClient: vulnClient}
|
||||
}
|
||||
|
||||
// Detect is for backward compatibility
|
||||
func (s *Server) Detect(_ context.Context, req *proto.LibDetectRequest) (res *proto.DetectResponse, err error) {
|
||||
vulns, err := s.detector.Detect("", req.FilePath, time.Time{}, rpc.ConvertFromRpcLibraries(req.Libraries))
|
||||
vulns, err := s.detector.Detect("", req.FilePath, time.Time{}, rpc.ConvertFromRPCLibraries(req.Libraries))
|
||||
if err != nil {
|
||||
err = xerrors.Errorf("failed to detect library vulnerabilities: %w", err)
|
||||
log.Logger.Error(err)
|
||||
@@ -41,5 +43,5 @@ func (s *Server) Detect(_ context.Context, req *proto.LibDetectRequest) (res *pr
|
||||
|
||||
s.vulnClient.FillInfo(vulns, "")
|
||||
|
||||
return &proto.DetectResponse{Vulnerabilities: rpc.ConvertToRpcVulns(vulns)}, nil
|
||||
return &proto.DetectResponse{Vulnerabilities: rpc.ConvertToRPCVulns(vulns)}, nil
|
||||
}
|
||||
|
||||
@@ -24,11 +24,13 @@ import (
|
||||
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
|
||||
// DBWorkerSuperSet binds the dependencies for Trivy DB worker
|
||||
var DBWorkerSuperSet = wire.NewSet(
|
||||
dbFile.SuperSet,
|
||||
newDBWorker,
|
||||
)
|
||||
|
||||
// ListenAndServe starts Trivy server
|
||||
func ListenAndServe(c config.Config, fsCache cache.FSCache) error {
|
||||
requestWg := &sync.WaitGroup{}
|
||||
dbUpdateWg := &sync.WaitGroup{}
|
||||
@@ -132,7 +134,7 @@ func (w dbWorker) hotUpdate(ctx context.Context, cacheDir string, dbUpdateWg, re
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
if err := w.dbClient.Download(ctx, tmpDir, false); err != nil {
|
||||
if err = w.dbClient.Download(ctx, tmpDir, false); err != nil {
|
||||
return xerrors.Errorf("failed to download vulnerability DB: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
proto "github.com/aquasecurity/trivy/rpc/detector"
|
||||
)
|
||||
|
||||
// SuperSet binds dependencies for RPC server
|
||||
var SuperSet = wire.NewSet(
|
||||
detector.SuperSet,
|
||||
vulnerability.SuperSet,
|
||||
@@ -26,13 +27,14 @@ type Server struct {
|
||||
vulnClient vulnerability.Operation
|
||||
}
|
||||
|
||||
// NewServer is the factory method to return Server
|
||||
func NewServer(detector detector.Operation, vulnClient vulnerability.Operation) *Server {
|
||||
return &Server{detector: detector, vulnClient: vulnClient}
|
||||
}
|
||||
|
||||
// Detect is for backward compatibility
|
||||
func (s *Server) Detect(_ context.Context, req *proto.OSDetectRequest) (res *proto.DetectResponse, err error) {
|
||||
vulns, eosl, err := s.detector.Detect("", req.OsFamily, req.OsName, time.Time{}, rpc.ConvertFromRpcPkgs(req.Packages))
|
||||
vulns, eosl, err := s.detector.Detect("", req.OsFamily, req.OsName, time.Time{}, rpc.ConvertFromRPCPkgs(req.Packages))
|
||||
if err != nil {
|
||||
err = xerrors.Errorf("failed to detect vulnerabilities of OS packages: %w", err)
|
||||
log.Logger.Error(err)
|
||||
@@ -41,5 +43,5 @@ func (s *Server) Detect(_ context.Context, req *proto.OSDetectRequest) (res *pro
|
||||
|
||||
s.vulnClient.FillInfo(vulns, "")
|
||||
|
||||
return &proto.DetectResponse{Vulnerabilities: rpc.ConvertToRpcVulns(vulns), Eosl: eosl}, nil
|
||||
return &proto.DetectResponse{Vulnerabilities: rpc.ConvertToRPCVulns(vulns), Eosl: eosl}, nil
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
rpcScanner "github.com/aquasecurity/trivy/rpc/scanner"
|
||||
)
|
||||
|
||||
// ScanSuperSet binds the dependencies for server
|
||||
var ScanSuperSet = wire.NewSet(
|
||||
local.SuperSet,
|
||||
wire.Bind(new(scanner.Driver), new(local.Scanner)),
|
||||
@@ -24,15 +25,18 @@ var ScanSuperSet = wire.NewSet(
|
||||
NewScanServer,
|
||||
)
|
||||
|
||||
// ScanServer implements the scanner
|
||||
type ScanServer struct {
|
||||
localScanner scanner.Driver
|
||||
vulnClient vulnerability.Operation
|
||||
}
|
||||
|
||||
// NewScanServer is the factory method for scanner
|
||||
func NewScanServer(s scanner.Driver, vulnClient vulnerability.Operation) *ScanServer {
|
||||
return &ScanServer{localScanner: s, vulnClient: vulnClient}
|
||||
}
|
||||
|
||||
// Scan scans and return response
|
||||
func (s *ScanServer) Scan(_ context.Context, in *rpcScanner.ScanRequest) (*rpcScanner.ScanResponse, error) {
|
||||
options := types.ScanOptions{VulnType: in.Options.VulnType}
|
||||
results, os, eosl, err := s.localScanner.Scan(in.Target, in.ArtifactId, in.BlobIds, options)
|
||||
@@ -43,39 +47,44 @@ func (s *ScanServer) Scan(_ context.Context, in *rpcScanner.ScanRequest) (*rpcSc
|
||||
for i := range results {
|
||||
s.vulnClient.FillInfo(results[i].Vulnerabilities, results[i].Type)
|
||||
}
|
||||
return rpc.ConvertToRpcScanResponse(results, os, eosl), nil
|
||||
return rpc.ConvertToRPCScanResponse(results, os, eosl), nil
|
||||
}
|
||||
|
||||
// CacheServer implements the cache
|
||||
type CacheServer struct {
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
// NewCacheServer is the facotry method for cacheServer
|
||||
func NewCacheServer(c cache.Cache) *CacheServer {
|
||||
return &CacheServer{cache: c}
|
||||
}
|
||||
|
||||
// PutArtifact puts the artifacts in cache
|
||||
func (s *CacheServer) PutArtifact(_ context.Context, in *rpcCache.PutArtifactRequest) (*google_protobuf.Empty, error) {
|
||||
if in.ArtifactInfo == nil {
|
||||
return nil, xerrors.Errorf("empty image info")
|
||||
}
|
||||
imageInfo := rpc.ConvertFromRpcPutArtifactRequest(in)
|
||||
imageInfo := rpc.ConvertFromRPCPutArtifactRequest(in)
|
||||
if err := s.cache.PutArtifact(in.ArtifactId, imageInfo); err != nil {
|
||||
return nil, xerrors.Errorf("unable to store image info in cache: %w", err)
|
||||
}
|
||||
return &google_protobuf.Empty{}, nil
|
||||
}
|
||||
|
||||
// PutBlob puts the blobs in cache
|
||||
func (s *CacheServer) PutBlob(_ context.Context, in *rpcCache.PutBlobRequest) (*google_protobuf.Empty, error) {
|
||||
if in.BlobInfo == nil {
|
||||
return nil, xerrors.Errorf("empty layer info")
|
||||
}
|
||||
layerInfo := rpc.ConvertFromRpcPutBlobRequest(in)
|
||||
layerInfo := rpc.ConvertFromRPCPutBlobRequest(in)
|
||||
if err := s.cache.PutBlob(in.DiffId, layerInfo); err != nil {
|
||||
return nil, xerrors.Errorf("unable to store layer info in cache: %w", err)
|
||||
}
|
||||
return &google_protobuf.Empty{}, nil
|
||||
}
|
||||
|
||||
// MissingBlobs returns missing blobs from cache
|
||||
func (s *CacheServer) MissingBlobs(_ context.Context, in *rpcCache.MissingBlobsRequest) (*rpcCache.MissingBlobsResponse, error) {
|
||||
missingArtifact, blobIDs, err := s.cache.MissingBlobs(in.ArtifactId, in.BlobIds)
|
||||
if err != nil {
|
||||
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
)
|
||||
|
||||
// SuperSet binds dependencies for Local scan
|
||||
var SuperSet = wire.NewSet(
|
||||
applier.NewApplier,
|
||||
wire.Bind(new(Applier), new(applier.Applier)),
|
||||
@@ -50,28 +51,35 @@ var SuperSet = wire.NewSet(
|
||||
NewScanner,
|
||||
)
|
||||
|
||||
// Applier defines operation to scan image layers
|
||||
type Applier interface {
|
||||
ApplyLayers(artifactID string, blobIDs []string) (detail ftypes.ArtifactDetail, err error)
|
||||
}
|
||||
|
||||
// OspkgDetector defines operation to detect OS vulnerabilities
|
||||
type OspkgDetector interface {
|
||||
Detect(imageName, osFamily, osName string, created time.Time, pkgs []ftypes.Package) (detectedVulns []types.DetectedVulnerability, eosl bool, err error)
|
||||
}
|
||||
|
||||
// LibraryDetector defines operation to detect library vulnerabilities
|
||||
type LibraryDetector interface {
|
||||
Detect(imageName, filePath string, created time.Time, pkgs []ftypes.LibraryInfo) (detectedVulns []types.DetectedVulnerability, err error)
|
||||
}
|
||||
|
||||
// Scanner implements the OspkgDetector and LibraryDetector
|
||||
type Scanner struct {
|
||||
applier Applier
|
||||
ospkgDetector OspkgDetector
|
||||
libDetector LibraryDetector
|
||||
}
|
||||
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner(applier Applier, ospkgDetector OspkgDetector, libDetector LibraryDetector) Scanner {
|
||||
return Scanner{applier: applier, ospkgDetector: ospkgDetector, libDetector: libDetector}
|
||||
}
|
||||
|
||||
// Scan scans the local image and return results. TODO: fix cyclometic complexity
|
||||
// nolint: gocyclo
|
||||
func (s Scanner) Scan(target string, imageID string, layerIDs []string, options types.ScanOptions) (report.Results, *ftypes.OS, bool, error) {
|
||||
imageDetail, err := s.applier.ApplyLayers(imageID, layerIDs)
|
||||
if err != nil {
|
||||
|
||||
@@ -26,6 +26,7 @@ var StandaloneSuperSet = wire.NewSet(
|
||||
NewScanner,
|
||||
)
|
||||
|
||||
// StandaloneDockerSet binds docker dependencies
|
||||
var StandaloneDockerSet = wire.NewSet(
|
||||
types.GetDockerOption,
|
||||
image.NewDockerImage,
|
||||
@@ -33,17 +34,20 @@ var StandaloneDockerSet = wire.NewSet(
|
||||
StandaloneSuperSet,
|
||||
)
|
||||
|
||||
// StandaloneArchiveSet binds archive scan dependencies
|
||||
var StandaloneArchiveSet = wire.NewSet(
|
||||
image.NewArchiveImage,
|
||||
aimage.NewArtifact,
|
||||
StandaloneSuperSet,
|
||||
)
|
||||
|
||||
// StandaloneFilesystemSet binds filesystem dependencies
|
||||
var StandaloneFilesystemSet = wire.NewSet(
|
||||
flocal.NewArtifact,
|
||||
StandaloneSuperSet,
|
||||
)
|
||||
|
||||
// StandaloneRepositorySet binds repository dependencies
|
||||
var StandaloneRepositorySet = wire.NewSet(
|
||||
remote.NewArtifact,
|
||||
StandaloneSuperSet,
|
||||
@@ -57,30 +61,36 @@ var RemoteSuperSet = wire.NewSet(
|
||||
NewScanner,
|
||||
)
|
||||
|
||||
// RemoteDockerSet binds remote docker dependencies
|
||||
var RemoteDockerSet = wire.NewSet(
|
||||
types.GetDockerOption,
|
||||
image.NewDockerImage,
|
||||
RemoteSuperSet,
|
||||
)
|
||||
|
||||
// RemoteArchiveSet binds remote archive dependencies
|
||||
var RemoteArchiveSet = wire.NewSet(
|
||||
image.NewArchiveImage,
|
||||
RemoteSuperSet,
|
||||
)
|
||||
|
||||
// Scanner implements the Artifact and Driver operations
|
||||
type Scanner struct {
|
||||
driver Driver
|
||||
artifact artifact.Artifact
|
||||
}
|
||||
|
||||
// Driver defines operations of scanner
|
||||
type Driver interface {
|
||||
Scan(target string, imageID string, layerIDs []string, options types.ScanOptions) (results report.Results, osFound *ftypes.OS, eols bool, err error)
|
||||
}
|
||||
|
||||
// NewScanner is the factory method of Scanner
|
||||
func NewScanner(driver Driver, ar artifact.Artifact) Scanner {
|
||||
return Scanner{driver: driver, artifact: ar}
|
||||
}
|
||||
|
||||
// ScanArtifact scans the artifacts and returns results
|
||||
func (s Scanner) ScanArtifact(ctx context.Context, options types.ScanOptions) (report.Results, error) {
|
||||
artifactInfo, err := s.artifact.Inspect(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -18,6 +18,7 @@ var (
|
||||
preReleaseSplitter = regexp.MustCompile(`(?P<Number>^[0-9]+)(?P<PreRelease>[a-z]*.*)`)
|
||||
)
|
||||
|
||||
// MatchVersions runs comparison on currentVersion based on rangeVersions and return true/false
|
||||
func MatchVersions(currentVersion *semver.Version, rangeVersions []string) bool {
|
||||
for _, v := range rangeVersions {
|
||||
v = replacer.Replace(v)
|
||||
@@ -55,14 +56,17 @@ func MatchVersions(currentVersion *semver.Version, rangeVersions []string) bool
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatVersion formats the package version based on epoch, version & release
|
||||
func FormatVersion(pkg types.Package) string {
|
||||
return formatVersion(pkg.Epoch, pkg.Version, pkg.Release)
|
||||
}
|
||||
|
||||
// FormatSrcVersion formats the package version based on source epoch, version & release
|
||||
func FormatSrcVersion(pkg types.Package) string {
|
||||
return formatVersion(pkg.SrcEpoch, pkg.SrcVersion, pkg.SrcRelease)
|
||||
}
|
||||
|
||||
// FormatPatchVersion returns the semver compatible version string given non-semver version
|
||||
func FormatPatchVersion(version string) string {
|
||||
part := strings.Split(version, ".")
|
||||
if len(part) > 3 {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/aquasecurity/fanal/types"
|
||||
)
|
||||
|
||||
// DockerConfig holds the config of Docker
|
||||
type DockerConfig struct {
|
||||
UserName string `env:"TRIVY_USERNAME"`
|
||||
Password string `env:"TRIVY_PASSWORD"`
|
||||
@@ -17,6 +18,7 @@ type DockerConfig struct {
|
||||
NonSSL bool `env:"TRIVY_NON_SSL" envDefault:"false"`
|
||||
}
|
||||
|
||||
// GetDockerOption returns the Docker scanning options using DockerConfig
|
||||
func GetDockerOption(timeout time.Duration) (types.DockerOption, error) {
|
||||
cfg := DockerConfig{}
|
||||
if err := env.Parse(&cfg); err != nil {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package types
|
||||
|
||||
// Library holds the attribute of a package library
|
||||
type Library struct {
|
||||
Name string
|
||||
Version string
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package types
|
||||
|
||||
// ScanOptions holds the attributes for scanning vulnerabilities
|
||||
type ScanOptions struct {
|
||||
VulnType []string
|
||||
ScanRemovedPackages bool
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/aquasecurity/trivy-db/pkg/types"
|
||||
)
|
||||
|
||||
// DetectedVulnerability holds the information of detected vulnerabilities
|
||||
type DetectedVulnerability struct {
|
||||
VulnerabilityID string `json:",omitempty"`
|
||||
PkgName string `json:",omitempty"`
|
||||
@@ -15,3 +16,26 @@ type DetectedVulnerability struct {
|
||||
|
||||
types.Vulnerability
|
||||
}
|
||||
|
||||
// BySeverity implements sort.Interface based on the Severity field.
|
||||
type BySeverity []DetectedVulnerability
|
||||
|
||||
// Len returns the length of DetectedVulnerabilities
|
||||
func (v BySeverity) Len() int { return len(v) }
|
||||
|
||||
// Less compares 2 DetectedVulnerabilities based on package name, severity and vulnerabilityID
|
||||
func (v BySeverity) Less(i, j int) bool {
|
||||
if v[i].PkgName != v[j].PkgName {
|
||||
return v[i].PkgName < v[j].PkgName
|
||||
}
|
||||
ret := types.CompareSeverityString(
|
||||
v[j].Severity, v[i].Severity,
|
||||
)
|
||||
if ret != 0 {
|
||||
return ret > 0
|
||||
}
|
||||
return v[i].VulnerabilityID < v[j].VulnerabilityID
|
||||
}
|
||||
|
||||
// Swap swaps 2 vulnerability
|
||||
func (v BySeverity) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
var cacheDir string
|
||||
|
||||
// DefaultCacheDir returns/creates the cache-dir to be used for trivu operations
|
||||
func DefaultCacheDir() string {
|
||||
tmpDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
@@ -27,14 +28,17 @@ func DefaultCacheDir() string {
|
||||
return filepath.Join(tmpDir, "trivy")
|
||||
}
|
||||
|
||||
// CacheDir returns the directory used for caching
|
||||
func CacheDir() string {
|
||||
return cacheDir
|
||||
}
|
||||
|
||||
// SetCacheDir sets the tricy cacheDir
|
||||
func SetCacheDir(dir string) {
|
||||
cacheDir = dir
|
||||
}
|
||||
|
||||
// FileWalk walks the directory and performs operations on files defined by walkFn
|
||||
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 err != nil {
|
||||
@@ -75,6 +79,7 @@ func FileWalk(root string, targetFiles map[string]struct{}, walkFn func(r io.Rea
|
||||
return nil
|
||||
}
|
||||
|
||||
// StringInSlice checks if strings exist in list of strings
|
||||
func StringInSlice(a string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
@@ -84,6 +89,7 @@ func StringInSlice(a string, list []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// FilterTargets filters the target based on prefixPath
|
||||
func FilterTargets(prefixPath string, targets map[string]struct{}) (map[string]struct{}, error) {
|
||||
filtered := map[string]struct{}{}
|
||||
for filename := range targets {
|
||||
@@ -101,6 +107,7 @@ func FilterTargets(prefixPath string, targets map[string]struct{}) (map[string]s
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
// CopyFile copies the file content from scr to dst
|
||||
func CopyFile(src, dst string) (int64, error) {
|
||||
sourceFileStat, err := os.Stat(src)
|
||||
if err != nil {
|
||||
|
||||
@@ -21,29 +21,35 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultIgnoreFile is the file name to be ignored
|
||||
DefaultIgnoreFile = ".trivyignore"
|
||||
)
|
||||
|
||||
// SuperSet binds the dependencies
|
||||
var SuperSet = wire.NewSet(
|
||||
wire.Struct(new(db.Config)),
|
||||
NewClient,
|
||||
wire.Bind(new(Operation), new(Client)),
|
||||
)
|
||||
|
||||
// Operation defines the vulnerability operations
|
||||
type Operation interface {
|
||||
FillInfo(vulns []types.DetectedVulnerability, reportType string)
|
||||
Filter(ctx context.Context, vulns []types.DetectedVulnerability, severities []dbTypes.Severity,
|
||||
ignoreUnfixed bool, ignoreFile string, policy string) ([]types.DetectedVulnerability, error)
|
||||
}
|
||||
|
||||
// Client implements db operations
|
||||
type Client struct {
|
||||
dbc db.Operation
|
||||
}
|
||||
|
||||
// NewClient is the factory method for Client
|
||||
func NewClient(dbc db.Config) Client {
|
||||
return Client{dbc: dbc}
|
||||
}
|
||||
|
||||
// FillInfo fills extra info rin vulnerability objects
|
||||
func (c Client) FillInfo(vulns []types.DetectedVulnerability, reportType string) {
|
||||
var err error
|
||||
|
||||
@@ -91,6 +97,7 @@ func (c Client) getVendorSeverity(vuln *types.DetectedVulnerability, reportType
|
||||
}
|
||||
}
|
||||
|
||||
// Filter filter out the vulnerabilities
|
||||
func (c Client) Filter(ctx context.Context, vulns []types.DetectedVulnerability, severities []dbTypes.Severity,
|
||||
ignoreUnfixed bool, ignoreFile string, policyFile string) ([]types.DetectedVulnerability, error) {
|
||||
ignoredIDs := getIgnoredIDs(ignoreFile)
|
||||
@@ -118,19 +125,7 @@ func (c Client) Filter(ctx context.Context, vulns []types.DetectedVulnerability,
|
||||
return nil, xerrors.Errorf("failed to apply the policy: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(vulnerabilities, func(i, j int) bool {
|
||||
if vulnerabilities[i].PkgName != vulnerabilities[j].PkgName {
|
||||
return vulnerabilities[i].PkgName < vulnerabilities[j].PkgName
|
||||
}
|
||||
ret := dbTypes.CompareSeverityString(
|
||||
vulnerabilities[j].Severity, vulnerabilities[i].Severity,
|
||||
)
|
||||
if ret != 0 {
|
||||
return ret > 0
|
||||
}
|
||||
return vulnerabilities[i].VulnerabilityID < vulnerabilities[j].VulnerabilityID
|
||||
})
|
||||
sort.Sort(types.BySeverity(vulnerabilities))
|
||||
return vulnerabilities, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user