Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use gradle-dep-tree with Audit #719

Merged
merged 82 commits into from
Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
5e8666c
first commit
omerzi Jan 15, 2023
dcf13c2
Merge remote-tracking branch 'upstream/dev' into frogbot-air-gapped
omerzi Jan 30, 2023
bd8e06a
Merge remote-tracking branch 'upstream/dev' into frogbot-air-gapped
omerzi Feb 6, 2023
1094d3a
Improve deps resolution and refactor audit
omerzi Feb 13, 2023
61420fc
refactor params
omerzi Feb 13, 2023
e48a6ea
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 13, 2023
b03f72f
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 13, 2023
9b843f0
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 13, 2023
79ddaea
Merge remote-tracking branch 'upstream/dev' into frogbot-air-gapped
omerzi Feb 13, 2023
1f883b0
fix tests
omerzi Feb 14, 2023
e122083
Fix tests
omerzi Feb 14, 2023
521e18c
fix tests
omerzi Feb 14, 2023
f3f51fe
Fix and Add tests
omerzi Feb 14, 2023
463bf9c
Fix and Add tests
omerzi Feb 14, 2023
26b9cca
Fix and Add tests
omerzi Feb 14, 2023
b34056d
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 15, 2023
7fa5aa8
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 15, 2023
35a1085
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 15, 2023
c69113b
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 15, 2023
d8323be
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 16, 2023
0b71e27
Merge remote-tracking branch 'upstream/dev' into frogbot-air-gapped
omerzi Feb 19, 2023
3de544a
update branch
omerzi Feb 19, 2023
53cd452
update branch
omerzi Feb 19, 2023
5b25c03
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 19, 2023
84a5374
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 19, 2023
7842d2c
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 19, 2023
a6d5355
Merge remote-tracking branch 'upstream/dev' into frogbot-air-gapped
omerzi Feb 19, 2023
add2688
fix gradle wrapper issue
omerzi Feb 20, 2023
5bdf581
fix race condition in GetConfigList
omerzi Feb 20, 2023
6971635
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 22, 2023
2c74c54
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 22, 2023
c6fe5d6
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 22, 2023
7a2540a
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 22, 2023
8966da4
Merge remote-tracking branch 'origin/frogbot-air-gapped' into frogbot…
omerzi Feb 22, 2023
3d68d3c
Merge remote-tracking branch 'upstream/dev' into frogbot-air-gapped
omerzi Feb 27, 2023
537dc87
CR Changes
omerzi Feb 27, 2023
d683efc
CR Changes
omerzi Feb 27, 2023
d469e3f
fix tests
omerzi Feb 27, 2023
7f85953
Merge branch 'frogbot-air-gapped' into audit-with-gradledeptree
omerzi Feb 28, 2023
dc7a8ce
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Mar 2, 2023
e58cc38
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Mar 15, 2023
527d8a4
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Mar 19, 2023
8bd583b
Use gradle-dep-tree in Audit
omerzi Mar 23, 2023
fb91ce1
Fix tests
omerzi Mar 23, 2023
10da050
Fix tests
omerzi Mar 23, 2023
0b7d7b9
Fix tests
omerzi Mar 23, 2023
c53e3cc
map refactor
omerzi Mar 26, 2023
ff2dd28
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Mar 26, 2023
fd34972
"Flatten" the graph
omerzi Mar 26, 2023
5359f39
Fix tests
omerzi Mar 27, 2023
6c452c8
improvements
omerzi Mar 27, 2023
0dd7ef9
Revert "map refactor"
omerzi Mar 27, 2023
d2141b8
Revert
omerzi Mar 27, 2023
85d330d
flatten graph
omerzi Mar 29, 2023
6993b1c
flatten graph
omerzi Mar 29, 2023
1a65095
remove flatten from gradle
omerzi Mar 30, 2023
7ebde1a
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Mar 30, 2023
4a55a71
Fix tests
omerzi Mar 30, 2023
a2fa589
Improvements
omerzi Apr 3, 2023
a6ac3bd
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 3, 2023
c9f48fa
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 3, 2023
3b55c33
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 3, 2023
4a80a2b
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 3, 2023
1e5a5d3
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 3, 2023
878097c
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 3, 2023
5a42af9
debug logs
omerzi Apr 3, 2023
169483f
Fix tests
omerzi Apr 3, 2023
72b51ca
Fix tests
omerzi Apr 3, 2023
91f4b41
add SetReleaseRepo
omerzi Apr 3, 2023
317b1cd
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 3, 2023
7ca8a53
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 4, 2023
6eb6755
CR Changes
omerzi Apr 4, 2023
819972f
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 4, 2023
dc02e04
Fix tests
omerzi Apr 4, 2023
6bb387f
More CR Changes
omerzi Apr 4, 2023
53393b9
fix tests
omerzi Apr 4, 2023
40e151e
fix tests
omerzi Apr 4, 2023
acd05da
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 4, 2023
581f4af
fix tests
omerzi Apr 4, 2023
ce76a26
fix tests
omerzi Apr 4, 2023
80e58af
Merge remote-tracking branch 'upstream/dev' into audit-with-gradledep…
omerzi Apr 5, 2023
3719829
CR Changes
omerzi Apr 5, 2023
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
2 changes: 1 addition & 1 deletion artifactory/commands/gradle/gradle.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (gc *GradleCommand) SetServerDetails(serverDetails *config.ServerDetails) *

func (gc *GradleCommand) init() (vConfig *viper.Viper, err error) {
// Read config
vConfig, err = utils.ReadGradleConfig(gc.configPath, nil)
vConfig, err = utils.ReadConfigFile(gc.configPath, utils.YAML)
if err != nil {
return
}
Expand Down
9 changes: 0 additions & 9 deletions artifactory/utils/buildinfoproperties.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,6 @@ func ReadConfigFile(configPath string, configType ConfigType) (config *viper.Vip
return config, errorutils.CheckError(err)
}

func ReadGradleConfig(path string, gradleConfigParams map[string]any) (config *viper.Viper, err error) {
if path == "" {
config = createDefaultConfigWithParams(YAML, Gradle.String(), gradleConfigParams)
} else {
config, err = ReadConfigFile(path, YAML)
}
return
}

func ReadMavenConfig(path string, mvnProps map[string]any) (config *viper.Viper, err error) {
if path == "" {
config = createDefaultConfigWithParams(YAML, Maven.String(), mvnProps)
Expand Down
2 changes: 1 addition & 1 deletion utils/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ type MissionControlDetails struct {
}

func (serverDetails *ServerDetails) IsEmpty() bool {
return len(serverDetails.ServerId) == 0
return len(serverDetails.ServerId) == 0 && serverDetails.Url == ""
}

func (serverDetails *ServerDetails) SetUser(username string) {
Expand Down
4 changes: 2 additions & 2 deletions utils/coreutils/techutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ var technologiesData = map[Technology]TechData{
execCommand: "mvn",
},
Gradle: {
indicators: []string{".gradle"},
indicators: []string{".gradle", ".gradle.kts"},
ciSetupSupport: true,
packageDescriptor: "build.gradle",
packageDescriptor: "build.gradle, build.gradle.kts",
},
Npm: {
indicators: []string{"package.json", "package-lock.json", "npm-shrinkwrap.json"},
Expand Down
3 changes: 2 additions & 1 deletion utils/mvn/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
"github.com/spf13/viper"
)

func RunMvn(vConfig *viper.Viper, buildArtifactsDetailsFile string, buildConf *utils.BuildConfiguration, goals []string, threads int, insecureTls, disableDeploy bool) error {
func RunMvn(vConfig *viper.Viper, buildArtifactsDetailsFile string, buildConf *utils.BuildConfiguration,
goals []string, threads int, insecureTls, disableDeploy bool) error {
buildInfoService := utils.CreateBuildInfoService()
buildName, err := buildConf.GetBuildName()
if err != nil {
Expand Down
267 changes: 233 additions & 34 deletions xray/audit/java/gradle.go
Original file line number Diff line number Diff line change
@@ -1,70 +1,269 @@
package java

import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/jfrog/build-info-go/build"
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
gradleutils "github.com/jfrog/jfrog-cli-core/v2/utils/gradle"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
"github.com/jfrog/jfrog-client-go/utils/log"
"github.com/jfrog/jfrog-client-go/xray/services"
"os"
"os/exec"
"path/filepath"
"strings"
)

const gradlew = "gradlew"
const (
remoteDepTreePath = "artifactory/oss-releases"
gradlew = "gradlew"
depTreeInitFile = "gradledeptree.init"
depTreeOutputFile = "gradledeptree.out"
depTreeInitScript = `initscript {
repositories { %s
mavenCentral()
}
dependencies {
classpath 'com.jfrog:gradle-dep-tree:2.2.0'
}
}

allprojects {
repositories { %s
}
apply plugin: com.jfrog.GradleDepTree
}`
artifactoryRepository = `
maven {
url "%s/%s"
credentials {
username = '%s'
password = '%s'
}
}`
)

type depTreeManager struct {
dependenciesTree
server *config.ServerDetails
releasesRepo string
depsRepo string
useWrapper bool
}

// dependenciesTree represents a map between dependencies to their children dependencies in multiple projects.
type dependenciesTree struct {
tree map[string][]dependenciesPaths
}

// dependenciesPaths represents a map between dependencies to their children dependencies in a single project.
type dependenciesPaths struct {
Paths map[string]dependenciesPaths `json:"children"`
}

// The gradle-dep-tree generates a JSON representation for the dependencies for each gradle build file in the project.
// parseDepTreeFiles iterates over those JSONs, and append them to the map of dependencies in dependenciesTree struct.
func (dtp *depTreeManager) parseDepTreeFiles(jsonFiles []byte) error {
outputFiles := strings.Split(strings.TrimSpace(string(jsonFiles)), "\n")
for _, path := range outputFiles {
tree, err := os.ReadFile(strings.TrimSpace(path))
if err != nil {
return errorutils.CheckError(err)
}

encodedFileName := path[strings.LastIndex(path, string(os.PathSeparator))+1:]
decodedFileName, err := base64.StdEncoding.DecodeString(encodedFileName)
if err != nil {
return errorutils.CheckError(err)
}

if err = dtp.appendDependenciesPaths(tree, string(decodedFileName)); err != nil {
return errorutils.CheckError(err)
}
}
return nil
}

func buildGradleDependencyTree(excludeTestDeps, useWrapper, ignoreConfigFile bool, gradleConfigParams map[string]any) (dependencyTree []*services.GraphNode, err error) {
buildConfiguration, cleanBuild := createBuildConfiguration("audit-gradle")
func (dtp *depTreeManager) appendDependenciesPaths(jsonDepTree []byte, fileName string) error {
var deps dependenciesPaths
if err := json.Unmarshal(jsonDepTree, &deps); err != nil {
return errorutils.CheckError(err)
}
if dtp.tree == nil {
dtp.tree = make(map[string][]dependenciesPaths)
}
dtp.tree[fileName] = append(dtp.tree[fileName], deps)
return nil
}

func buildGradleDependencyTree(useWrapper bool, server *config.ServerDetails, depsRepo, releasesRepo string) (dependencyTree []*services.GraphNode, err error) {
if (server != nil && server.IsEmpty()) || depsRepo == "" {
depsRepo, server, err = getGradleConfig()
if err != nil {
return
}
}

manager := &depTreeManager{
server: server,
releasesRepo: releasesRepo,
depsRepo: depsRepo,
useWrapper: useWrapper,
}

outputFileContent, err := manager.runGradleDepTree()
if err != nil {
return nil, err
}
return manager.getGraphFromDepTree(outputFileContent)
}

func (dtp *depTreeManager) runGradleDepTree() (outputFileContent []byte, err error) {
// Create the script file in the repository
depTreeDir, err := dtp.createDepTreeScript()
if err != nil {
return
}
defer func() {
e := cleanBuild()
e := fileutils.RemoveTempDir(depTreeDir)
if err == nil {
err = e
}
}()

err = runGradle(buildConfiguration, excludeTestDeps, useWrapper, ignoreConfigFile, gradleConfigParams)
if dtp.useWrapper {
dtp.useWrapper, err = isGradleWrapperExist()
if err != nil {
return
}
}

return dtp.execGradleDepTree(depTreeDir)
}

func (dtp *depTreeManager) createDepTreeScript() (tmpDir string, err error) {
tmpDir, err = fileutils.CreateTempDir()
if err != nil {
return
}
depsRepo := ""
releasesRepo := ""
if dtp.server != nil {
releasesRepo, err = getDepTreeArtifactoryRepository(fmt.Sprintf("%s/%s", dtp.releasesRepo, remoteDepTreePath), dtp.server)
if err != nil {
return
}
depsRepo, err = getDepTreeArtifactoryRepository(dtp.depsRepo, dtp.server)
if err != nil {
return
}
}
depTreeInitScript := fmt.Sprintf(depTreeInitScript, releasesRepo, depsRepo)
return tmpDir, errorutils.CheckError(os.WriteFile(filepath.Join(tmpDir, depTreeInitFile), []byte(depTreeInitScript), 0666))
}

func (dtp *depTreeManager) execGradleDepTree(depTreeDir string) (outputFileContent []byte, err error) {
gradleExecPath, err := build.GetGradleExecPath(dtp.useWrapper)
if err != nil {
err = errorutils.CheckError(err)
return
}

dependencyTree, err = createGavDependencyTree(buildConfiguration)
outputFilePath := filepath.Join(depTreeDir, depTreeOutputFile)
tasks := []string{
"clean",
"generateDepTrees", "-I", filepath.Join(depTreeDir, depTreeInitFile),
"-q",
fmt.Sprintf("-Dcom.jfrog.depsTreeOutputFile=%s", outputFilePath),
"-Dcom.jfrog.includeAllBuildFiles=true"}
log.Info("Running gradle dep tree command: ", gradleExecPath, tasks)
if output, err := exec.Command(gradleExecPath, tasks...).CombinedOutput(); err != nil {
return nil, errorutils.CheckErrorf("error running gradle-dep-tree: %s\n%s", err.Error(), string(output))
}
defer func() {
e := errorutils.CheckError(os.Remove(outputFilePath))
if err == nil {
err = e
}
}()

outputFileContent, err = os.ReadFile(outputFilePath)
err = errorutils.CheckError(err)
return
}

func runGradle(buildConfiguration *utils.BuildConfiguration, excludeTestDeps, useWrapper, ignoreConfigFile bool, gradleConfigParams map[string]any) (err error) {
tasks := "clean compileJava "
if !excludeTestDeps {
tasks += "compileTestJava "
}
tasks += "artifactoryPublish"
log.Debug(fmt.Sprintf("gradle command tasks: %v", tasks))
configFilePath := ""
if !ignoreConfigFile {
var exists bool
configFilePath, exists, err = utils.GetProjectConfFilePath(utils.Gradle)
if err != nil {
return
// Assuming we ran gradle-dep-tree, getGraphFromDepTree receives the content of the depTreeOutputFile as input
func (dtp *depTreeManager) getGraphFromDepTree(outputFileContent []byte) ([]*services.GraphNode, error) {
if err := dtp.parseDepTreeFiles(outputFileContent); err != nil {
return nil, err
}
var depsGraph []*services.GraphNode
for dependency, children := range dtp.tree {
directDependency := &services.GraphNode{
Id: GavPackageTypeIdentifier + dependency,
Nodes: []*services.GraphNode{},
}
if exists {
log.Debug("Using resolver config from", configFilePath)
for _, childPath := range children {
populateGradleDependencyTree(directDependency, childPath)
}
depsGraph = append(depsGraph, directDependency)
}
// Check whether gradle wrapper exists
if useWrapper {
useWrapper, err = isGradleWrapperExist()
if err != nil {
return
return depsGraph, nil
}

func populateGradleDependencyTree(currNode *services.GraphNode, currNodeChildren dependenciesPaths) {
for gav, children := range currNodeChildren.Paths {
childNode := &services.GraphNode{
Id: GavPackageTypeIdentifier + gav,
Nodes: []*services.GraphNode{},
Parent: currNode,
}
if gradleConfigParams == nil {
gradleConfigParams = make(map[string]any)
if currNode.NodeHasLoop() {
return
}
gradleConfigParams["usewrapper"] = useWrapper
populateGradleDependencyTree(childNode, children)
currNode.Nodes = append(currNode.Nodes, childNode)
}
}

func getDepTreeArtifactoryRepository(remoteRepo string, server *config.ServerDetails) (string, error) {
pass := server.Password
user := server.User
if server.AccessToken != "" {
pass = server.AccessToken
}
// Read config
vConfig, err := utils.ReadGradleConfig(configFilePath, gradleConfigParams)
if pass == "" && user == "" {
return "", fmt.Errorf("either username/password or access token must be set for %s", server.Url)
}
return fmt.Sprintf(artifactoryRepository,
strings.TrimSuffix(server.ArtifactoryUrl, "/"),
remoteRepo,
user,
pass), nil
}

// getGradleConfig the remote repository and server details defined in the .jfrog/projects/gradle.yaml file, if configured.
func getGradleConfig() (string, *config.ServerDetails, error) {
omerzi marked this conversation as resolved.
Show resolved Hide resolved
var exists bool
configFilePath, exists, err := utils.GetProjectConfFilePath(utils.Gradle)
if err != nil || !exists {
return "", nil, err
}
log.Debug("Using resolver config from", configFilePath)
configContent, err := utils.ReadConfigFile(configFilePath, utils.YAML)
if err != nil {
return err
return "", nil, err
}
var repository string
if configContent.IsSet("resolver.repo") {
repository = configContent.Get("resolver.repo").(string)
}
return gradleutils.RunGradle(vConfig, tasks, "", buildConfiguration, 0, true)
server, err := utils.GetServerDetails(configContent)
return repository, server, err
}

// This function assumes that the Gradle wrapper is in the root directory.
Expand Down
Loading