Skip to content

Commit

Permalink
feat(flag): Add glob support to --skip-dirs and --skip-files (aqu…
Browse files Browse the repository at this point in the history
  • Loading branch information
simar7 committed Mar 30, 2023
1 parent b40f60c commit abff139
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 3 deletions.
16 changes: 16 additions & 0 deletions docs/docs/vulnerability/examples/others.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ If your image contains lock files which are not maintained by you, you can skip
$ trivy image --skip-files "/Gemfile.lock" --skip-files "/var/lib/gems/2.5.0/gems/http_parser.rb-0.6.0/Gemfile.lock" quay.io/fluentd_elasticsearch/fluentd:v2.9.0
```

It's possible to specify globs as part of the value.

```bash
$ trivy image --skip-files "./testdata/*/bar" .
```

Will skip any file named `bar` in the subdirectories of testdata.

## Skip Directories
Trivy traversals directories and look for all lock files by default.
If your image contains lock files which are not maintained by you, you can skip traversal in the specific directory.
Expand All @@ -16,6 +24,14 @@ If your image contains lock files which are not maintained by you, you can skip
$ trivy image --skip-dirs /var/lib/gems/2.5.0/gems/fluent-plugin-detect-exceptions-0.0.13 --skip-dirs "/var/lib/gems/2.5.0/gems/http_parser.rb-0.6.0" quay.io/fluentd_elasticsearch/fluentd:v2.9.0
```

It's possible to specify globs as part of the value.

```bash
$ trivy image --skip-dirs "./testdata/*" .
```

Will skip all subdirectories of the testdata directory.

## File patterns
When a directory is given as an input, Trivy will recursively look for and test all files based on file patterns.
The default file patterns are [here](../../misconfiguration/custom/index.md).
Expand Down
22 changes: 19 additions & 3 deletions pkg/fanal/walker/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package walker

import (
"os"
"path"
"path/filepath"
"strings"

"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/utils"
"github.com/aquasecurity/trivy/pkg/log"
)

var (
Expand Down Expand Up @@ -53,7 +55,16 @@ func (w *walker) shouldSkipFile(filePath string) bool {
filePath = strings.TrimLeft(filePath, "/")

// skip files
return utils.StringInSlice(filePath, w.skipFiles)
for _, pattern := range w.skipFiles {
match, err := path.Match(pattern, filePath)
if err != nil {
return false // return early if bad pattern
} else if match {
log.Logger.Debugf("Skipping file: %s", filePath)
return true
}
}
return false
}

func (w *walker) shouldSkipDir(dir string) bool {
Expand All @@ -66,8 +77,13 @@ func (w *walker) shouldSkipDir(dir string) bool {
}

// Skip system dirs and specified dirs (absolute path)
if utils.StringInSlice(dir, w.skipDirs) {
return true
for _, pattern := range w.skipDirs {
if match, err := path.Match(pattern, dir); err != nil {
return false // return early if bad pattern
} else if match {
log.Logger.Debugf("Skipping directory: %s", dir)
return true
}
}

return false
Expand Down
109 changes: 109 additions & 0 deletions pkg/fanal/walker/walk_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package walker

import (
"fmt"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_shouldSkipFile(t *testing.T) {
testCases := []struct {
skipFiles []string
skipMap map[string]bool
}{
{
skipFiles: []string{filepath.Join("/etc/*")},
skipMap: map[string]bool{
filepath.Join("/etc/foo"): true,
filepath.Join("/etc/foo/bar"): false,
},
},
{
skipFiles: []string{filepath.Join("/etc/*/*")},
skipMap: map[string]bool{
filepath.Join("/etc/foo"): false,
filepath.Join("/etc/foo/bar"): true,
},
},
{
skipFiles: []string{filepath.Join("/etc/*/*"), filepath.Join("/var/log/*.txt")},
skipMap: map[string]bool{
filepath.Join("/etc/foo"): false,
filepath.Join("/etc/foo/bar"): true,
filepath.Join("/var/log/bar.txt"): true,
},
},
{
skipFiles: []string{filepath.Join(`[^etc`)}, // filepath.Match returns ErrBadPattern
skipMap: map[string]bool{
filepath.Join("/etc/foo"): false,
filepath.Join("/etc/foo/bar"): false,
},
},
}

for i, tc := range testCases {
t.Run(fmt.Sprint(i), func(t *testing.T) {
w := newWalker(tc.skipFiles, nil, false)
for file, skipResult := range tc.skipMap {
assert.Equal(t, skipResult, w.shouldSkipFile(filepath.ToSlash(filepath.Clean(file))), fmt.Sprintf("skipFiles: %s, file: %s", tc.skipFiles, file))
}
})
}
}

func Test_shouldSkipDir(t *testing.T) {
testCases := []struct {
skipDirs []string
skipMap map[string]bool
}{
{
skipDirs: nil,
skipMap: map[string]bool{
".git": true, // AppDir
"proc": true, // SystemDir
"foo.bar": false, // random directory
},
},
{
skipDirs: []string{filepath.Join("/*")},
skipMap: map[string]bool{
filepath.Join("/etc"): true,
filepath.Join("/etc/foo/bar"): false,
},
},
{
skipDirs: []string{filepath.Join("/etc/*/*")},
skipMap: map[string]bool{
filepath.Join("/etc/foo"): false,
filepath.Join("/etc/foo/bar"): true,
},
},
{
skipDirs: []string{filepath.Join("/etc/*/*"), filepath.Join("/var/log/*")},
skipMap: map[string]bool{
filepath.Join("/etc/foo"): false,
filepath.Join("/etc/foo/bar"): true,
filepath.Join("/var/log/bar"): true,
},
},
{
skipDirs: []string{filepath.Join(`[^etc`)}, // filepath.Match returns ErrBadPattern
skipMap: map[string]bool{
filepath.Join("/etc/foo"): false,
filepath.Join("/etc/foo/bar"): false,
},
},
}

for i, tc := range testCases {
t.Run(fmt.Sprint(i), func(t *testing.T) {
w := newWalker(nil, tc.skipDirs, false)
for dir, skipResult := range tc.skipMap {
assert.Equal(t, skipResult, w.shouldSkipDir(filepath.ToSlash(filepath.Clean(dir))), fmt.Sprintf("skipDirs: %s, dir: %s", tc.skipDirs, dir))
}
})
}
}

0 comments on commit abff139

Please sign in to comment.