diff --git a/pkg/fanal/analyzer/analyzer.go b/pkg/fanal/analyzer/analyzer.go index ccb578be62fa..48b7d7c71907 100644 --- a/pkg/fanal/analyzer/analyzer.go +++ b/pkg/fanal/analyzer/analyzer.go @@ -144,8 +144,9 @@ type PostAnalysisInput struct { } type AnalysisOptions struct { - Offline bool - FileChecksum bool + Offline bool + FileChecksum bool + CollectsFiles bool } type AnalysisResult struct { diff --git a/pkg/fanal/analyzer/pkg/apk/apk.go b/pkg/fanal/analyzer/pkg/apk/apk.go index a319ebc6717f..dd3d38531ba5 100644 --- a/pkg/fanal/analyzer/pkg/apk/apk.go +++ b/pkg/fanal/analyzer/pkg/apk/apk.go @@ -34,7 +34,7 @@ type alpinePkgAnalyzer struct{} func (a alpinePkgAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { scanner := bufio.NewScanner(input.Content) - parsedPkgs, installedFiles := a.parseApkInfo(scanner) + parsedPkgs, installedFiles := a.parseApkInfo(scanner, input) return &analyzer.AnalysisResult{ PackageInfos: []types.PackageInfo{ @@ -47,7 +47,7 @@ func (a alpinePkgAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInp }, nil } -func (a alpinePkgAnalyzer) parseApkInfo(scanner *bufio.Scanner) ([]types.Package, []string) { +func (a alpinePkgAnalyzer) parseApkInfo(scanner *bufio.Scanner, input analyzer.AnalysisInput) ([]types.Package, []string) { var ( pkgs []types.Package pkg types.Package @@ -90,7 +90,9 @@ func (a alpinePkgAnalyzer) parseApkInfo(scanner *bufio.Scanner) ([]types.Package dir = line[2:] case "R:": absPath := path.Join(dir, line[2:]) - pkg.InstalledFiles = append(pkg.InstalledFiles, absPath) + if input.Options.CollectsFiles { + pkg.InstalledFiles = append(pkg.InstalledFiles, absPath) + } installedFiles = append(installedFiles, absPath) case "p:": // provides (corresponds to provides in PKGINFO, concatenated by spaces into a single line) a.parseProvides(line, pkg.ID, provides) diff --git a/pkg/fanal/analyzer/pkg/apk/apk_test.go b/pkg/fanal/analyzer/pkg/apk/apk_test.go index f7b308fcbd49..9244e7db43c8 100644 --- a/pkg/fanal/analyzer/pkg/apk/apk_test.go +++ b/pkg/fanal/analyzer/pkg/apk/apk_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/types" ) @@ -411,7 +412,7 @@ func TestParseApkInfo(t *testing.T) { defer f.Close() require.NoError(t, err) scanner := bufio.NewScanner(f) - gotPkgs, gotFiles := a.parseApkInfo(scanner) + gotPkgs, gotFiles := a.parseApkInfo(scanner, analyzer.AnalysisInput{}) assert.Equal(t, tt.wantPkgs, gotPkgs) assert.Equal(t, tt.wantFiles, gotFiles) diff --git a/pkg/fanal/analyzer/pkg/dpkg/dpkg.go b/pkg/fanal/analyzer/pkg/dpkg/dpkg.go index 74fd4d82ef7b..0b35db1a18d9 100644 --- a/pkg/fanal/analyzer/pkg/dpkg/dpkg.go +++ b/pkg/fanal/analyzer/pkg/dpkg/dpkg.go @@ -76,7 +76,9 @@ func (a dpkgAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysis if err != nil { return err } - packageFiles[strings.TrimSuffix(filepath.Base(path), ".list")] = systemFiles + if input.Options.CollectsFiles { + packageFiles[strings.TrimSuffix(filepath.Base(path), ".list")] = systemFiles + } systemInstalledFiles = append(systemInstalledFiles, systemFiles...) return nil } @@ -92,14 +94,16 @@ func (a dpkgAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysis return nil, xerrors.Errorf("dpkg walk error: %w", err) } - // map the packages to their respective files - for i, pkgInfo := range packageInfos { - for j, pkg := range pkgInfo.Packages { - installedFiles, found := packageFiles[pkg.Name] - if !found { - installedFiles = packageFiles[pkg.Name+":"+pkg.Arch] + if input.Options.CollectsFiles { + // map the packages to their respective files + for i, pkgInfo := range packageInfos { + for j, pkg := range pkgInfo.Packages { + installedFiles, found := packageFiles[pkg.Name] + if !found { + installedFiles = packageFiles[pkg.Name+":"+pkg.Arch] + } + packageInfos[i].Packages[j].InstalledFiles = installedFiles } - packageInfos[i].Packages[j].InstalledFiles = installedFiles } } diff --git a/pkg/fanal/analyzer/pkg/rpm/rpm.go b/pkg/fanal/analyzer/pkg/rpm/rpm.go index 21c8f50c93e5..e75ba73a114b 100644 --- a/pkg/fanal/analyzer/pkg/rpm/rpm.go +++ b/pkg/fanal/analyzer/pkg/rpm/rpm.go @@ -64,7 +64,7 @@ var osVendors = []string{ type rpmPkgAnalyzer struct{} func (a rpmPkgAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { - parsedPkgs, installedFiles, err := a.parsePkgInfo(input.Content) + parsedPkgs, installedFiles, err := a.parsePkgInfo(input.Content, input) if err != nil { return nil, xerrors.Errorf("failed to parse rpmdb: %w", err) } @@ -80,7 +80,7 @@ func (a rpmPkgAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) }, nil } -func (a rpmPkgAnalyzer) parsePkgInfo(rc io.Reader) (types.Packages, []string, error) { +func (a rpmPkgAnalyzer) parsePkgInfo(rc io.Reader, input analyzer.AnalysisInput) (types.Packages, []string, error) { filePath, err := writeToTempFile(rc) if err != nil { return nil, nil, xerrors.Errorf("temp file error: %w", err) @@ -154,7 +154,10 @@ func (a rpmPkgAnalyzer) parsePkgInfo(rc io.Reader) (types.Packages, []string, er DependsOn: pkg.Requires, // Will be replaced with package IDs Maintainer: pkg.Vendor, Digest: d, - InstalledFiles: files, + } + + if input.Options.CollectsFiles { + p.InstalledFiles = files } pkgs = append(pkgs, p) installedFiles = append(installedFiles, files...) diff --git a/pkg/fanal/analyzer/pkg/rpm/rpm_test.go b/pkg/fanal/analyzer/pkg/rpm/rpm_test.go index 9cb29cbb09b6..66297fe2707a 100644 --- a/pkg/fanal/analyzer/pkg/rpm/rpm_test.go +++ b/pkg/fanal/analyzer/pkg/rpm/rpm_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/types" ) @@ -547,7 +548,7 @@ func TestParseRpmInfo(t *testing.T) { require.NoError(t, err) defer f.Close() - got, _, err := a.parsePkgInfo(f) + got, _, err := a.parsePkgInfo(f, analyzer.AnalysisInput{}) require.NoError(t, err) sort.Sort(tc.pkgs) diff --git a/pkg/fanal/artifact/artifact.go b/pkg/fanal/artifact/artifact.go index 2028b601c744..8c8b84e53d14 100644 --- a/pkg/fanal/artifact/artifact.go +++ b/pkg/fanal/artifact/artifact.go @@ -20,6 +20,7 @@ type Option struct { NoProgress bool Insecure bool Offline bool + CollectFiles bool AppDirs []string SBOMSources []string RekorURL string diff --git a/pkg/fanal/artifact/local/fs.go b/pkg/fanal/artifact/local/fs.go index 49d20fd14f95..e0c1df124750 100644 --- a/pkg/fanal/artifact/local/fs.go +++ b/pkg/fanal/artifact/local/fs.go @@ -124,8 +124,9 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error) result := analyzer.NewAnalysisResult() limit := semaphore.New(a.artifactOption.Slow) opts := analyzer.AnalysisOptions{ - Offline: a.artifactOption.Offline, - FileChecksum: a.artifactOption.FileChecksum, + Offline: a.artifactOption.Offline, + FileChecksum: a.artifactOption.FileChecksum, + CollectsFiles: a.artifactOption.CollectFiles, } // Prepare filesystem for post analysis diff --git a/pkg/fanal/test/integration/containerd_test.go b/pkg/fanal/test/integration/containerd_test.go index 45339fd9a347..285d54a4984c 100644 --- a/pkg/fanal/test/integration/containerd_test.go +++ b/pkg/fanal/test/integration/containerd_test.go @@ -246,7 +246,7 @@ func TestContainerd_SearchLocalStoreByNameOrDigest(t *testing.T) { } require.NoError(t, err) - ar, err := aimage.NewArtifact(img, c, artifact.Option{}) + ar, err := aimage.NewArtifact(img, c, artifact.Option{CollectFiles: true}) require.NoError(t, err) ref, err := ar.Inspect(ctx) @@ -694,6 +694,7 @@ func localImageTestWithNamespace(t *testing.T, namespace string) { analyzer.TypeExecutable, analyzer.TypeLicenseFile, }, + CollectFiles: true, }) require.NoError(t, err) @@ -830,6 +831,7 @@ func TestContainerd_PullImage(t *testing.T) { analyzer.TypeExecutable, analyzer.TypeLicenseFile, }, + CollectFiles: true, }) require.NoError(t, err) require.NotNil(t, art)