diff --git a/pkg/analysis/passes/gomanifest/gomanifest.go b/pkg/analysis/passes/gomanifest/gomanifest.go index 99cf1cea..3ae2bfd8 100644 --- a/pkg/analysis/passes/gomanifest/gomanifest.go +++ b/pkg/analysis/passes/gomanifest/gomanifest.go @@ -9,7 +9,6 @@ import ( "fmt" "os" "path/filepath" - "slices" "strings" "github.com/bmatcuk/doublestar/v4" @@ -73,6 +72,11 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } + goFiles, err = filterPluginGoFiles(sourceCodeDir, goFiles) + if err != nil { + return nil, err + } + if len(goFiles) == 0 { // no go files found so we can't check the manifest return nil, nil @@ -159,9 +163,8 @@ func parseManifestFile(file string) (map[string]string, error) { } sha256sum := strings.TrimSpace(parsedLine[0]) fileName := normalizeFileName(strings.TrimSpace(parsedLine[1])) - // skip known non-backend files that some published plugins - // include in their manifest - if slices.Contains(ignoredManifestFiles, fileName) { + // skip non-plugin files that may exist in dependency folders + if isNodeModulesPath(fileName) { continue } // format the manifest fileName:sha256sum @@ -175,18 +178,37 @@ func parseManifestFile(file string) (map[string]string, error) { return manifest, nil } -// ignoredManifestFiles lists specific files that should be ignored when -// validating the manifest. These are files that some published plugins -// include in their manifest but are not part of the backend source code. -var ignoredManifestFiles = []string{ - "node_modules/flatted/golang/pkg/flatted/flatted.go", -} - func normalizeFileName(fileName string) string { // takes a filename that might have windows or linux separators and converts them to a linux separator return strings.Replace(fileName, "\\", "/", -1) } +func isNodeModulesPath(fileName string) bool { + normalized := normalizeFileName(fileName) + return normalized == "node_modules" || + strings.HasPrefix(normalized, "node_modules/") || + strings.Contains(normalized, "/node_modules/") +} + +func filterPluginGoFiles(sourceCodeDir string, goFiles []string) ([]string, error) { + filteredGoFiles := make([]string, 0, len(goFiles)) + + for _, goFilePath := range goFiles { + goFileRelativePath, err := filepath.Rel(sourceCodeDir, goFilePath) + if err != nil { + return nil, err + } + + if isNodeModulesPath(goFileRelativePath) { + continue + } + + filteredGoFiles = append(filteredGoFiles, goFilePath) + } + + return filteredGoFiles, nil +} + func verifyManifest( manifest map[string]string, goFiles []string, diff --git a/pkg/analysis/passes/gomanifest/gomanifest_test.go b/pkg/analysis/passes/gomanifest/gomanifest_test.go index 93d9f967..9d9f4e9c 100644 --- a/pkg/analysis/passes/gomanifest/gomanifest_test.go +++ b/pkg/analysis/passes/gomanifest/gomanifest_test.go @@ -218,3 +218,41 @@ func TestWindowsLineEndingsManifest(t *testing.T) { prettyprint.Print(interceptor.Diagnostics) require.Len(t, interceptor.Diagnostics, 0) } + +func TestIsNodeModulesPath(t *testing.T) { + testCases := []struct { + name string + path string + expected bool + }{ + {name: "exact node_modules", path: "node_modules", expected: true}, + {name: "root node_modules child", path: "node_modules/flatted/main.go", expected: true}, + {name: "nested node_modules child", path: "src/node_modules/flatted/main.go", expected: true}, + {name: "windows separators", path: `src\\node_modules\\flatted\\main.go`, expected: true}, + {name: "similar but different directory name", path: "node_modules2/flatted/main.go", expected: false}, + {name: "regular source path", path: "pkg/main.go", expected: false}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + require.Equal(t, tc.expected, isNodeModulesPath(tc.path)) + }) + } +} + +func TestFilterPluginGoFiles(t *testing.T) { + sourceCodeDir := filepath.Join("repo", "plugin") + goFiles := []string{ + filepath.Join(sourceCodeDir, "pkg", "main.go"), + filepath.Join(sourceCodeDir, "pkg", "subdir", "worker.go"), + filepath.Join(sourceCodeDir, "node_modules", "flatted", "main.go"), + filepath.Join(sourceCodeDir, "src", "node_modules", "dep", "dep.go"), + } + + filtered, err := filterPluginGoFiles(sourceCodeDir, goFiles) + require.NoError(t, err) + require.Equal(t, []string{ + filepath.Join(sourceCodeDir, "pkg", "main.go"), + filepath.Join(sourceCodeDir, "pkg", "subdir", "worker.go"), + }, filtered) +}