Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion packageupdaters/commonpackageupdater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ func TestGradleFixVulnerabilityIfExists(t *testing.T) {

gph := GradlePackageUpdater{}

descriptorFiles, err := gph.GetAllDescriptorFilesFullPaths([]string{groovyDescriptorFileSuffix, kotlinDescriptorFileSuffix})
descriptorFiles, err := getAllGradleDescriptorFilesFullPaths()
assert.NoError(t, err)

for _, descriptorFile := range descriptorFiles {
Expand Down Expand Up @@ -595,6 +595,49 @@ func TestGradleIsVersionSupportedForFix(t *testing.T) {
}
}

func TestGetAllGradleDescriptorFilesFullPaths(t *testing.T) {
var testcases = []struct {
testProjectRepo string
expectedResultSuffixes []string
patternsToExclude []string
}{
{
testProjectRepo: "gradle",
expectedResultSuffixes: []string{"build.gradle", filepath.Join("innerProjectForTest", "build.gradle.kts")},
},
{
testProjectRepo: "gradle",
expectedResultSuffixes: []string{"build.gradle"},
patternsToExclude: []string{".*innerProjectForTest.*"},
},
}

currDir, outerErr := os.Getwd()
assert.NoError(t, outerErr)

for _, testcase := range testcases {
tmpDir, err := os.MkdirTemp("", "")
assert.NoError(t, err)
assert.NoError(t, biutils.CopyDir(filepath.Join("..", "testdata", "projects", testcase.testProjectRepo), tmpDir, true, nil))
assert.NoError(t, os.Chdir(tmpDir))

finalDirPath, err := os.Getwd()
assert.NoError(t, err)

var expectedResults []string
for _, suffix := range testcase.expectedResultSuffixes {
expectedResults = append(expectedResults, filepath.Join(finalDirPath, suffix))
}

descriptorFilesFullPaths, err := getAllGradleDescriptorFilesFullPaths(testcase.patternsToExclude...)
assert.NoError(t, err)
assert.ElementsMatch(t, expectedResults, descriptorFilesFullPaths)

assert.NoError(t, os.Chdir(currDir))
assert.NoError(t, fileutils.RemoveTempDir(tmpDir))
}
}

func TestGetAllDescriptorFilesFullPaths(t *testing.T) {
var testcases = []struct {
testProjectRepo string
Expand Down
62 changes: 60 additions & 2 deletions packageupdaters/gradlepackageupdater.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package packageupdaters

import (
"fmt"
"github.com/jfrog/frogbot/v2/utils"
"io/fs"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/jfrog/frogbot/v2/utils"
)

const (
Expand All @@ -22,6 +25,12 @@ var directMapWithVersionRegexp = getMapRegexpEntry("group") + "," + getMapRegexp

var gradleDescriptorsSuffixes = []string{groovyDescriptorFileSuffix, kotlinDescriptorFileSuffix}

// skipDirNamesWhenCollectingGradleDescriptors are directory base names to skip when walking for build.gradle / build.gradle.kts (outputs, tooling, VCS).
var skipDirNamesWhenCollectingGradleDescriptors = map[string]struct{}{
".git": {}, ".gradle": {}, "build": {}, "node_modules": {}, "out": {},
".idea": {}, "dist": {}, "bin": {}, ".vscode": {},
}

func getMapRegexpEntry(mapEntry string) string {
return fmt.Sprintf(directMapRegexpEntry, mapEntry) + apostrophes + "%s" + apostrophes
}
Expand Down Expand Up @@ -54,7 +63,7 @@ func (gph *GradlePackageUpdater) updateDirectDependency(vulnDetails *utils.Vulne
// A gradle project may contain several descriptor files in several sub-modules. Each vulnerability may be found in each of the descriptor files.
// Therefore we iterate over every descriptor file for each vulnerability and try to find and fix it.
var descriptorFilesFullPaths []string
descriptorFilesFullPaths, err = gph.GetAllDescriptorFilesFullPaths(gradleDescriptorsSuffixes)
descriptorFilesFullPaths, err = getAllGradleDescriptorFilesFullPaths()
if err != nil {
return
}
Expand All @@ -76,6 +85,55 @@ func (gph *GradlePackageUpdater) updateDirectDependency(vulnDetails *utils.Vulne
return
}

// getAllGradleDescriptorFilesFullPaths walks the tree from the current directory and collects all build.gradle / build.gradle.kts files (multi-module projects).
func getAllGradleDescriptorFilesFullPaths(patternsToExclude ...string) (descriptorFilesFullPaths []string, err error) {
var regexpPatternsCompilers []*regexp.Regexp
for _, patternToExclude := range patternsToExclude {
regexpPatternsCompilers = append(regexpPatternsCompilers, regexp.MustCompile(patternToExclude))
}

err = filepath.WalkDir(".", func(path string, d fs.DirEntry, innerErr error) error {
if innerErr != nil {
return fmt.Errorf("an error has occurred when attempting to access or traverse the file system: %w", innerErr)
}

if path == "." {
return nil
}

for _, regexpCompiler := range regexpPatternsCompilers {
if regexpCompiler.FindString(path) != "" {
if d.IsDir() {
return filepath.SkipDir
}
return nil
}
}

if d.IsDir() {
if _, skip := skipDirNamesWhenCollectingGradleDescriptors[filepath.Base(path)]; skip {
return filepath.SkipDir
}
return nil
}

for _, suffix := range gradleDescriptorsSuffixes {
if strings.HasSuffix(path, suffix) {
absFilePath, absErr := filepath.Abs(path)
if absErr != nil {
return fmt.Errorf("couldn't retrieve file's absolute path for './%s': %w", path, absErr)
}
descriptorFilesFullPaths = append(descriptorFilesFullPaths, absFilePath)
}
}
return nil
})
if err != nil {
err = fmt.Errorf("failed to get Gradle descriptor files absolute paths: %w", err)
}
return
}

// Checks if the impacted version is currently supported for fix
func isVersionSupportedForFix(impactedVersion string) bool {
if strings.Contains(impactedVersion, "+") ||
Expand Down
Loading