diff --git a/pkg/action/action.go b/pkg/action/action.go deleted file mode 100644 index 97754b37b..000000000 --- a/pkg/action/action.go +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2024 Chainguard, Inc. -// SPDX-License-Identifier: Apache-2.0 - -package action diff --git a/pkg/action/diff.go b/pkg/action/diff.go index 01c42c424..10abd3db9 100644 --- a/pkg/action/diff.go +++ b/pkg/action/diff.go @@ -33,8 +33,7 @@ type ScanResult struct { // displayPath mimics diff(1) output for relative paths. func displayPath(base, path string) string { if filepath.IsAbs(path) { - rel, err := filepath.Rel(base, path) - if err == nil { + if rel, err := filepath.Rel(base, path); err == nil { return rel } } @@ -43,9 +42,11 @@ func displayPath(base, path string) string { // relPath returns the cleanest possible relative path between a source path and files within said path. func relPath(from string, fr *malcontent.FileReport, isArchive bool, isImage bool) (string, string, error) { - var base string - var err error - var rel string + var ( + base, rel string + err error + ) + switch { case isArchive: fromRoot := fr.ArchiveRoot @@ -136,10 +137,16 @@ func relFileReport(ctx context.Context, c malcontent.Config, fromPath string, is } fromRelPath := map[string]*malcontent.FileReport{} - var base string - var rangeErr error + + var ( + base string + rangeErr error + ) fromReport.Files.Range(func(key, value any) bool { + if ctx.Err() != nil { + return false + } if key == nil || value == nil { return true } @@ -171,9 +178,6 @@ func relFileReport(ctx context.Context, c malcontent.Config, fromPath string, is // scoreFile returns a boolean to determine how individual files are stored in a diff report. func scoreFile(fr, tr *malcontent.FileReport) bool { - scoreSrc := false - scoreDest := false - patterns := []string{ `^[\w.-]+\.so$`, `^.+-.*-r\d+\.spdx\.json$`, @@ -181,19 +185,14 @@ func scoreFile(fr, tr *malcontent.FileReport) bool { for _, pattern := range patterns { re := regexp.MustCompile(pattern) - if re.MatchString(fr.Path) { - scoreSrc = true - } - if re.MatchString(tr.Path) { - scoreDest = true + + // If both files match patterns, return true to indicate that `inferMoves` should be used + // Otherwise, indicate that `handleFile` should be used + if re.MatchString(fr.Path) && re.MatchString(tr.Path) { + return true } } - // If both files match patterns, reeturn true to indicate that `inferMoves` should be used - // Otherwise, indicate that `handleFile` should be used - if scoreSrc && scoreDest { - return true - } return false } @@ -206,13 +205,15 @@ func Diff(ctx context.Context, c malcontent.Config, _ *clog.Logger) (*malcontent return nil, fmt.Errorf("diff mode requires 2 paths, you passed in %d path(s)", len(c.ScanPaths)) } - srcPath := c.ScanPaths[0] - destPath := c.ScanPaths[1] + srcPath, destPath := c.ScanPaths[0], c.ScanPaths[1] // If diffing images, use their temporary directories as scan paths // Flip c.OCI to false when finished to block other image code paths - var isImage bool - var err error + var ( + err error + isImage bool + ) + if c.OCI { srcPath, err = archive.OCI(ctx, srcPath) if err != nil { @@ -222,24 +223,20 @@ func Diff(ctx context.Context, c malcontent.Config, _ *clog.Logger) (*malcontent if err != nil { return nil, fmt.Errorf("failed to prepare scan path: %w", err) } - isImage = true - c.OCI = false + isImage, c.OCI = true, false } var g errgroup.Group - srcCh := make(chan ScanResult, 1) - destCh := make(chan ScanResult, 1) + srcCh, destCh := make(chan ScanResult, 1), make(chan ScanResult, 1) - srcIsArchive := programkind.IsSupportedArchive(srcPath) - destIsArchive := programkind.IsSupportedArchive(destPath) + srcIsArchive, destIsArchive := programkind.IsSupportedArchive(srcPath), programkind.IsSupportedArchive(destPath) g.Go(func() error { files, base, err := relFileReport(ctx, c, srcPath, isImage) res := ScanResult{files: files, base: base, err: err} if isImage { - res.imageURI = c.ScanPaths[0] - res.tmpRoot = srcPath + res.imageURI, res.tmpRoot = c.ScanPaths[0], srcPath } srcCh <- res return err @@ -249,8 +246,7 @@ func Diff(ctx context.Context, c malcontent.Config, _ *clog.Logger) (*malcontent files, base, err := relFileReport(ctx, c, destPath, isImage) res := ScanResult{files: files, base: base, err: err} if isImage { - res.imageURI = c.ScanPaths[1] - res.tmpRoot = destPath + res.imageURI, res.tmpRoot = c.ScanPaths[1], destPath } destCh <- res return err @@ -293,7 +289,9 @@ func Diff(ctx context.Context, c malcontent.Config, _ *clog.Logger) (*malcontent // and employ add/delete for files that are not the same // When scanning two files, do a 1:1 comparison and // consider the source -> destination as a change rather than an add/delete - if ((srcInfo.IsDir() && destInfo.IsDir()) || (srcIsArchive && destIsArchive)) || isImage { + shouldHandleDir := ((srcInfo.IsDir() && destInfo.IsDir()) || (srcIsArchive && destIsArchive)) || isImage + + if shouldHandleDir { handleDir(ctx, c, srcResult, destResult, d, isImage) } else { var srcFile, destFile *malcontent.FileReport @@ -330,8 +328,7 @@ func handleDir(ctx context.Context, c malcontent.Config, src, dest ScanResult, d return } - srcFiles := make(map[string]*malcontent.FileReport) - destFiles := make(map[string]*malcontent.FileReport) + srcFiles, destFiles := make(map[string]*malcontent.FileReport), make(map[string]*malcontent.FileReport) for path, fr := range src.files { base := filepath.Base(path) diff --git a/pkg/action/scan.go b/pkg/action/scan.go index 6ab40446c..990d370f4 100644 --- a/pkg/action/scan.go +++ b/pkg/action/scan.go @@ -502,6 +502,8 @@ func setupMatchHandler(ctx context.Context, matchChan chan matchResult, c malcon go func() { select { + case <-ctx.Done(): + return case match := <-matchChan: if match.fr != nil && c.Renderer != nil && match.fr.RiskScore >= c.MinFileRisk { if err := c.Renderer.File(ctx, match.fr); err != nil { @@ -509,8 +511,6 @@ func setupMatchHandler(ctx context.Context, matchChan chan matchResult, c malcon } } cancel() - case <-ctx.Done(): - return } }() } @@ -545,6 +545,10 @@ func handleArchiveFile(ctx context.Context, path string, c malcontent.Config, r } } + if frs == nil { + return nil + } + if !c.OCI && (c.ExitFirstHit || c.ExitFirstMiss) { match, err := exitIfHitOrMiss(frs, path, c.ExitFirstHit, c.ExitFirstMiss) if err != nil { @@ -555,31 +559,30 @@ func handleArchiveFile(ctx context.Context, path string, c malcontent.Config, r } } - //nolint:nestif // ignore complexity of 14 - if frs != nil { - frs.Range(func(key, value any) bool { - if ctx.Err() != nil { - return false - } - if key == nil || value == nil { - return true - } - if k, ok := key.(string); ok { - if fr, ok := value.(*malcontent.FileReport); ok { - if len(c.TrimPrefixes) > 0 { - k = report.TrimPrefixes(k, c.TrimPrefixes) - } - r.Files.Store(k, fr) - if c.Renderer != nil && r.Diff == nil && fr.RiskScore >= c.MinFileRisk { - if err := c.Renderer.File(ctx, fr); err != nil { - logger.Errorf("render error: %v", err) - } + //nolint:nestif // ignore complexity of 13 + frs.Range(func(key, value any) bool { + if ctx.Err() != nil { + return false + } + if key == nil || value == nil { + return true + } + if k, ok := key.(string); ok { + if fr, ok := value.(*malcontent.FileReport); ok { + if len(c.TrimPrefixes) > 0 { + k = report.TrimPrefixes(k, c.TrimPrefixes) + } + r.Files.Store(k, fr) + if c.Renderer != nil && r.Diff == nil && fr.RiskScore >= c.MinFileRisk { + if err := c.Renderer.File(ctx, fr); err != nil { + logger.Errorf("render error: %v", err) } } } - return true - }) - } + } + return true + }) + return nil } @@ -783,23 +786,25 @@ func Scan(ctx context.Context, c malcontent.Config) (*malcontent.Report, error) if err != nil && !interactive(c) { return r, err } + if r == nil { + return nil, nil + } - if r != nil { - r.Files.Range(func(key, value any) bool { - if scanCtx.Err() != nil { - return false - } - if key == nil || value == nil { - return true - } - if fr, ok := value.(*malcontent.FileReport); ok { - if fr.RiskScore < c.MinFileRisk { - r.Files.Delete(key) - } - } + r.Files.Range(func(key, value any) bool { + if scanCtx.Err() != nil { + return false + } + if key == nil || value == nil { return true - }) - } + } + if fr, ok := value.(*malcontent.FileReport); ok { + if fr.RiskScore < c.MinFileRisk { + r.Files.Delete(key) + } + } + return true + }) + if scanCtx.Err() == nil && c.Stats && c.Renderer.Name() != "JSON" && c.Renderer.Name() != "YAML" { err = render.Statistics(&c, r) if err != nil { diff --git a/pkg/refresh/refresh.go b/pkg/refresh/refresh.go index 217fcb698..351845aae 100644 --- a/pkg/refresh/refresh.go +++ b/pkg/refresh/refresh.go @@ -38,7 +38,7 @@ type TestData struct { func discoverTestData(rc Config) (map[string]string, error) { testFiles := make(map[string]string) - err := filepath.Walk(rc.TestDataPath, func(path string, info fs.FileInfo, err error) error { + err := filepath.WalkDir(rc.TestDataPath, func(path string, info os.DirEntry, err error) error { if err != nil { return err }