From 8d6fc3b6981f2f43408c41905adca121f2864da9 Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Mon, 26 Sep 2022 09:58:49 -0400 Subject: [PATCH] fix: support exclude patterns on Windows Signed-off-by: Keith Zantow --- syft/source/source.go | 5 +++ syft/source/source_test.go | 69 ++++++++++++++++++++++++++++++++++ syft/source/source_win_test.go | 54 ++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 syft/source/source_win_test.go diff --git a/syft/source/source.go b/syft/source/source.go index 2a27d8ae3c0..c2ea7326f83 100644 --- a/syft/source/source.go +++ b/syft/source/source.go @@ -392,6 +392,9 @@ func getDirectoryExclusionFunctions(root string, exclusions []string) ([]pathFil return nil, err } + // this handles Windows file paths by converting them to C:/something/else format + root = filepath.ToSlash(root) + if !strings.HasSuffix(root, "/") { root += "/" } @@ -414,6 +417,8 @@ func getDirectoryExclusionFunctions(root string, exclusions []string) ([]pathFil return []pathFilterFn{ func(path string, _ os.FileInfo) bool { for _, exclusion := range exclusions { + // this is required to handle Windows filepaths + path = filepath.ToSlash(path) matches, err := doublestar.Match(exclusion, path) if err != nil { return false diff --git a/syft/source/source_test.go b/syft/source/source_test.go index b7e960fcb45..e16e608da0c 100644 --- a/syft/source/source_test.go +++ b/syft/source/source_test.go @@ -579,6 +579,75 @@ func TestImageExclusions(t *testing.T) { } } +func Test_crossPlatformExclusions(t *testing.T) { + testCases := []struct { + desc string + root string + path string + exclude string + match bool + }{ + { + desc: "linux doublestar", + root: "/usr", + path: "/usr/var/lib/etc.txt", + exclude: "**/*.txt", + match: true, + }, + { + desc: "linux relative", + root: "/usr/var/lib", + path: "/usr/var/lib/etc.txt", + exclude: "./*.txt", + match: true, + }, + { + desc: "linux one level", + root: "/usr", + path: "/usr/var/lib/etc.txt", + exclude: "*/*.txt", + match: false, + }, + // NOTE: since these tests will run in linux and macOS, the windows paths will be + // considered relative if they do not start with a forward slash and paths with backslashes + // won't be modified by the filepath.ToSlash call, so these are emulating the result of + // filepath.ToSlash usage + { + desc: "windows doublestar", + root: "/C:/User/stuff", + path: "/C:/User/stuff/thing.txt", + exclude: "**/*.txt", + match: true, + }, + { + desc: "windows relative", + root: "/C:/User/stuff", + path: "/C:/User/stuff/thing.txt", + exclude: "./*.txt", + match: true, + }, + { + desc: "windows one level", + root: "/C:/User/stuff", + path: "/C:/User/stuff/thing.txt", + exclude: "*/*.txt", + match: false, + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + fns, err := getDirectoryExclusionFunctions(test.root, []string{test.exclude}) + require.NoError(t, err) + + for _, f := range fns { + result := f(test.path, nil) + require.Equal(t, test.match, result) + } + }) + } +} + // createArchive creates a new archive file at destinationArchivePath based on the directory found at sourceDirPath. func createArchive(t testing.TB, sourceDirPath, destinationArchivePath string) { t.Helper() diff --git a/syft/source/source_win_test.go b/syft/source/source_win_test.go new file mode 100644 index 00000000000..8fd5eb4b700 --- /dev/null +++ b/syft/source/source_win_test.go @@ -0,0 +1,54 @@ +//go:build windows +// +build windows + +package source + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_crossPlatformExclusions(t *testing.T) { + testCases := []struct { + desc string + root string + path string + exclude string + match bool + }{ + { + desc: "windows doublestar", + root: "C:\\User\\stuff", + path: "C:\\User\\stuff\\thing.txt", + exclude: "**/*.txt", + match: true, + }, + { + desc: "windows relative", + root: "C:\\User\\stuff", + path: "C:\\User\\stuff\\thing.txt", + exclude: "./*.txt", + match: true, + }, + { + desc: "windows one level", + root: "C:\\User\\stuff", + path: "C:\\User\\stuff\\thing.txt", + exclude: "*/*.txt", + match: false, + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + fns, err := getDirectoryExclusionFunctions(test.root, []string{test.exclude}) + require.NoError(t, err) + + for _, f := range fns { + result := f(test.path, nil) + require.Equal(t, test.match, result) + } + }) + } +}