diff --git a/pkg/fanal/analyzer/analyzer.go b/pkg/fanal/analyzer/analyzer.go index abedb4b90638..c30d835bbcd7 100644 --- a/pkg/fanal/analyzer/analyzer.go +++ b/pkg/fanal/analyzer/analyzer.go @@ -142,8 +142,9 @@ type AnalysisInput struct { } type PostAnalysisInput struct { - FS fs.FS - Options AnalysisOptions + FS fs.FS + Options AnalysisOptions + FilePathsMatchedFromPatterns []string // List of filePaths got from --file-patterns flag } type AnalysisOptions struct { @@ -455,13 +456,23 @@ func (ag AnalyzerGroup) AnalyzeFile(ctx context.Context, wg *sync.WaitGroup, lim } // RequiredPostAnalyzers returns a list of analyzer types that require the given file. -func (ag AnalyzerGroup) RequiredPostAnalyzers(filePath string, info os.FileInfo) []Type { +func (ag AnalyzerGroup) RequiredPostAnalyzers(filePath string, info os.FileInfo, requiredByFilePatterns map[Type][]string) []Type { if info.IsDir() { return nil } var postAnalyzerTypes []Type for _, a := range ag.postAnalyzers { - if ag.filePatternMatch(a.Type(), filePath) || a.Required(filePath, info) { + if ag.filePatternMatch(a.Type(), filePath) { + postAnalyzerTypes = append(postAnalyzerTypes, a.Type()) + + // Save filePaths for files required by filePatterns to use in PostAnalyze + filePaths := []string{filePath} + if saved, ok := requiredByFilePatterns[a.Type()]; ok { + filePaths = append(filePaths, saved...) + } + requiredByFilePatterns[a.Type()] = filePaths + } + if a.Required(filePath, info) { postAnalyzerTypes = append(postAnalyzerTypes, a.Type()) } } @@ -472,7 +483,8 @@ func (ag AnalyzerGroup) RequiredPostAnalyzers(filePath string, info os.FileInfo) // and passes it to the respective post-analyzer. // The obtained results are merged into the "result". // This function may be called concurrently and must be thread-safe. -func (ag AnalyzerGroup) PostAnalyze(ctx context.Context, compositeFS *CompositeFS, result *AnalysisResult, opts AnalysisOptions) error { +func (ag AnalyzerGroup) PostAnalyze(ctx context.Context, compositeFS *CompositeFS, result *AnalysisResult, + opts AnalysisOptions, requiredByFilePatterns map[Type][]string) error { for _, a := range ag.postAnalyzers { fsys, ok := compositeFS.Get(a.Type()) if !ok { @@ -503,8 +515,9 @@ func (ag AnalyzerGroup) PostAnalyze(ctx context.Context, compositeFS *CompositeF } res, err := a.PostAnalyze(ctx, PostAnalysisInput{ - FS: filteredFS, - Options: opts, + FS: filteredFS, + Options: opts, + FilePathsMatchedFromPatterns: requiredByFilePatterns[a.Type()], }) if err != nil { return xerrors.Errorf("post analysis error: %w", err) diff --git a/pkg/fanal/analyzer/analyzer_test.go b/pkg/fanal/analyzer/analyzer_test.go index 313fccda7e94..ce795658e844 100644 --- a/pkg/fanal/analyzer/analyzer_test.go +++ b/pkg/fanal/analyzer/analyzer_test.go @@ -630,7 +630,7 @@ func TestAnalyzerGroup_PostAnalyze(t *testing.T) { ctx := context.Background() got := new(analyzer.AnalysisResult) - err = a.PostAnalyze(ctx, composite, got, analyzer.AnalysisOptions{}) + err = a.PostAnalyze(ctx, composite, got, analyzer.AnalysisOptions{}, make(map[analyzer.Type][]string)) require.NoError(t, err) assert.Equal(t, tt.want, got) }) diff --git a/pkg/fanal/analyzer/language/c/conan/conan.go b/pkg/fanal/analyzer/language/c/conan/conan.go index a32591dae7fe..a63d4a462024 100644 --- a/pkg/fanal/analyzer/language/c/conan/conan.go +++ b/pkg/fanal/analyzer/language/c/conan/conan.go @@ -45,7 +45,7 @@ func newConanLockAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, er func (a conanLockAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysisInput) (*analyzer.AnalysisResult, error) { required := func(filePath string, d fs.DirEntry) bool { - // we need all file got from `a.Required` function (conan.lock files) and from file-patterns. + // Parse all required files: `conan.lock` (from a.Required func) + input.FilePathsMatchedFromPatterns return true } diff --git a/pkg/fanal/analyzer/language/dart/pub/pubspec.go b/pkg/fanal/analyzer/language/dart/pub/pubspec.go index 30fc2dadb18b..c64cf4a31837 100644 --- a/pkg/fanal/analyzer/language/dart/pub/pubspec.go +++ b/pkg/fanal/analyzer/language/dart/pub/pubspec.go @@ -55,7 +55,8 @@ func (a pubSpecLockAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostA } required := func(path string, d fs.DirEntry) bool { - return filepath.Base(path) == types.PubSpecLock + // Parse all required files: `pubspec.lock` (from a.Required func) + input.FilePathsMatchedFromPatterns + return true } err = fsutils.WalkDir(input.FS, ".", required, func(path string, _ fs.DirEntry, r io.Reader) error { diff --git a/pkg/fanal/analyzer/language/dotnet/nuget/nuget.go b/pkg/fanal/analyzer/language/dotnet/nuget/nuget.go index b7400048edac..75c254a45a90 100644 --- a/pkg/fanal/analyzer/language/dotnet/nuget/nuget.go +++ b/pkg/fanal/analyzer/language/dotnet/nuget/nuget.go @@ -59,9 +59,8 @@ func (a *nugetLibraryAnalyzer) PostAnalyze(_ context.Context, input analyzer.Pos a.logger.Debug("The nuget packages directory couldn't be found. License search disabled") } - // We saved only config and lock files in the FS, - // so we need to parse all saved files required := func(path string, d fs.DirEntry) bool { + // Parse all required files: `packages.lock.json`, `packages.config` (from a.Required func) + input.FilePathsMatchedFromPatterns return true } diff --git a/pkg/fanal/analyzer/language/golang/mod/mod.go b/pkg/fanal/analyzer/language/golang/mod/mod.go index 398511fdc63c..372622f4ac54 100644 --- a/pkg/fanal/analyzer/language/golang/mod/mod.go +++ b/pkg/fanal/analyzer/language/golang/mod/mod.go @@ -68,7 +68,7 @@ func (a *gomodAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalys var apps []types.Application required := func(path string, d fs.DirEntry) bool { - return filepath.Base(path) == types.GoMod + return filepath.Base(path) == types.GoMod || slices.Contains(input.FilePathsMatchedFromPatterns, path) } err := fsutils.WalkDir(input.FS, ".", required, func(path string, d fs.DirEntry, _ io.Reader) error { diff --git a/pkg/fanal/analyzer/language/java/gradle/lockfile.go b/pkg/fanal/analyzer/language/java/gradle/lockfile.go index ce7fc2c31e59..3e9c7419b0d2 100644 --- a/pkg/fanal/analyzer/language/java/gradle/lockfile.go +++ b/pkg/fanal/analyzer/language/java/gradle/lockfile.go @@ -49,7 +49,8 @@ func (a gradleLockAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAn } required := func(path string, d fs.DirEntry) bool { - return a.Required(path, nil) + // Parse all required files: `*gradle.lockfile` (from a.Required func) + input.FilePathsMatchedFromPatterns + return true } var apps []types.Application diff --git a/pkg/fanal/analyzer/language/julia/pkg/pkg.go b/pkg/fanal/analyzer/language/julia/pkg/pkg.go index 66d715e061b2..7ae13e85d44c 100644 --- a/pkg/fanal/analyzer/language/julia/pkg/pkg.go +++ b/pkg/fanal/analyzer/language/julia/pkg/pkg.go @@ -54,7 +54,7 @@ func (a juliaAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysi var apps []types.Application required := func(path string, d fs.DirEntry) bool { - return filepath.Base(path) == types.JuliaManifest + return filepath.Base(path) == types.JuliaManifest || slices.Contains(input.FilePathsMatchedFromPatterns, path) } err := fsutils.WalkDir(input.FS, ".", required, func(path string, d fs.DirEntry, r io.Reader) error { diff --git a/pkg/fanal/analyzer/language/nodejs/npm/npm.go b/pkg/fanal/analyzer/language/nodejs/npm/npm.go index 870ba1be88e7..f21427668d29 100644 --- a/pkg/fanal/analyzer/language/nodejs/npm/npm.go +++ b/pkg/fanal/analyzer/language/nodejs/npm/npm.go @@ -8,6 +8,7 @@ import ( "os" "path" "path/filepath" + "slices" "golang.org/x/xerrors" @@ -47,7 +48,7 @@ func newNpmLibraryAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, e func (a npmLibraryAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysisInput) (*analyzer.AnalysisResult, error) { // Parse package-lock.json required := func(path string, _ fs.DirEntry) bool { - return filepath.Base(path) == types.NpmPkgLock + return filepath.Base(path) == types.NpmPkgLock || slices.Contains(input.FilePathsMatchedFromPatterns, path) } var apps []types.Application diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go index 9c8f51a38265..5fe3cff19e3c 100644 --- a/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go @@ -8,6 +8,7 @@ import ( "os" "path" "path/filepath" + "slices" "golang.org/x/xerrors" @@ -45,7 +46,7 @@ func (a pnpmAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysis var apps []types.Application required := func(path string, d fs.DirEntry) bool { - return filepath.Base(path) == types.PnpmLock + return filepath.Base(path) == types.PnpmLock || slices.Contains(input.FilePathsMatchedFromPatterns, path) } err := fsutils.WalkDir(input.FS, ".", required, func(filePath string, d fs.DirEntry, r io.Reader) error { diff --git a/pkg/fanal/analyzer/language/nodejs/yarn/yarn.go b/pkg/fanal/analyzer/language/nodejs/yarn/yarn.go index 984f72983ec9..b8afd7cef96a 100644 --- a/pkg/fanal/analyzer/language/nodejs/yarn/yarn.go +++ b/pkg/fanal/analyzer/language/nodejs/yarn/yarn.go @@ -71,7 +71,7 @@ func (a yarnAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysis var apps []types.Application required := func(path string, d fs.DirEntry) bool { - return filepath.Base(path) == types.YarnLock + return filepath.Base(path) == types.YarnLock || slices.Contains(input.FilePathsMatchedFromPatterns, path) } err := fsutils.WalkDir(input.FS, ".", required, func(filePath string, d fs.DirEntry, r io.Reader) error { diff --git a/pkg/fanal/analyzer/language/php/composer/composer.go b/pkg/fanal/analyzer/language/php/composer/composer.go index d0b3f4466352..879529bec9a7 100644 --- a/pkg/fanal/analyzer/language/php/composer/composer.go +++ b/pkg/fanal/analyzer/language/php/composer/composer.go @@ -47,7 +47,7 @@ func (a composerAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnal var apps []types.Application required := func(path string, d fs.DirEntry) bool { - return filepath.Base(path) == types.ComposerLock + return filepath.Base(path) == types.ComposerLock || slices.Contains(input.FilePathsMatchedFromPatterns, path) } err := fsutils.WalkDir(input.FS, ".", required, func(path string, d fs.DirEntry, r io.Reader) error { diff --git a/pkg/fanal/analyzer/language/python/packaging/packaging.go b/pkg/fanal/analyzer/language/python/packaging/packaging.go index 944a5abde331..83f32b8f9706 100644 --- a/pkg/fanal/analyzer/language/python/packaging/packaging.go +++ b/pkg/fanal/analyzer/language/python/packaging/packaging.go @@ -8,6 +8,7 @@ import ( "os" "path" "path/filepath" + "slices" "strings" "github.com/samber/lo" @@ -63,7 +64,7 @@ func (a packagingAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAna var apps []types.Application required := func(path string, _ fs.DirEntry) bool { - return filepath.Base(path) == "METADATA" || isEggFile(path) + return filepath.Base(path) == "METADATA" || isEggFile(path) || slices.Contains(input.FilePathsMatchedFromPatterns, path) } err := fsutils.WalkDir(input.FS, ".", required, func(filePath string, d fs.DirEntry, r io.Reader) error { diff --git a/pkg/fanal/analyzer/language/python/pip/pip.go b/pkg/fanal/analyzer/language/python/pip/pip.go index 670dd195bb50..a4feb8664e8b 100644 --- a/pkg/fanal/analyzer/language/python/pip/pip.go +++ b/pkg/fanal/analyzer/language/python/pip/pip.go @@ -59,8 +59,8 @@ func (a pipLibraryAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAn a.logger.Warn("Unable to find python `site-packages` directory. License detection is skipped.", log.Err(err)) } - // We only saved the `requirements.txt` files required := func(_ string, _ fs.DirEntry) bool { + // Parse all required files: `conan.lock` (from a.Required func) + input.FilePathsMatchedFromPatterns return true } diff --git a/pkg/fanal/analyzer/language/python/poetry/poetry.go b/pkg/fanal/analyzer/language/python/poetry/poetry.go index 3b751f747621..0aede0af5e98 100644 --- a/pkg/fanal/analyzer/language/python/poetry/poetry.go +++ b/pkg/fanal/analyzer/language/python/poetry/poetry.go @@ -7,6 +7,7 @@ import ( "io/fs" "os" "path/filepath" + "slices" "github.com/samber/lo" "golang.org/x/xerrors" @@ -44,7 +45,7 @@ func (a poetryAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalys var apps []types.Application required := func(path string, d fs.DirEntry) bool { - return filepath.Base(path) == types.PoetryLock + return filepath.Base(path) == types.PoetryLock || slices.Contains(input.FilePathsMatchedFromPatterns, path) } err := fsutils.WalkDir(input.FS, ".", required, func(path string, d fs.DirEntry, r io.Reader) error { diff --git a/pkg/fanal/analyzer/language/rust/cargo/cargo.go b/pkg/fanal/analyzer/language/rust/cargo/cargo.go index ab436bf95fe2..c3fce63319a6 100644 --- a/pkg/fanal/analyzer/language/rust/cargo/cargo.go +++ b/pkg/fanal/analyzer/language/rust/cargo/cargo.go @@ -57,7 +57,7 @@ func (a cargoAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysi var apps []types.Application required := func(path string, d fs.DirEntry) bool { - return filepath.Base(path) == types.CargoLock + return filepath.Base(path) == types.CargoLock || slices.Contains(input.FilePathsMatchedFromPatterns, path) } err := fsutils.WalkDir(input.FS, ".", required, func(filePath string, d fs.DirEntry, r io.Reader) error { diff --git a/pkg/fanal/artifact/image/image.go b/pkg/fanal/artifact/image/image.go index b4350b25b866..abb896e60ac7 100644 --- a/pkg/fanal/artifact/image/image.go +++ b/pkg/fanal/artifact/image/image.go @@ -264,6 +264,8 @@ func (a Artifact) inspectLayer(ctx context.Context, layerInfo LayerInfo, disable } defer composite.Cleanup() + // Files required by file patterns grouped by analyzer types + requiredByFilePatterns := make(map[analyzer.Type][]string) // Walk a tar layer opqDirs, whFiles, err := a.walker.Walk(rc, func(filePath string, info os.FileInfo, opener analyzer.Opener) error { if err = a.analyzer.AnalyzeFile(ctx, &wg, limit, result, "", filePath, info, opener, disabled, opts); err != nil { @@ -271,7 +273,7 @@ func (a Artifact) inspectLayer(ctx context.Context, layerInfo LayerInfo, disable } // Skip post analysis if the file is not required - analyzerTypes := a.analyzer.RequiredPostAnalyzers(filePath, info) + analyzerTypes := a.analyzer.RequiredPostAnalyzers(filePath, info, requiredByFilePatterns) if len(analyzerTypes) == 0 { return nil } @@ -295,7 +297,7 @@ func (a Artifact) inspectLayer(ctx context.Context, layerInfo LayerInfo, disable wg.Wait() // Post-analysis - if err = a.analyzer.PostAnalyze(ctx, composite, result, opts); err != nil { + if err = a.analyzer.PostAnalyze(ctx, composite, result, opts, requiredByFilePatterns); err != nil { return types.BlobInfo{}, xerrors.Errorf("post analysis error: %w", err) } diff --git a/pkg/fanal/artifact/local/fs.go b/pkg/fanal/artifact/local/fs.go index 2f5ef7fe4ecd..c4e79db97460 100644 --- a/pkg/fanal/artifact/local/fs.go +++ b/pkg/fanal/artifact/local/fs.go @@ -83,6 +83,9 @@ func (a Artifact) Inspect(ctx context.Context) (artifact.Reference, error) { return artifact.Reference{}, xerrors.Errorf("failed to prepare filesystem for post analysis: %w", err) } + // Files required by file patterns grouped by analyzer types + requiredByFilePatterns := make(map[analyzer.Type][]string) + err = a.walker.Walk(a.rootPath, a.artifactOption.WalkerOption, func(filePath string, info os.FileInfo, opener analyzer.Opener) error { dir := a.rootPath @@ -97,7 +100,7 @@ func (a Artifact) Inspect(ctx context.Context) (artifact.Reference, error) { } // Skip post analysis if the file is not required - analyzerTypes := a.analyzer.RequiredPostAnalyzers(filePath, info) + analyzerTypes := a.analyzer.RequiredPostAnalyzers(filePath, info, requiredByFilePatterns) if len(analyzerTypes) == 0 { return nil } @@ -117,7 +120,7 @@ func (a Artifact) Inspect(ctx context.Context) (artifact.Reference, error) { wg.Wait() // Post-analysis - if err = a.analyzer.PostAnalyze(ctx, composite, result, opts); err != nil { + if err = a.analyzer.PostAnalyze(ctx, composite, result, opts, requiredByFilePatterns); err != nil { return artifact.Reference{}, xerrors.Errorf("post analysis error: %w", err) } diff --git a/pkg/fanal/artifact/local/fs_test.go b/pkg/fanal/artifact/local/fs_test.go index dbef68e893bb..d1f0c90cf5b3 100644 --- a/pkg/fanal/artifact/local/fs_test.go +++ b/pkg/fanal/artifact/local/fs_test.go @@ -18,6 +18,7 @@ import ( "github.com/aquasecurity/trivy/pkg/misconf" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/all" + _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/npm" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/python/pip" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/os/alpine" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/pkg/apk" @@ -47,7 +48,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:5ba63074e071e3f0247d03dd7e544b6a75f7224ee238618482c490b36f4792dc", + BlobID: "sha256:08434f862f7e9a56a6575749dd38b1885985b959c9e234a8be1b98b741fe199c", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -82,9 +83,9 @@ func TestArtifact_Inspect(t *testing.T) { want: artifact.Reference{ Name: "host", Type: artifact.TypeFilesystem, - ID: "sha256:5ba63074e071e3f0247d03dd7e544b6a75f7224ee238618482c490b36f4792dc", + ID: "sha256:08434f862f7e9a56a6575749dd38b1885985b959c9e234a8be1b98b741fe199c", BlobIDs: []string{ - "sha256:5ba63074e071e3f0247d03dd7e544b6a75f7224ee238618482c490b36f4792dc", + "sha256:08434f862f7e9a56a6575749dd38b1885985b959c9e234a8be1b98b741fe199c", }, }, }, @@ -98,6 +99,7 @@ func TestArtifact_Inspect(t *testing.T) { analyzer.TypeAlpine, analyzer.TypeApk, analyzer.TypePip, + analyzer.TypeNpmPkgLock, }, }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ @@ -125,7 +127,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:5ba63074e071e3f0247d03dd7e544b6a75f7224ee238618482c490b36f4792dc", + BlobID: "sha256:08434f862f7e9a56a6575749dd38b1885985b959c9e234a8be1b98b741fe199c", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -175,7 +177,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", + BlobID: "sha256:8e7dab5cdac2610dddfc4f7655fb83c60959414ed79b6b4bc2db8969dee6b08b", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ @@ -203,9 +205,63 @@ func TestArtifact_Inspect(t *testing.T) { want: artifact.Reference{ Name: "testdata/requirements.txt", Type: artifact.TypeFilesystem, - ID: "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", + ID: "sha256:8e7dab5cdac2610dddfc4f7655fb83c60959414ed79b6b4bc2db8969dee6b08b", BlobIDs: []string{ - "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", + "sha256:8e7dab5cdac2610dddfc4f7655fb83c60959414ed79b6b4bc2db8969dee6b08b", + }, + }, + }, + { + name: "happy path with single file got from filePatterns", + fields: fields{ + dir: "testdata/my-package-lock.json", + }, + artifactOpt: artifact.Option{ + FilePatterns: []string{ + "npm:my-.*-lock.json", + }, + }, + putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ + Args: cache.ArtifactCachePutBlobArgs{ + BlobID: "sha256:d611213b69108e725dff998cb48eabd104f0bd0723dcf560233f392eb38b2541", + BlobInfo: types.BlobInfo{ + SchemaVersion: types.BlobJSONSchemaVersion, + Applications: []types.Application{ + { + Type: "npm", + FilePath: "my-package-lock.json", + Packages: types.Packages{ + { + ID: "ms@2.1.3", + Name: "ms", + Version: "2.1.3", + Relationship: types.RelationshipDirect, + Locations: []types.Location{ + { + StartLine: 15, + EndLine: 20, + }, + }, + ExternalReferences: []types.ExternalRef{ + { + Type: types.RefOther, + URL: "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + }, + }, + }, + }, + }, + }, + }, + }, + Returns: cache.ArtifactCachePutBlobReturns{}, + }, + want: artifact.Reference{ + Name: "testdata/my-package-lock.json", + Type: artifact.TypeFilesystem, + ID: "sha256:d611213b69108e725dff998cb48eabd104f0bd0723dcf560233f392eb38b2541", + BlobIDs: []string{ + "sha256:d611213b69108e725dff998cb48eabd104f0bd0723dcf560233f392eb38b2541", }, }, }, @@ -216,7 +272,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", + BlobID: "sha256:8e7dab5cdac2610dddfc4f7655fb83c60959414ed79b6b4bc2db8969dee6b08b", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ @@ -244,9 +300,9 @@ func TestArtifact_Inspect(t *testing.T) { want: artifact.Reference{ Name: "testdata/requirements.txt", Type: artifact.TypeFilesystem, - ID: "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", + ID: "sha256:8e7dab5cdac2610dddfc4f7655fb83c60959414ed79b6b4bc2db8969dee6b08b", BlobIDs: []string{ - "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", + "sha256:8e7dab5cdac2610dddfc4f7655fb83c60959414ed79b6b4bc2db8969dee6b08b", }, }, }, @@ -332,9 +388,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/single-failure", Type: artifact.TypeFilesystem, - ID: "sha256:4f2a334086f1d175c0ee57cd4220f20b187b456dc36bbe39a63c42b5637b2179", + ID: "sha256:a17dce21ef90889a5dea35c8cb65c8e317f91713651f1f656fc4bff2647f3f70", BlobIDs: []string{ - "sha256:4f2a334086f1d175c0ee57cd4220f20b187b456dc36bbe39a63c42b5637b2179", + "sha256:a17dce21ef90889a5dea35c8cb65c8e317f91713651f1f656fc4bff2647f3f70", }, }, }, @@ -408,9 +464,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/multiple-failures", Type: artifact.TypeFilesystem, - ID: "sha256:ff7a84de97729e169c94107a89bc9da88f5ecf94873cdbd9bf0844e1af5f5b30", + ID: "sha256:81b5c45917329d0892dc5a5ea5ec73d89aaafa8b251fa94731499f9f4f658bdf", BlobIDs: []string{ - "sha256:ff7a84de97729e169c94107a89bc9da88f5ecf94873cdbd9bf0844e1af5f5b30", + "sha256:81b5c45917329d0892dc5a5ea5ec73d89aaafa8b251fa94731499f9f4f658bdf", }, }, }, @@ -431,9 +487,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/no-results", Type: artifact.TypeFilesystem, - ID: "sha256:06406e9bb7ba09d8d24c73c0995ac3b94fc1d6ce059e5a45418d7c0ab2b6dca4", + ID: "sha256:92e6c822670c479822230f144b6806931a6a18b5499788a8bf4b460894c79ef5", BlobIDs: []string{ - "sha256:06406e9bb7ba09d8d24c73c0995ac3b94fc1d6ce059e5a45418d7c0ab2b6dca4", + "sha256:92e6c822670c479822230f144b6806931a6a18b5499788a8bf4b460894c79ef5", }, }, }, @@ -471,9 +527,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/passed", Type: artifact.TypeFilesystem, - ID: "sha256:107251e6ee7312c8c27ff04e71dd943b92021777c575971809f57b60bf41bba4", + ID: "sha256:b9af9e04f44d351d0db13cea80d2ac9c573f7987d199cb602b137f345ec33025", BlobIDs: []string{ - "sha256:107251e6ee7312c8c27ff04e71dd943b92021777c575971809f57b60bf41bba4", + "sha256:b9af9e04f44d351d0db13cea80d2ac9c573f7987d199cb602b137f345ec33025", }, }, }, @@ -528,9 +584,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/busted-relative-paths/child/main.tf", Type: artifact.TypeFilesystem, - ID: "sha256:f2f07f41dbd6816d41ce6f28b3922fcedab611b8602d95e328571afd5c53b31d", + ID: "sha256:d31def375864e60ee336e7806562f877e98f5b844d0117c70065128953d71f8d", BlobIDs: []string{ - "sha256:f2f07f41dbd6816d41ce6f28b3922fcedab611b8602d95e328571afd5c53b31d", + "sha256:d31def375864e60ee336e7806562f877e98f5b844d0117c70065128953d71f8d", }, }, }, @@ -573,9 +629,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/tfvar-outside/tf", Type: artifact.TypeFilesystem, - ID: "sha256:107251e6ee7312c8c27ff04e71dd943b92021777c575971809f57b60bf41bba4", + ID: "sha256:b9af9e04f44d351d0db13cea80d2ac9c573f7987d199cb602b137f345ec33025", BlobIDs: []string{ - "sha256:107251e6ee7312c8c27ff04e71dd943b92021777c575971809f57b60bf41bba4", + "sha256:b9af9e04f44d351d0db13cea80d2ac9c573f7987d199cb602b137f345ec33025", }, }, }, @@ -655,9 +711,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/relative-paths/child", Type: artifact.TypeFilesystem, - ID: "sha256:f04c37d8e5300ce9344c795c2d4e0bb1dbef251b15538a6e0c11d6d9a86664d1", + ID: "sha256:df7adc5839d508ea2bce0bf526eb08bbb4f0bc1e4d3ebf5ce897ecfabca2edca", BlobIDs: []string{ - "sha256:f04c37d8e5300ce9344c795c2d4e0bb1dbef251b15538a6e0c11d6d9a86664d1", + "sha256:df7adc5839d508ea2bce0bf526eb08bbb4f0bc1e4d3ebf5ce897ecfabca2edca", }, }, }, @@ -776,9 +832,9 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraformplan/snapshots/single-failure", Type: artifact.TypeFilesystem, - ID: "sha256:c21e15d7d0cfe7c1ef1e1933b443f781d1411b864500431302a1e45fe0950529", + ID: "sha256:4ae243c0ee816ce55140d88daade3dfb9de13b0edba931c664beb5de5a4bb3d3", BlobIDs: []string{ - "sha256:c21e15d7d0cfe7c1ef1e1933b443f781d1411b864500431302a1e45fe0950529", + "sha256:4ae243c0ee816ce55140d88daade3dfb9de13b0edba931c664beb5de5a4bb3d3", }, }, }, @@ -852,9 +908,9 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraformplan/snapshots/multiple-failures", Type: artifact.TypeFilesystem, - ID: "sha256:800c9ce07be36c7f4d1a4876ecfaaa77c1d90b15f43c58eaf52ea27670afcc42", + ID: "sha256:bd0eab2a9df3aa47333bcd9a39e9476127654628b57fb0e767c3736e0da00f86", BlobIDs: []string{ - "sha256:800c9ce07be36c7f4d1a4876ecfaaa77c1d90b15f43c58eaf52ea27670afcc42", + "sha256:bd0eab2a9df3aa47333bcd9a39e9476127654628b57fb0e767c3736e0da00f86", }, }, }, @@ -892,9 +948,9 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraformplan/snapshots/passed", Type: artifact.TypeFilesystem, - ID: "sha256:3d90bb96d2dc0af277ab0ce28972670eb81968d00775d1e92edce54ae2d165c0", + ID: "sha256:9492a26d265bfd1ac3e1973c2dfe60619eee7bd4dd7af4d7db498c36334eaa87", BlobIDs: []string{ - "sha256:3d90bb96d2dc0af277ab0ce28972670eb81968d00775d1e92edce54ae2d165c0", + "sha256:9492a26d265bfd1ac3e1973c2dfe60619eee7bd4dd7af4d7db498c36334eaa87", }, }, }, @@ -1004,9 +1060,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/cloudformation/single-failure/src", Type: artifact.TypeFilesystem, - ID: "sha256:bd481a673eb07ed7b51e1ff2a6e7aca08b433d11288eb9f5e9aa2d2f482a0c16", + ID: "sha256:7ab98e9e46757e54563a1dc58dddece27612a61815ce84f940512f76aeb5a373", BlobIDs: []string{ - "sha256:bd481a673eb07ed7b51e1ff2a6e7aca08b433d11288eb9f5e9aa2d2f482a0c16", + "sha256:7ab98e9e46757e54563a1dc58dddece27612a61815ce84f940512f76aeb5a373", }, }, }, @@ -1087,9 +1143,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/cloudformation/multiple-failures/src", Type: artifact.TypeFilesystem, - ID: "sha256:c25676d23114b9c912067d45285cd9e662cefae5e3cc82c40f67df5fee39f92a", + ID: "sha256:9ceff8d195a22fbe61e554abebc85aabb07c9495518632a965982f76875b5fc7", BlobIDs: []string{ - "sha256:c25676d23114b9c912067d45285cd9e662cefae5e3cc82c40f67df5fee39f92a", + "sha256:9ceff8d195a22fbe61e554abebc85aabb07c9495518632a965982f76875b5fc7", }, }, }, @@ -1118,9 +1174,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/cloudformation/no-results/src", Type: artifact.TypeFilesystem, - ID: "sha256:522b19ad182f50b7b04217831c914df52c2d2eb1bdddb02eb9cd2b4e14c9a32b", + ID: "sha256:53de80f16641bcf3c9a51544a85d085230307b7cbab9c8dbd27765ed0f1959da", BlobIDs: []string{ - "sha256:522b19ad182f50b7b04217831c914df52c2d2eb1bdddb02eb9cd2b4e14c9a32b", + "sha256:53de80f16641bcf3c9a51544a85d085230307b7cbab9c8dbd27765ed0f1959da", }, }, }, @@ -1175,9 +1231,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/cloudformation/params/code/src", Type: artifact.TypeFilesystem, - ID: "sha256:40d6550292de7518fd7229f7b14803c67cbffbad3376e773ad7e6dc003846e87", + ID: "sha256:5039581be69d80b93de3d98c529d48ff62195df368b1f02bd55e0fcd2ed1b53d", BlobIDs: []string{ - "sha256:40d6550292de7518fd7229f7b14803c67cbffbad3376e773ad7e6dc003846e87", + "sha256:5039581be69d80b93de3d98c529d48ff62195df368b1f02bd55e0fcd2ed1b53d", }, }, }, @@ -1232,9 +1288,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/cloudformation/passed/src", Type: artifact.TypeFilesystem, - ID: "sha256:e2269b8ea44e29aedeaeea83368f879b3fb0cb97bfe46bcca4383a637280cace", + ID: "sha256:bf16efcef601f232244af2a1d7c527917d0f34667794f5289e84a81514af8d17", BlobIDs: []string{ - "sha256:e2269b8ea44e29aedeaeea83368f879b3fb0cb97bfe46bcca4383a637280cace", + "sha256:bf16efcef601f232244af2a1d7c527917d0f34667794f5289e84a81514af8d17", }, }, }, @@ -1319,9 +1375,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/dockerfile/single-failure/src", Type: artifact.TypeFilesystem, - ID: "sha256:3551bddb0f53fb9e0c32390e3ac33f841e3cc15a52ddbcbd9ea07f7e6d1d4437", + ID: "sha256:9659d03cf3140d1aa4a6463442f951e2b9d16a153e41bd5f3d3d4b0aa350f3ca", BlobIDs: []string{ - "sha256:3551bddb0f53fb9e0c32390e3ac33f841e3cc15a52ddbcbd9ea07f7e6d1d4437", + "sha256:9659d03cf3140d1aa4a6463442f951e2b9d16a153e41bd5f3d3d4b0aa350f3ca", }, }, }, @@ -1376,9 +1432,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/dockerfile/multiple-failures/src", Type: artifact.TypeFilesystem, - ID: "sha256:3551bddb0f53fb9e0c32390e3ac33f841e3cc15a52ddbcbd9ea07f7e6d1d4437", + ID: "sha256:9659d03cf3140d1aa4a6463442f951e2b9d16a153e41bd5f3d3d4b0aa350f3ca", BlobIDs: []string{ - "sha256:3551bddb0f53fb9e0c32390e3ac33f841e3cc15a52ddbcbd9ea07f7e6d1d4437", + "sha256:9659d03cf3140d1aa4a6463442f951e2b9d16a153e41bd5f3d3d4b0aa350f3ca", }, }, }, @@ -1406,9 +1462,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/dockerfile/no-results/src", Type: artifact.TypeFilesystem, - ID: "sha256:e57ad1b0be7370a131e1265a25ac8790bbfec2bb5867315916cf92799e5855d3", + ID: "sha256:9d03393551ed1af9bf5e87037b2ced30bf30a0c75161a1ed1d783cd6df5e98c9", BlobIDs: []string{ - "sha256:e57ad1b0be7370a131e1265a25ac8790bbfec2bb5867315916cf92799e5855d3", + "sha256:9d03393551ed1af9bf5e87037b2ced30bf30a0c75161a1ed1d783cd6df5e98c9", }, }, }, @@ -1465,9 +1521,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/dockerfile/passed/src", Type: artifact.TypeFilesystem, - ID: "sha256:ff4a3a7aed57bd8190277cf2cc16213eef43b7a37f26f8458525f2efd9793e8f", + ID: "sha256:63bb406c0b1662d29596fdc357ff9d8051e521620e0c827d4b29ff1efe4df90b", BlobIDs: []string{ - "sha256:ff4a3a7aed57bd8190277cf2cc16213eef43b7a37f26f8458525f2efd9793e8f", + "sha256:63bb406c0b1662d29596fdc357ff9d8051e521620e0c827d4b29ff1efe4df90b", }, }, }, @@ -1557,9 +1613,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/kubernetes/single-failure/src", Type: artifact.TypeFilesystem, - ID: "sha256:63ceedb6582e29ee4184b8b776ee27efe226d07a932461639c05bfbe47bf7efa", + ID: "sha256:5d6175a5c00b82ccfe1457f57ff65c193bf18c9b8ed1adbba95dab1000c9a609", BlobIDs: []string{ - "sha256:63ceedb6582e29ee4184b8b776ee27efe226d07a932461639c05bfbe47bf7efa", + "sha256:5d6175a5c00b82ccfe1457f57ff65c193bf18c9b8ed1adbba95dab1000c9a609", }, }, }, @@ -1642,9 +1698,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/kubernetes/multiple-failures/src", Type: artifact.TypeFilesystem, - ID: "sha256:47fcc85b182385fc6cd7ca08270efff33281ba7717c7a97c7b28a47bef24fae3", + ID: "sha256:6cac5e4862b30e92a8f01f023e38cd0d53d5cf58903674bae7d9da949da01bbc", BlobIDs: []string{ - "sha256:47fcc85b182385fc6cd7ca08270efff33281ba7717c7a97c7b28a47bef24fae3", + "sha256:6cac5e4862b30e92a8f01f023e38cd0d53d5cf58903674bae7d9da949da01bbc", }, }, }, @@ -1672,9 +1728,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/kubernetes/no-results/src", Type: artifact.TypeFilesystem, - ID: "sha256:4aad6cb079f406935fa383e126616cee6c82e326a92c163042d6043596f18e04", + ID: "sha256:8211cd1fe39211df971a124672cd5a3e5bab64d07a8feb30a9f122efd60486d7", BlobIDs: []string{ - "sha256:4aad6cb079f406935fa383e126616cee6c82e326a92c163042d6043596f18e04", + "sha256:8211cd1fe39211df971a124672cd5a3e5bab64d07a8feb30a9f122efd60486d7", }, }, }, @@ -1731,9 +1787,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/kubernetes/passed/src", Type: artifact.TypeFilesystem, - ID: "sha256:b781859c685b32a25e96e54b331957d696cedfc98162146819ac64d3f157660e", + ID: "sha256:eb8ba4a472e0447a2386131dff82f703121ed6e5eb322cad38eaa0826a8c71e4", BlobIDs: []string{ - "sha256:b781859c685b32a25e96e54b331957d696cedfc98162146819ac64d3f157660e", + "sha256:eb8ba4a472e0447a2386131dff82f703121ed6e5eb322cad38eaa0826a8c71e4", }, }, }, @@ -1821,9 +1877,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/azurearm/single-failure/src", Type: artifact.TypeFilesystem, - ID: "sha256:62a167d993f603f5552042e4b3c7ac3a65dbbe62bad28e72631c69c9a8f5e2b5", + ID: "sha256:c2d7f3cdf20d7bb213405b0f51377632c624efb95075e19a6c9b2272859692f7", BlobIDs: []string{ - "sha256:62a167d993f603f5552042e4b3c7ac3a65dbbe62bad28e72631c69c9a8f5e2b5", + "sha256:c2d7f3cdf20d7bb213405b0f51377632c624efb95075e19a6c9b2272859692f7", }, }, }, @@ -1903,9 +1959,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/azurearm/multiple-failures/src", Type: artifact.TypeFilesystem, - ID: "sha256:3cc8c966f10a75dc902589329cf202168176243ef8fdec7219452bb54d02af8e", + ID: "sha256:f96a5b1d9d9e7ccb88c6f1a2faa7b0cfc5d580112f1d3d722bb348e6be635ad3", BlobIDs: []string{ - "sha256:3cc8c966f10a75dc902589329cf202168176243ef8fdec7219452bb54d02af8e", + "sha256:f96a5b1d9d9e7ccb88c6f1a2faa7b0cfc5d580112f1d3d722bb348e6be635ad3", }, }, }, @@ -1933,9 +1989,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/azurearm/no-results/src", Type: artifact.TypeFilesystem, - ID: "sha256:522b19ad182f50b7b04217831c914df52c2d2eb1bdddb02eb9cd2b4e14c9a32b", + ID: "sha256:53de80f16641bcf3c9a51544a85d085230307b7cbab9c8dbd27765ed0f1959da", BlobIDs: []string{ - "sha256:522b19ad182f50b7b04217831c914df52c2d2eb1bdddb02eb9cd2b4e14c9a32b", + "sha256:53de80f16641bcf3c9a51544a85d085230307b7cbab9c8dbd27765ed0f1959da", }, }, }, @@ -1989,9 +2045,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/azurearm/passed/src", Type: artifact.TypeFilesystem, - ID: "sha256:d6a4722cb6865cac6f55c1789d64c57479539e9198722519918764a230586b4b", + ID: "sha256:c7c06b6d7899778b81ebcf9936a758f55df52484cb7078c86f7fe578d999280f", BlobIDs: []string{ - "sha256:d6a4722cb6865cac6f55c1789d64c57479539e9198722519918764a230586b4b", + "sha256:c7c06b6d7899778b81ebcf9936a758f55df52484cb7078c86f7fe578d999280f", }, }, }, diff --git a/pkg/fanal/artifact/local/testdata/my-package-lock.json b/pkg/fanal/artifact/local/testdata/my-package-lock.json new file mode 100644 index 000000000000..2d62c88be722 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/my-package-lock.json @@ -0,0 +1,22 @@ +{ + "name": "app", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "app", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "ms": "^2.1.3" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + } + } +} \ No newline at end of file diff --git a/pkg/fanal/artifact/vm/vm.go b/pkg/fanal/artifact/vm/vm.go index 56f7a0f5fa88..668d6a7386b7 100644 --- a/pkg/fanal/artifact/vm/vm.go +++ b/pkg/fanal/artifact/vm/vm.go @@ -108,6 +108,9 @@ func (a *Storage) Analyze(ctx context.Context, r *io.SectionReader) (types.BlobI } defer composite.Cleanup() + // Files required by file patterns grouped by analyzer types + requiredByFilePatterns := make(map[analyzer.Type][]string) + // TODO: Always walk from the root directory. Consider whether there is a need to be able to set optional err = a.walker.Walk(r, "/", a.artifactOption.WalkerOption, func(filePath string, info os.FileInfo, opener analyzer.Opener) error { path := strings.TrimPrefix(filePath, "/") @@ -116,7 +119,7 @@ func (a *Storage) Analyze(ctx context.Context, r *io.SectionReader) (types.BlobI } // Skip post analysis if the file is not required - analyzerTypes := a.analyzer.RequiredPostAnalyzers(path, info) + analyzerTypes := a.analyzer.RequiredPostAnalyzers(path, info, requiredByFilePatterns) if len(analyzerTypes) == 0 { return nil } @@ -142,7 +145,7 @@ func (a *Storage) Analyze(ctx context.Context, r *io.SectionReader) (types.BlobI } // Post-analysis - if err = a.analyzer.PostAnalyze(ctx, composite, result, opts); err != nil { + if err = a.analyzer.PostAnalyze(ctx, composite, result, opts, requiredByFilePatterns); err != nil { return types.BlobInfo{}, xerrors.Errorf("post analysis error: %w", err) }