mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
Added support of list-all-packages (#574)
* Added support of list-all-packages * updated Readme * Added library packages and fixed import name * updated env var name * Sorting packages in scan
This commit is contained in:
@@ -1731,6 +1731,7 @@ OPTIONS:
|
||||
--ignorefile value specify .trivyignore file (default: ".trivyignore") [$TRIVY_IGNOREFILE]
|
||||
--timeout value docker timeout (default: 2m0s) [$TRIVY_TIMEOUT]
|
||||
--light light mode: it's faster, but vulnerability descriptions and references are not displayed (default: false) [$TRIVY_LIGHT]
|
||||
--list-all-pkgs enabling the option will output all packages regardless of vulnerability [$TRIVY_LIST_ALL_PKGS]
|
||||
--help, -h show help (default: false)
|
||||
```
|
||||
|
||||
|
||||
@@ -182,6 +182,12 @@ var (
|
||||
EnvVars: []string{"TRIVY_IGNORE_POLICY"},
|
||||
}
|
||||
|
||||
listAllPackages = cli.BoolFlag{
|
||||
Name: "list-all-pkgs",
|
||||
Usage: "enabling the option will output all packages regardless of vulnerability",
|
||||
EnvVars: []string{"TRIVY_LIST_ALL_PKGS"},
|
||||
}
|
||||
|
||||
globalFlags = []cli.Flag{
|
||||
&quietFlag,
|
||||
&debugFlag,
|
||||
@@ -207,6 +213,7 @@ var (
|
||||
&timeoutFlag,
|
||||
&lightFlag,
|
||||
&ignorePolicy,
|
||||
&listAllPackages,
|
||||
}
|
||||
|
||||
// deprecated options
|
||||
@@ -360,6 +367,7 @@ func NewFilesystemCommand() *cli.Command {
|
||||
&timeoutFlag,
|
||||
&noProgressFlag,
|
||||
&ignorePolicy,
|
||||
&listAllPackages,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -389,6 +397,7 @@ func NewRepositoryCommand() *cli.Command {
|
||||
&timeoutFlag,
|
||||
&noProgressFlag,
|
||||
&ignorePolicy,
|
||||
&listAllPackages,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ func run(c config.Config, initializeScanner InitializeScanner) error {
|
||||
scanOptions := types.ScanOptions{
|
||||
VulnType: c.VulnType,
|
||||
ScanRemovedPackages: c.ScanRemovedPkgs, // this is valid only for image subcommand
|
||||
ListAllPackages: c.ListAllPkgs,
|
||||
}
|
||||
log.Logger.Debugf("Vulnerability type: %s", scanOptions.VulnType)
|
||||
|
||||
|
||||
@@ -9,11 +9,13 @@ import (
|
||||
|
||||
type ImageConfig struct {
|
||||
ScanRemovedPkgs bool
|
||||
ListAllPkgs bool
|
||||
}
|
||||
|
||||
func NewImageConfig(c *cli.Context) ImageConfig {
|
||||
return ImageConfig{
|
||||
ScanRemovedPkgs: c.Bool("removed-pkgs"),
|
||||
ListAllPkgs: c.Bool("list-all-pkgs"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"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"
|
||||
@@ -24,6 +25,7 @@ type Results []Result
|
||||
type Result struct {
|
||||
Target string `json:"Target"`
|
||||
Type string `json:"Type,omitempty"`
|
||||
Packages []ftypes.Package `json:"Packages,omitempty"`
|
||||
Vulnerabilities []types.DetectedVulnerability `json:"Vulnerabilities"`
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package local
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/wire"
|
||||
@@ -98,12 +99,18 @@ func (s Scanner) Scan(target string, imageID string, layerIDs []string, options
|
||||
return nil, nil, false, xerrors.Errorf("failed to scan OS packages: %w", err)
|
||||
}
|
||||
if result != nil {
|
||||
if options.ListAllPackages {
|
||||
sort.Slice(pkgs, func(i, j int) bool {
|
||||
return strings.Compare(pkgs[i].Name, pkgs[j].Name) <= 0
|
||||
})
|
||||
result.Packages = pkgs
|
||||
}
|
||||
results = append(results, *result)
|
||||
}
|
||||
}
|
||||
|
||||
if utils.StringInSlice("library", options.VulnType) {
|
||||
libResults, err := s.scanLibrary(imageDetail.Applications)
|
||||
libResults, err := s.scanLibrary(imageDetail.Applications, options.ListAllPackages)
|
||||
if err != nil {
|
||||
return nil, nil, false, xerrors.Errorf("failed to scan application libraries: %w", err)
|
||||
}
|
||||
@@ -133,19 +140,33 @@ func (s Scanner) scanOSPkg(target, osFamily, osName string, pkgs []ftypes.Packag
|
||||
return result, eosl, nil
|
||||
}
|
||||
|
||||
func (s Scanner) scanLibrary(apps []ftypes.Application) (report.Results, error) {
|
||||
func (s Scanner) scanLibrary(apps []ftypes.Application, listAllPackages bool) (report.Results, error) {
|
||||
var results report.Results
|
||||
for _, app := range apps {
|
||||
vulns, err := s.libDetector.Detect("", app.FilePath, time.Time{}, app.Libraries)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed vulnerability detection of libraries: %w", err)
|
||||
}
|
||||
|
||||
results = append(results, report.Result{
|
||||
libReport := report.Result{
|
||||
Target: app.FilePath,
|
||||
Vulnerabilities: vulns,
|
||||
Type: app.Type,
|
||||
})
|
||||
}
|
||||
if listAllPackages {
|
||||
var pkgs []ftypes.Package
|
||||
for _, lib := range app.Libraries {
|
||||
pkgs = append(pkgs, ftypes.Package{
|
||||
Name: lib.Library.Name,
|
||||
Version: lib.Library.Version,
|
||||
Layer: lib.Layer,
|
||||
})
|
||||
}
|
||||
sort.Slice(pkgs, func(i, j int) bool {
|
||||
return strings.Compare(pkgs[i].Name, pkgs[j].Name) <= 0
|
||||
})
|
||||
libReport.Packages = pkgs
|
||||
}
|
||||
results = append(results, libReport)
|
||||
}
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].Target < results[j].Target
|
||||
|
||||
@@ -173,6 +173,184 @@ func TestScanner_Scan(t *testing.T) {
|
||||
Name: "3.11",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with list all packages",
|
||||
args: args{
|
||||
target: "alpine:latest",
|
||||
layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
options: types.ScanOptions{VulnType: []string{"os", "library"}, ListAllPackages: true},
|
||||
},
|
||||
applyLayersExpectation: ApplierApplyLayersExpectation{
|
||||
Args: ApplierApplyLayersArgs{
|
||||
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
|
||||
},
|
||||
Returns: ApplierApplyLayersReturns{
|
||||
Detail: ftypes.ArtifactDetail{
|
||||
OS: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
Packages: []ftypes.Package{
|
||||
{
|
||||
Name: "musl",
|
||||
Version: "1.2.3",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ausl",
|
||||
Version: "1.2.3",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:bbf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888",
|
||||
},
|
||||
},
|
||||
},
|
||||
Applications: []ftypes.Application{
|
||||
{
|
||||
Type: "bundler",
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Libraries: []ftypes.LibraryInfo{
|
||||
{
|
||||
Library: dtypes.Library{Name: "rails", Version: "6.0"},
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ospkgDetectExpectations: []OspkgDetectorDetectExpectation{
|
||||
{
|
||||
Args: OspkgDetectorDetectArgs{
|
||||
OsFamily: "alpine",
|
||||
OsName: "3.11",
|
||||
Pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "musl",
|
||||
Version: "1.2.3",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ausl",
|
||||
Version: "1.2.3",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:bbf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Returns: OspkgDetectorDetectReturns{
|
||||
DetectedVulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-9999",
|
||||
PkgName: "musl",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888",
|
||||
},
|
||||
},
|
||||
},
|
||||
Eosl: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
libDetectExpectations: []LibraryDetectorDetectExpectation{
|
||||
{
|
||||
Args: LibraryDetectorDetectArgs{
|
||||
FilePath: "/app/Gemfile.lock",
|
||||
Pkgs: []ftypes.LibraryInfo{
|
||||
{
|
||||
Library: dtypes.Library{Name: "rails", Version: "6.0"},
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Returns: LibraryDetectorDetectReturns{
|
||||
DetectedVulns: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-10000",
|
||||
PkgName: "rails",
|
||||
InstalledVersion: "6.0",
|
||||
FixedVersion: "6.1",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResults: report.Results{
|
||||
{
|
||||
Target: "alpine:latest (alpine 3.11)",
|
||||
Packages: []ftypes.Package{
|
||||
{
|
||||
Name: "ausl",
|
||||
Version: "1.2.3",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:bbf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "musl",
|
||||
Version: "1.2.3",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-9999",
|
||||
PkgName: "musl",
|
||||
InstalledVersion: "1.2.3",
|
||||
FixedVersion: "1.2.4",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888",
|
||||
},
|
||||
},
|
||||
},
|
||||
Type: vulnerability.Alpine,
|
||||
},
|
||||
{
|
||||
Target: "/app/Gemfile.lock",
|
||||
Packages: []ftypes.Package{
|
||||
{
|
||||
Name: "rails",
|
||||
Version: "6.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2020-10000",
|
||||
PkgName: "rails",
|
||||
InstalledVersion: "6.0",
|
||||
FixedVersion: "6.1",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33",
|
||||
},
|
||||
},
|
||||
},
|
||||
Type: "bundler",
|
||||
},
|
||||
},
|
||||
wantOS: &ftypes.OS{
|
||||
Family: "alpine",
|
||||
Name: "3.11",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with empty os",
|
||||
args: args{
|
||||
|
||||
@@ -3,4 +3,5 @@ package types
|
||||
type ScanOptions struct {
|
||||
VulnType []string
|
||||
ScanRemovedPackages bool
|
||||
ListAllPackages bool
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user