From fe47ad77e2af48bc4a98a76da282051aba5f6d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20L=C3=B3pez=20L=C3=B3pez?= Date: Thu, 16 Jul 2026 09:56:14 +0200 Subject: [PATCH] fix: ignored-parent semantics --- pkg/utils/file_filter.go | 6 ++++++ pkg/utils/file_filter_test.go | 29 +++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/pkg/utils/file_filter.go b/pkg/utils/file_filter.go index daa9ebcfb..0f0cc2649 100644 --- a/pkg/utils/file_filter.go +++ b/pkg/utils/file_filter.go @@ -148,7 +148,12 @@ func (fw *FileFilter) GetFilteredFiles(filesCh chan string, globs []string) chan // buildGlobs iterates a list of ignore filesToFilter and returns a list of glob patterns that can be used to test for ignored filesToFilter func (fw *FileFilter) buildGlobs(ignoreFiles []string) ([]string, error) { var globs = make([]string, 0) + globPatternMatcher := gitignore.CompileIgnoreLines() for _, ignoreFile := range ignoreFiles { + if globPatternMatcher.MatchesPath(ignoreFile) { + continue + } + var content []byte content, err := os.ReadFile(ignoreFile) if err != nil { @@ -162,6 +167,7 @@ func (fw *FileFilter) buildGlobs(ignoreFiles []string) ([]string, error) { parsedRules := parseIgnoreFile(content, filepath.Dir(ignoreFile)) globs = append(globs, parsedRules...) } + globPatternMatcher = gitignore.CompileIgnoreLines(globs...) } return globs, nil diff --git a/pkg/utils/file_filter_test.go b/pkg/utils/file_filter_test.go index 1ecf5baeb..d2183f6a1 100644 --- a/pkg/utils/file_filter_test.go +++ b/pkg/utils/file_filter_test.go @@ -606,6 +606,31 @@ func TestFileFilter_GetFilteredFiles_ignoreRuleScenarios(t *testing.T) { excluded: []string{"root.txt", "pkg/pkg.txt", "pkg/root.txt"}, kept: []string{"pkg/keep.txt"}, }, + { + name: "ignore file below ignored parent cannot reinclude files", + files: map[string]string{ + ".gitignore": "node_modules\n", + "node_modules/pkg/.gitignore": "!index.js\n", + "node_modules/pkg/index.js": "x", + "node_modules/pkg/other.js": "x", + "src/index.js": "x", + }, + ruleFiles: []string{".gitignore"}, + excluded: []string{"node_modules/pkg/index.js", "node_modules/pkg/other.js"}, + kept: []string{"src/index.js"}, + }, + { + name: "gitignore below snyk-excluded parent cannot reinclude files", + files: map[string]string{ + ".snyk": "version: v1.25.1\nexclude:\n global:\n - node_modules\n", + "node_modules/pkg/.gitignore": "!index.js\n", + "node_modules/pkg/index.js": "x", + "src/index.js": "x", + }, + ruleFiles: []string{".gitignore", ".snyk"}, + excluded: []string{"node_modules/pkg/index.js"}, + kept: []string{"src/index.js"}, + }, // --- C2. Special characters in the ignore rule pattern itself --- // git treats parentheses/spaces in a gitignore pattern as literal (fnmatch), so a folder @@ -992,7 +1017,7 @@ func testCases(t *testing.T) []fileFilterTestCase { "a/.gitignore": "!*.txt", }, filesToFilter: []string{"a/file2.js"}, - expectedFiles: []string{"file1.js", "a/file1.txt", ".gitignore", "a/.gitignore"}, + expectedFiles: []string{"file1.js", ".gitignore", "a/.gitignore"}, }, { name: "Supports .dcignore rule file", @@ -1003,7 +1028,7 @@ func testCases(t *testing.T) []fileFilterTestCase { "a/.dcignore": "!*.txt", }, filesToFilter: []string{"a/file2.js"}, - expectedFiles: []string{"file1.js", "a/file1.txt", ".dcignore", "a/.dcignore"}, + expectedFiles: []string{"file1.js", ".dcignore", "a/.dcignore"}, }, { name: "Supports .snyk style exclude rules",