diff --git a/action/node_modules/.package-lock.json b/action/node_modules/.package-lock.json index d5a139759..b61afb6da 100644 --- a/action/node_modules/.package-lock.json +++ b/action/node_modules/.package-lock.json @@ -1,7 +1,7 @@ { "name": "@jfrog/frogbot", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "node_modules/@actions/core": { diff --git a/packagehandlers/commonpackagehandler.go b/packagehandlers/commonpackagehandler.go index 7d9129616..b30e39237 100644 --- a/packagehandlers/commonpackagehandler.go +++ b/packagehandlers/commonpackagehandler.go @@ -14,7 +14,7 @@ type PackageHandler interface { UpdateDependency(details *utils.VulnerabilityDetails) error } -func GetCompatiblePackageHandler(vulnDetails *utils.VulnerabilityDetails, details *utils.ScanDetails) (handler PackageHandler) { +func GetCompatiblePackageHandler(vulnDetails *utils.VulnerabilityDetails, details *utils.RepositoryScanDetails) (handler PackageHandler) { switch vulnDetails.Technology { case coreutils.Go: handler = &GoPackageHandler{} @@ -27,9 +27,9 @@ func GetCompatiblePackageHandler(vulnDetails *utils.VulnerabilityDetails, detail case coreutils.Yarn: handler = &YarnPackageHandler{} case coreutils.Pip: - handler = &PythonPackageHandler{pipRequirementsFile: details.PipRequirementsFile} + handler = &PythonPackageHandler{pipRequirementsFile: details.Project().PipRequirementsFile} case coreutils.Maven: - handler = &MavenPackageHandler{depsRepo: details.DepsRepo, ServerDetails: details.ServerDetails} + handler = &MavenPackageHandler{depsRepo: details.Project().DepsRepo, ServerDetails: details.ServerDetails()} case coreutils.Nuget: handler = &NugetPackageHandler{} default: diff --git a/packagehandlers/packagehandlers_test.go b/packagehandlers/packagehandlers_test.go index a3dc10539..8ac224b07 100644 --- a/packagehandlers/packagehandlers_test.go +++ b/packagehandlers/packagehandlers_test.go @@ -18,7 +18,7 @@ import ( type dependencyFixTest struct { vulnDetails *utils.VulnerabilityDetails - scanDetails *utils.ScanDetails + project *utils.Project fixSupported bool specificTechVersion string uniqueChecksExtraArgs []string @@ -74,7 +74,7 @@ func TestUpdateDependency(t *testing.T) { SuggestedFixedVersion: "1.25.9", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "urllib3"}, }, - scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "requirements.txt"}}, + project: &utils.Project{PipRequirementsFile: "requirements.txt"}, fixSupported: false, }, { @@ -82,7 +82,7 @@ func TestUpdateDependency(t *testing.T) { SuggestedFixedVersion: "1.25.9", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyName: "urllib3"}, }, - scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "pyproejct.toml"}}, + project: &utils.Project{PipRequirementsFile: "pyproejct.toml"}, fixSupported: false, }, { @@ -90,7 +90,7 @@ func TestUpdateDependency(t *testing.T) { SuggestedFixedVersion: "1.25.9", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pipenv, ImpactedDependencyName: "urllib3"}, }, - scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "Pipfile"}}, + project: &utils.Project{PipRequirementsFile: "Pipfile"}, fixSupported: false, }, { @@ -99,7 +99,7 @@ func TestUpdateDependency(t *testing.T) { VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "pyjwt"}, IsDirectDependency: true, }, - scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "requirements.txt"}}, + project: &utils.Project{PipRequirementsFile: "requirements.txt"}, fixSupported: true, }, { @@ -107,7 +107,7 @@ func TestUpdateDependency(t *testing.T) { SuggestedFixedVersion: "2.4.0", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "Pyjwt"}, IsDirectDependency: true}, - scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "requirements.txt"}}, + project: &utils.Project{PipRequirementsFile: "requirements.txt"}, fixSupported: true, }, { @@ -115,7 +115,7 @@ func TestUpdateDependency(t *testing.T) { SuggestedFixedVersion: "2.4.0", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "pyjwt"}, IsDirectDependency: true}, - scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "setup.py"}}, + project: &utils.Project{PipRequirementsFile: "setup.py"}, fixSupported: true, }, { @@ -123,7 +123,7 @@ func TestUpdateDependency(t *testing.T) { SuggestedFixedVersion: "2.4.0", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyName: "pyjwt"}, IsDirectDependency: true}, - scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "pyproject.toml"}}, + project: &utils.Project{PipRequirementsFile: "pyproject.toml"}, fixSupported: true, }, }, @@ -185,7 +185,7 @@ func TestUpdateDependency(t *testing.T) { SuggestedFixedVersion: "2.7", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Maven, ImpactedDependencyName: "commons-io:commons-io"}, IsDirectDependency: true}, - scanDetails: &utils.ScanDetails{Project: &utils.Project{DepsRepo: ""}, ServerDetails: nil}, + project: &utils.Project{DepsRepo: ""}, fixSupported: true, }, { @@ -193,7 +193,7 @@ func TestUpdateDependency(t *testing.T) { SuggestedFixedVersion: "4.3.20", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Maven, ImpactedDependencyName: "org.springframework:spring-core"}, IsDirectDependency: false}, - scanDetails: &utils.ScanDetails{Project: &utils.Project{DepsRepo: ""}, ServerDetails: nil}, + project: &utils.Project{DepsRepo: ""}, fixSupported: false, }, }, @@ -222,7 +222,11 @@ func TestUpdateDependency(t *testing.T) { for _, testBatch := range testCases { for _, test := range testBatch { - packageHandler := GetCompatiblePackageHandler(test.vulnDetails, test.scanDetails) + repositoryScanDetails := utils.NewRepositoryScanDetails(nil, nil) + if test.project != nil { + repositoryScanDetails.SetProject(test.project) + } + packageHandler := GetCompatiblePackageHandler(test.vulnDetails, repositoryScanDetails) t.Run(fmt.Sprintf("%s:%s direct:%s", test.vulnDetails.Technology.ToString()+test.specificTechVersion, test.vulnDetails.ImpactedDependencyName, strconv.FormatBool(test.vulnDetails.IsDirectDependency)), func(t *testing.T) { testDataDir := getTestDataDir(t, test.vulnDetails.IsDirectDependency) diff --git a/scanpullrequest/scanpullrequest.go b/scanpullrequest/scanpullrequest.go index 757e817e9..8802768b6 100644 --- a/scanpullrequest/scanpullrequest.go +++ b/scanpullrequest/scanpullrequest.go @@ -164,18 +164,13 @@ func auditPullRequest(repoConfig *utils.Repository, client vcsclient.VcsClient, err = errors.Join(err, cleanupSource(), cleanupTarget()) }() - scanDetails := utils.NewScanDetails(client, &repoConfig.Server, &repoConfig.Git). - SetXrayGraphScanParams(repoConfig.Watches, repoConfig.JFrogProjectKey). - SetMinSeverity(repoConfig.MinSeverity). - SetFixableOnly(repoConfig.FixableOnly). - SetFailOnInstallationErrors(*repoConfig.FailOnSecurityIssues) - + scanDetails := utils.NewPullRequestScanDetails(client, repoConfig) for i := range repoConfig.Projects { scanDetails.SetProject(&repoConfig.Projects[i]) // Audit source branch var sourceResults *audit.Results - workingDirs := utils.GetFullPathWorkingDirs(scanDetails.Project.WorkingDirs, sourceBranchWd) + workingDirs := utils.GetFullPathWorkingDirs(scanDetails.Project().WorkingDirs, sourceBranchWd) sourceResults, err = scanDetails.RunInstallAndAudit(workingDirs...) if err != nil { return @@ -202,7 +197,7 @@ func auditPullRequest(repoConfig *utils.Repository, client vcsclient.VcsClient, // Set target branch scan details var targetResults *audit.Results - workingDirs = utils.GetFullPathWorkingDirs(scanDetails.Project.WorkingDirs, targetBranchWd) + workingDirs = utils.GetFullPathWorkingDirs(scanDetails.Project().WorkingDirs, targetBranchWd) targetResults, err = scanDetails.RunInstallAndAudit(workingDirs...) if err != nil { diff --git a/scanrepository/scanrepository.go b/scanrepository/scanrepository.go index 03f3444dd..82b7bffe8 100644 --- a/scanrepository/scanrepository.go +++ b/scanrepository/scanrepository.go @@ -32,13 +32,11 @@ type ScanRepositoryCmd struct { // When dryRun is enabled, dryRunRepoPath specifies the repository local path to clone dryRunRepoPath string // The scanDetails of the current scan - scanDetails *utils.ScanDetails + scanDetails *utils.RepositoryScanDetails // The base working directory baseWd string // The git client the command performs git operations with gitManager *utils.GitManager - // Determines whether to open a pull request for each vulnerability fix or to aggregate all fixes into one pull request - aggregateFixes bool // The current project technology projectTech coreutils.Technology // Stores all package manager handlers for detected issues @@ -58,7 +56,6 @@ func (cfp *ScanRepositoryCmd) scanAndFixRepository(repository *utils.Repository, if err = cfp.setCommandPrerequisites(repository, branch, client); err != nil { return } - cfp.scanDetails.SetXscGitInfoContext(branch, repository.Project, client) if err = cfp.scanAndFixBranch(repository); err != nil { return } @@ -80,7 +77,7 @@ func (cfp *ScanRepositoryCmd) scanAndFixBranch(repository *utils.Repository) (er err = errors.Join(err, restoreBaseDir(), fileutils.RemoveTempDir(clonedRepoDir)) }() for i := range repository.Projects { - cfp.scanDetails.Project = &repository.Projects[i] + cfp.scanDetails.SetProject(&repository.Projects[i]) cfp.projectTech = "" if err = cfp.scanAndFixProject(repository); err != nil { return @@ -90,29 +87,28 @@ func (cfp *ScanRepositoryCmd) scanAndFixBranch(repository *utils.Repository) (er } func (cfp *ScanRepositoryCmd) setCommandPrerequisites(repository *utils.Repository, branch string, client vcsclient.VcsClient) (err error) { - - cfp.scanDetails = utils.NewScanDetails(client, &repository.Server, &repository.Git). - SetXrayGraphScanParams(repository.Watches, repository.JFrogProjectKey). - SetFailOnInstallationErrors(*repository.FailOnSecurityIssues). - SetBaseBranch(branch). - SetFixableOnly(repository.FixableOnly). - SetMinSeverity(repository.MinSeverity) - - cfp.aggregateFixes = repository.Git.AggregateFixes cfp.OutputWriter = outputwriter.GetCompatibleOutputWriter(repository.GitProvider) - repositoryInfo, err := client.GetRepositoryInfo(context.Background(), cfp.scanDetails.RepoOwner, cfp.scanDetails.RepoName) + repositoryInfo, err := client.GetRepositoryInfo(context.Background(), repository.RepoOwner, repository.RepoName) if err != nil { return } - cfp.scanDetails.Git.RepositoryCloneUrl = repositoryInfo.CloneInfo.HTTP + + cfp.scanDetails = utils.NewRepositoryScanDetails(client, repository). + SetBaseBranch(branch). + SetAggregateFixes(repository.Git.AggregateFixes). + SetRepositoryCloneUrl(repositoryInfo.CloneInfo.HTTP). + SetXscGitInfoContext(branch, repository.Project, client) + cfp.gitManager, err = utils.NewGitManager(). - SetAuth(cfp.scanDetails.Username, cfp.scanDetails.Token). + SetAuth(cfp.scanDetails.VcsInfo().Username, cfp.scanDetails.VcsInfo().Username). SetDryRun(cfp.dryRun, cfp.dryRunRepoPath). - SetRemoteGitUrl(cfp.scanDetails.Git.RepositoryCloneUrl) + SetEmailAuthor(repository.EmailAuthor). + SetRemoteGitUrl(repositoryInfo.CloneInfo.HTTP) if err != nil { return } - _, err = cfp.gitManager.SetGitParams(cfp.scanDetails.Git) + customTemplates := utils.NewCustomTemplates(repository.CommitMessageTemplate, repository.BranchNameTemplate, repository.PullRequestTitleTemplate) + cfp.gitManager, err = cfp.gitManager.SetTemplates(customTemplates) return } @@ -122,7 +118,7 @@ func (cfp *ScanRepositoryCmd) scanAndFixProject(repository *utils.Repository) er // The value is a map of vulnerable package names -> the scanDetails of the vulnerable packages. // That means we have a map of all the vulnerabilities that were found in a specific folder, along with their full scanDetails. vulnerabilitiesByPathMap := make(map[string]map[string]*utils.VulnerabilityDetails) - projectFullPathWorkingDirs := utils.GetFullPathWorkingDirs(cfp.scanDetails.Project.WorkingDirs, cfp.baseWd) + projectFullPathWorkingDirs := utils.GetFullPathWorkingDirs(cfp.scanDetails.Project().WorkingDirs, cfp.baseWd) for _, fullPathWd := range projectFullPathWorkingDirs { scanResults, err := cfp.scan(fullPathWd) if err != nil { @@ -132,7 +128,7 @@ func (cfp *ScanRepositoryCmd) scanAndFixProject(repository *utils.Repository) er if repository.GitProvider.String() == vcsutils.GitHub.String() { // Uploads Sarif results to GitHub in order to view the scan in the code scanning UI // Currently available on GitHub only - if err = utils.UploadSarifResultsToGithubSecurityTab(scanResults, repository, cfp.scanDetails.BaseBranch(), cfp.scanDetails.Client()); err != nil { + if err = utils.UploadSarifResultsToGithubSecurityTab(scanResults, repository, cfp.scanDetails.BaseBranch(), cfp.scanDetails.GitClient()); err != nil { log.Warn(err) } } @@ -181,7 +177,7 @@ func (cfp *ScanRepositoryCmd) getVulnerabilitiesMap(scanResults *xrayutils.Exten } func (cfp *ScanRepositoryCmd) fixVulnerablePackages(vulnerabilitiesByWdMap map[string]map[string]*utils.VulnerabilityDetails) (err error) { - if cfp.aggregateFixes { + if cfp.scanDetails.AggregateFixes() { return cfp.fixIssuesSinglePR(vulnerabilitiesByWdMap) } return cfp.fixIssuesSeparatePRs(vulnerabilitiesByWdMap) @@ -334,7 +330,7 @@ func (cfp *ScanRepositoryCmd) openFixingPullRequest(fixBranchName string, vulnDe return } log.Debug("Creating Pull Request form:", fixBranchName, " to:", cfp.scanDetails.BaseBranch()) - return cfp.scanDetails.Client().CreatePullRequest(context.Background(), cfp.scanDetails.RepoOwner, cfp.scanDetails.RepoName, fixBranchName, cfp.scanDetails.BaseBranch(), pullRequestTitle, prBody) + return cfp.scanDetails.GitClient().CreatePullRequest(context.Background(), cfp.scanDetails.RepoOwner(), cfp.scanDetails.RepoName(), fixBranchName, cfp.scanDetails.BaseBranch(), pullRequestTitle, prBody) } // openAggregatedPullRequest handles the opening or updating of a pull request when the aggregate mode is active. @@ -353,20 +349,20 @@ func (cfp *ScanRepositoryCmd) openAggregatedPullRequest(fixBranchName string, pu } if pullRequestInfo == nil { log.Info("Creating Pull Request from:", fixBranchName, "to:", cfp.scanDetails.BaseBranch()) - return cfp.scanDetails.Client().CreatePullRequest(context.Background(), cfp.scanDetails.RepoOwner, cfp.scanDetails.RepoName, fixBranchName, cfp.scanDetails.BaseBranch(), pullRequestTitle, prBody) + return cfp.scanDetails.GitClient().CreatePullRequest(context.Background(), cfp.scanDetails.RepoOwner(), cfp.scanDetails.RepoName(), fixBranchName, cfp.scanDetails.BaseBranch(), pullRequestTitle, prBody) } log.Info("Updating Pull Request from:", fixBranchName, "to:", cfp.scanDetails.BaseBranch()) - return cfp.scanDetails.Client().UpdatePullRequest(context.Background(), cfp.scanDetails.RepoOwner, cfp.scanDetails.RepoName, pullRequestTitle, prBody, pullRequestInfo.Target.Name, int(pullRequestInfo.ID), vcsutils.Open) + return cfp.scanDetails.GitClient().UpdatePullRequest(context.Background(), cfp.scanDetails.RepoOwner(), cfp.scanDetails.RepoName(), pullRequestTitle, prBody, "", int(pullRequestInfo.ID), vcsutils.Open) } func (cfp *ScanRepositoryCmd) preparePullRequestDetails(vulnerabilitiesDetails ...*utils.VulnerabilityDetails) (string, string, error) { - if cfp.dryRun && cfp.aggregateFixes { + if cfp.dryRun && cfp.scanDetails.AggregateFixes() { // For testings, don't compare pull request body as scan results order may change. return outputwriter.GetAggregatedPullRequestTitle(cfp.projectTech), "", nil } vulnerabilitiesRows := utils.ExtractVulnerabilitiesDetailsToRows(vulnerabilitiesDetails) prBody := cfp.OutputWriter.VulnerabilitiesTitle(false) + "\n" + cfp.OutputWriter.VulnerabilitiesContent(vulnerabilitiesRows) + "\n---\n" + cfp.OutputWriter.UntitledForJasMsg() + cfp.OutputWriter.Footer() - if cfp.aggregateFixes { + if cfp.scanDetails.AggregateFixes() { scanHash, err := utils.VulnerabilityDetailsToMD5Hash(vulnerabilitiesRows...) if err != nil { return "", "", err @@ -381,7 +377,7 @@ func (cfp *ScanRepositoryCmd) preparePullRequestDetails(vulnerabilitiesDetails . func (cfp *ScanRepositoryCmd) cloneRepositoryAndCheckoutToBranch() (tempWd string, restoreDir func() error, err error) { if cfp.dryRun { - tempWd = filepath.Join(cfp.dryRunRepoPath, cfp.scanDetails.RepoName) + tempWd = filepath.Join(cfp.dryRunRepoPath, cfp.scanDetails.RepoName()) } else { // Create temp working directory if tempWd, err = fileutils.CreateTempDir(); err != nil { @@ -500,7 +496,7 @@ func (cfp *ScanRepositoryCmd) getRemoteBranchScanHash(prBody string) string { } func (cfp *ScanRepositoryCmd) getOpenPullRequestBySourceBranch(branchName string) (prInfo *vcsclient.PullRequestInfo, err error) { - list, err := cfp.scanDetails.Client().ListOpenPullRequestsWithBody(context.Background(), cfp.scanDetails.RepoOwner, cfp.scanDetails.RepoName) + list, err := cfp.scanDetails.GitClient().ListOpenPullRequestsWithBody(context.Background(), cfp.scanDetails.RepoOwner(), cfp.scanDetails.RepoName()) if err != nil { return } diff --git a/scanrepository/scanrepository_test.go b/scanrepository/scanrepository_test.go index a8dc66448..5a278a21a 100644 --- a/scanrepository/scanrepository_test.go +++ b/scanrepository/scanrepository_test.go @@ -115,8 +115,9 @@ func TestScanRepositoryCmd_Run(t *testing.T) { testName: "aggregate-cant-fix", expectedPackagesInBranch: map[string][]string{"frogbot-update-pip-dependencies": {}}, expectedVersionUpdatesInBranch: map[string][]string{"frogbot-update-pip-dependencies": {}}, - packageDescriptorPaths: []string{"setup.py"}, // This is a build tool dependency which should not be fixed - aggregateFixes: true, + // This is a build tool dependency that should not be fixed + packageDescriptorPaths: []string{"setup.py"}, + aggregateFixes: true, }, { testName: "non-aggregate", @@ -365,7 +366,7 @@ func TestPackageTypeFromScan(t *testing.T) { Params: params, } for _, pkg := range testPackagesData { - // Create temp technology project + // Create a temp technology project projectPath := filepath.Join("..", "testdata", "projects", pkg.packageType) t.Run(pkg.packageType, func(t *testing.T) { tmpDir, err := fileutils.CreateTempDir() @@ -379,22 +380,18 @@ func TestPackageTypeFromScan(t *testing.T) { assert.NoError(t, os.Chmod(filepath.Join(tmpDir, "gradlew.bat"), 0777)) } frogbotParams.Projects[0].WorkingDirs = []string{tmpDir} - files, err := fileutils.ListFiles(tmpDir, true) - assert.NoError(t, err) - for _, file := range files { - log.Info(file) - } frogbotParams.Projects[0].InstallCommandName = pkg.commandName frogbotParams.Projects[0].InstallCommandArgs = pkg.commandArgs - scanSetup := utils.ScanDetails{ - XrayGraphScanParams: &services.XrayGraphScanParams{}, - Project: &frogbotParams.Projects[0], - ServerDetails: &frogbotParams.Server, - } - testScan.scanDetails = &scanSetup + scanDetails := utils.NewRepositoryScanDetails(nil, nil) + scanDetails.SetProject(&frogbotParams.Projects[0]).SetServerDetails(&frogbotParams.Server).SetXrayGraphScanParams(nil, "") + testScan.scanDetails = scanDetails scanResponse, err := testScan.scan(tmpDir) assert.NoError(t, err) - verifyTechnologyNaming(t, scanResponse.ExtendedScanResults.XrayResults, pkg.packageType) + packageName := pkg.packageType + if pkg.commandName != "" { + packageName = pkg.commandName + } + verifyTechnologyNaming(t, scanResponse.ExtendedScanResults.XrayResults, packageName) }) } } @@ -659,7 +656,7 @@ random body } func TestPreparePullRequestDetails(t *testing.T) { - cfp := ScanRepositoryCmd{OutputWriter: &outputwriter.StandardOutput{}, gitManager: &utils.GitManager{}} + cfp := ScanRepositoryCmd{OutputWriter: &outputwriter.StandardOutput{}, gitManager: &utils.GitManager{}, scanDetails: utils.NewRepositoryScanDetails(nil, nil)} vulnerabilities := []*utils.VulnerabilityDetails{ { VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ @@ -689,7 +686,7 @@ func TestPreparePullRequestDetails(t *testing.T) { }, SuggestedFixedVersion: "2.0.0", }) - cfp.aggregateFixes = true + cfp.scanDetails.SetAggregateFixes(true) expectedPrBody = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | | package1:1.0.0 | 1.0.0
2.0.0 | CVE-2022-1234 |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableCriticalSeverity.png)
Critical | | package2:2.0.0 | 2.0.0
3.0.0 | CVE-2022-4321 |\n\n
\n\n## 👇 Details\n\n
\n [ CVE-2022-1234 ] package1 1.0.0 \n
\n\n**Description:**\nsummary\n\n\n
\n\n\n
\n [ CVE-2022-4321 ] package2 2.0.0 \n
\n\n**Description:**\nsummary\n\n\n
\n\n\n---\n\n
\n\n**Frogbot** also supports **Contextual Analysis, Secret Detection and IaC Vulnerabilities Scanning**. This features are included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system.\n\n
\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n\n[comment]: <> (Checksum: bec823edaceb5d0478b789798e819bde)\n" prTitle, prBody, err = cfp.preparePullRequestDetails(vulnerabilities...) assert.NoError(t, err) diff --git a/utils/depsutil.go b/utils/depsutil.go index 6e5fe1cea..b1845a572 100644 --- a/utils/depsutil.go +++ b/utils/depsutil.go @@ -27,9 +27,9 @@ var MapTechToResolvingFunc = map[string]resolveDependenciesFunc{ const yarnV2Version = "2.0.0" -func resolveNpmDependencies(scanSetup *ScanDetails) (output []byte, err error) { - npmCmd := npm.NewNpmCommand(scanSetup.InstallCommandArgs[0], false).SetServerDetails(scanSetup.ServerDetails) - if err = npmCmd.PreparePrerequisites(scanSetup.DepsRepo); err != nil { +func resolveNpmDependencies(scanDetails *ScanDetails) (output []byte, err error) { + npmCmd := npm.NewNpmCommand(scanDetails.project.InstallCommandArgs[0], false).SetServerDetails(&scanDetails.serverDetails) + if err = npmCmd.PreparePrerequisites(scanDetails.project.DepsRepo); err != nil { return nil, err } if err = npmCmd.CreateTempNpmrc(); err != nil { @@ -41,10 +41,10 @@ func resolveNpmDependencies(scanSetup *ScanDetails) (output []byte, err error) { err = restoreNpmrc() } }() - return exec.Command(coreutils.Npm.ToString(), scanSetup.InstallCommandArgs...).CombinedOutput() + return exec.Command(coreutils.Npm.ToString(), scanDetails.project.InstallCommandArgs...).CombinedOutput() } -func resolveYarnDependencies(scanSetup *ScanDetails) (output []byte, err error) { +func resolveYarnDependencies(scanDetails *ScanDetails) (output []byte, err error) { currWd, err := coreutils.GetWorkingDirectory() if err != nil { return nil, err @@ -70,7 +70,7 @@ func resolveYarnDependencies(scanSetup *ScanDetails) (output []byte, err error) return nil, err } - registry, repoAuthIdent, err := yarn.GetYarnAuthDetails(scanSetup.ServerDetails, scanSetup.DepsRepo) + registry, repoAuthIdent, err := yarn.GetYarnAuthDetails(&scanDetails.serverDetails, scanDetails.project.DepsRepo) if err != nil { return nil, yarn.RestoreConfigurationsAndError(nil, restoreYarnrcFunc, err) } @@ -84,10 +84,10 @@ func resolveYarnDependencies(scanSetup *ScanDetails) (output []byte, err error) err = e } }() - return nil, build.RunYarnCommand(yarnExecPath, currWd, scanSetup.InstallCommandArgs...) + return nil, build.RunYarnCommand(yarnExecPath, currWd, scanDetails.project.InstallCommandArgs...) } -func resolveDotnetDependencies(scanSetup *ScanDetails) (output []byte, err error) { +func resolveDotnetDependencies(scanDetails *ScanDetails) (output []byte, err error) { wd, err := fileutils.CreateTempDir() if err != nil { return @@ -98,12 +98,12 @@ func resolveDotnetDependencies(scanSetup *ScanDetails) (output []byte, err error err = e } }() - configFile, err := dotnet.InitNewConfig(wd, scanSetup.DepsRepo, scanSetup.ServerDetails, false) + configFile, err := dotnet.InitNewConfig(wd, scanDetails.project.DepsRepo, &scanDetails.serverDetails, false) if err != nil { return } - toolType := dotnetutils.ConvertNameToToolType(scanSetup.InstallCommandName) - args := scanSetup.InstallCommandArgs + toolType := dotnetutils.ConvertNameToToolType(scanDetails.project.InstallCommandName) + args := scanDetails.project.InstallCommandArgs args = append(args, toolType.GetTypeFlagPrefix()+"configfile", configFile.Name()) return exec.Command(toolType.String(), args...).CombinedOutput() } diff --git a/utils/depsutil_test.go b/utils/depsutil_test.go index cf80488a2..2a129e813 100644 --- a/utils/depsutil_test.go +++ b/utils/depsutil_test.go @@ -89,57 +89,49 @@ func TestResolveDependencies(t *testing.T) { testCases := []struct { name string tech string - scanSetup *ScanDetails + project Project repoKey string - resolveFunc func(scanSetup *ScanDetails) ([]byte, error) + resolveFunc func(scanDetails *ScanDetails) ([]byte, error) shouldExpectError bool }{ { name: "Resolve NPM dependencies", tech: "npm", - scanSetup: &ScanDetails{ - ServerDetails: ¶ms, - Project: &Project{ - InstallCommandName: "npm", - InstallCommandArgs: []string{"install"}, - }}, + project: Project{ + InstallCommandName: "npm", + InstallCommandArgs: []string{"install"}, + }, resolveFunc: resolveNpmDependencies, shouldExpectError: false, }, { name: "Resolve Yarn V2 dependencies", tech: "yarn2", - scanSetup: &ScanDetails{ - ServerDetails: ¶ms, - Project: &Project{ - InstallCommandName: "yarn", - InstallCommandArgs: []string{"install"}, - }}, + project: Project{ + InstallCommandName: "yarn", + InstallCommandArgs: []string{"install"}, + }, resolveFunc: resolveYarnDependencies, shouldExpectError: false, }, { name: "Resolve Yarn V1 dependencies", tech: "yarn1", - scanSetup: &ScanDetails{ - ServerDetails: ¶ms, - Project: &Project{ - InstallCommandName: "yarn", - InstallCommandArgs: []string{"install"}, - }}, + project: Project{ + InstallCommandName: "yarn", + InstallCommandArgs: []string{"install"}, + }, resolveFunc: resolveYarnDependencies, shouldExpectError: true, }, { name: "Resolve .NET dependencies", tech: "dotnet", - scanSetup: &ScanDetails{ - ServerDetails: ¶ms, - Project: &Project{ - DepsRepo: "frogbot-nuget-remote-tests", - InstallCommandName: "dotnet", - InstallCommandArgs: []string{"restore"}, - }}, + project: Project{ + DepsRepo: "frogbot-nuget-remote-tests", + InstallCommandName: "dotnet", + InstallCommandArgs: []string{"restore"}, + }, resolveFunc: resolveDotnetDependencies, shouldExpectError: false, }, @@ -149,8 +141,9 @@ func TestResolveDependencies(t *testing.T) { t.Run(test.name, func(t *testing.T) { restoreFunc, repoKey := setTestEnvironment(t, test.tech, ¶ms) defer restoreFunc() - test.scanSetup.Project.DepsRepo = repoKey - output, err := test.resolveFunc(test.scanSetup) + scanDetails := &ScanDetails{project: test.project, serverDetails: params} + scanDetails.project.DepsRepo = repoKey + output, err := test.resolveFunc(scanDetails) if test.shouldExpectError { assert.Error(t, err) } else { diff --git a/utils/git.go b/utils/git.go index 77b3d711c..8f97d7af8 100644 --- a/utils/git.go +++ b/utils/git.go @@ -44,12 +44,10 @@ type GitManager struct { dryRun bool // When dryRun is enabled, dryRunRepoPath specifies the repository local path to clone dryRunRepoPath string - // When dryRun is enabled, skipClone allows skipping the cloning of a repository for testing purposes - SkipClone bool // Custom naming formats customTemplates CustomTemplates - // Git details - git *Git + // Email author of the commits + emailAuthor string } type CustomTemplates struct { @@ -61,6 +59,14 @@ type CustomTemplates struct { pullRequestTitleTemplate string } +func NewCustomTemplates(commitMessage, branchName, prTitle string) *CustomTemplates { + return &CustomTemplates{ + commitMessageTemplate: commitMessage, + branchNameTemplate: branchName, + pullRequestTitleTemplate: prTitle, + } +} + func NewGitManager() *GitManager { setGoGitCustomClient() return &GitManager{} @@ -117,12 +123,11 @@ func (gm *GitManager) SetLocalRepository() (*GitManager, error) { return gm, err } -func (gm *GitManager) SetGitParams(gitParams *Git) (*GitManager, error) { +func (gm *GitManager) SetTemplates(templates *CustomTemplates) (*GitManager, error) { var err error - if gm.customTemplates, err = loadCustomTemplates(gitParams.CommitMessageTemplate, gitParams.BranchNameTemplate, gitParams.PullRequestTitleTemplate); err != nil { + if gm.customTemplates, err = loadCustomTemplates(templates.commitMessageTemplate, templates.branchNameTemplate, templates.pullRequestTitleTemplate); err != nil { return nil, err } - gm.git = gitParams return gm, nil } @@ -132,6 +137,11 @@ func (gm *GitManager) SetDryRun(dryRun bool, dryRunRepoPath string) *GitManager return gm } +func (gm *GitManager) SetEmailAuthor(emailAuthor string) *GitManager { + gm.emailAuthor = emailAuthor + return gm +} + func (gm *GitManager) Checkout(branchName string) error { log.Debug("Running git checkout to branch:", branchName) if err := gm.createBranchAndCheckout(branchName, false); err != nil { @@ -252,7 +262,7 @@ func (gm *GitManager) commit(commitMessage string) error { _, err = worktree.Commit(commitMessage, &git.CommitOptions{ Author: &object.Signature{ Name: frogbotAuthorName, - Email: gm.git.EmailAuthor, + Email: gm.emailAuthor, When: time.Now(), }, }) diff --git a/utils/pullrequestscandetails.go b/utils/pullrequestscandetails.go new file mode 100644 index 000000000..03e46d046 --- /dev/null +++ b/utils/pullrequestscandetails.go @@ -0,0 +1,17 @@ +package utils + +import ( + "github.com/jfrog/froggit-go/vcsclient" +) + +type PullRequestScanDetails struct { + *ScanDetails +} + +func NewPullRequestScanDetails(client vcsclient.VcsClient, repository *Repository) *PullRequestScanDetails { + return &PullRequestScanDetails{ScanDetails: newScanDetails(client, repository)} +} + +func (prd *PullRequestScanDetails) PullRequestDetails() vcsclient.PullRequestInfo { + return prd.git.PullRequestDetails +} diff --git a/utils/repositoryscandetails.go b/utils/repositoryscandetails.go new file mode 100644 index 000000000..6867ec5d8 --- /dev/null +++ b/utils/repositoryscandetails.go @@ -0,0 +1,122 @@ +package utils + +import ( + "context" + "fmt" + "github.com/jfrog/froggit-go/vcsclient" + "github.com/jfrog/froggit-go/vcsutils" + "github.com/jfrog/jfrog-client-go/utils/log" + "github.com/jfrog/jfrog-client-go/xray/services" +) + +type RepositoryScanDetails struct { + *ScanDetails + baseBranch string +} + +func NewRepositoryScanDetails(client vcsclient.VcsClient, repository *Repository) *RepositoryScanDetails { + return &RepositoryScanDetails{ScanDetails: newScanDetails(client, repository)} +} + +func (rsd *RepositoryScanDetails) SetBaseBranch(branch string) *RepositoryScanDetails { + rsd.baseBranch = branch + return rsd +} + +func (rsd *RepositoryScanDetails) BaseBranch() string { + return rsd.baseBranch +} + +func (rsd *RepositoryScanDetails) SetRepoOwner(owner string) *RepositoryScanDetails { + rsd.git.RepoOwner = owner + return rsd +} + +func (rsd *RepositoryScanDetails) RepoOwner() string { + return rsd.git.RepoOwner +} + +func (rsd *RepositoryScanDetails) SetRepoName(repoName string) *RepositoryScanDetails { + rsd.git.RepoName = repoName + return rsd +} + +func (rsd *RepositoryScanDetails) RepoName() string { + return rsd.git.RepoName +} + +func (rsd *RepositoryScanDetails) BranchNameTemplate() string { + return rsd.git.BranchNameTemplate +} + +func (rsd *RepositoryScanDetails) CommitMessageTemplate() string { + return rsd.git.CommitMessageTemplate +} + +func (rsd *RepositoryScanDetails) PullRequestTitleTemplate() string { + return rsd.git.PullRequestTitleTemplate +} + +func (rsd *RepositoryScanDetails) EmailAuthor() string { + return rsd.git.EmailAuthor +} + +func (rsd *RepositoryScanDetails) GitProvider() vcsutils.VcsProvider { + return rsd.git.GitProvider +} + +func (rsd *RepositoryScanDetails) VcsInfo() vcsclient.VcsInfo { + return rsd.git.VcsInfo +} + +func (rsd *RepositoryScanDetails) SetAggregateFixes(toAggregate bool) *RepositoryScanDetails { + rsd.git.AggregateFixes = toAggregate + return rsd +} + +func (rsd *RepositoryScanDetails) AggregateFixes() bool { + return rsd.git.AggregateFixes +} + +func (rsd *RepositoryScanDetails) SetRepositoryCloneUrl(cloneUrl string) *RepositoryScanDetails { + rsd.git.RepositoryCloneUrl = cloneUrl + return rsd +} + +func (rsd *RepositoryScanDetails) SetXscGitInfoContext(scannedBranch, gitProject string, client vcsclient.VcsClient) *RepositoryScanDetails { + XscGitInfoContext, err := rsd.createGitInfoContext(scannedBranch, gitProject, client) + if err != nil { + log.Debug("failed trying to create GitInfoContext for Xsc with the following error: ", err.Error()) + return rsd + } + rsd.xrayGraphScanParams.XscGitInfoContext = XscGitInfoContext + return rsd +} + +// CreateGitInfoContext Creates GitInfoContext for XSC scans, this is optional. +// ScannedBranch - name of the branch we are scanning. +// GitProject - [Optional] relevant for azure repos and Bitbucket server. +// Client vscClient +func (rsd *RepositoryScanDetails) createGitInfoContext(scannedBranch, gitProject string, client vcsclient.VcsClient) (gitInfo *services.XscGitInfoContext, err error) { + latestCommit, err := client.GetLatestCommit(context.Background(), rsd.git.RepoOwner, rsd.git.RepoName, scannedBranch) + if err != nil { + return nil, fmt.Errorf("failed getting latest commit, repository: %s, branch: %s. error: %s ", rsd.git.RepoName, scannedBranch, err.Error()) + } + // In some VCS providers, there are no git projects, fallback to the repository owner. + if gitProject == "" { + gitProject = rsd.git.RepoOwner + } + gitInfo = &services.XscGitInfoContext{ + // Use Clone URLs as Repo Url, on browsers it will redirect to repository URLS. + GitRepoUrl: rsd.git.RepositoryCloneUrl, + GitRepoName: rsd.git.RepoName, + GitProvider: rsd.git.GitProvider.String(), + GitProject: gitProject, + BranchName: scannedBranch, + LastCommit: latestCommit.Url, + CommitHash: latestCommit.Hash, + CommitMessage: latestCommit.Message, + CommitAuthor: latestCommit.AuthorName, + } + return +} diff --git a/utils/scandetails.go b/utils/scandetails.go index 0026b8e26..fd7dd34e9 100644 --- a/utils/scandetails.go +++ b/utils/scandetails.go @@ -1,7 +1,6 @@ package utils import ( - "context" "errors" "fmt" "github.com/jfrog/froggit-go/vcsclient" @@ -12,87 +11,96 @@ import ( "github.com/jfrog/jfrog-client-go/xray/services" "os/exec" - "path/filepath" "strings" ) const ( - installationCmdFailedErr = "Couldn't run the installation command on the base branch. Assuming new project in the source branch: " + installationCmdFailedMsg = "Couldn't run the installation command on the base branch. Assuming new project in the source branch: " ) type ScanDetails struct { - *Project - *Git - *services.XrayGraphScanParams - *config.ServerDetails - client vcsclient.VcsClient - failOnInstallationErrors bool - fixableOnly bool - minSeverityFilter string - baseBranch string + project Project + xrayGraphScanParams services.XrayGraphScanParams + serverDetails config.ServerDetails + git Git + client vcsclient.VcsClient + failOnSecurityIssues bool + fixableOnly bool + minSeverityFilter string +} + +func newScanDetails(client vcsclient.VcsClient, repository *Repository) *ScanDetails { + if repository == nil { + return &ScanDetails{} + } + scanDetails := ScanDetails{client: client, serverDetails: repository.Server, git: repository.Git} + scanDetails.SetFailOnSecurityIssues(*repository.FailOnSecurityIssues). + SetMinSeverity(repository.MinSeverity). + SetFixableOnly(repository.FixableOnly). + SetXrayGraphScanParams(repository.Watches, repository.JFrogProjectKey) + return &scanDetails } -func NewScanDetails(client vcsclient.VcsClient, server *config.ServerDetails, git *Git) *ScanDetails { - return &ScanDetails{client: client, ServerDetails: server, Git: git} +func (sc *ScanDetails) Project() *Project { + return &sc.project } -func (sc *ScanDetails) SetFailOnInstallationErrors(toFail bool) *ScanDetails { - sc.failOnInstallationErrors = toFail - return sc +func (sc *ScanDetails) XrayGraphScanParams() *services.XrayGraphScanParams { + return &sc.xrayGraphScanParams } -func (sc *ScanDetails) SetProject(project *Project) *ScanDetails { - sc.Project = project - return sc +func (sc *ScanDetails) ServerDetails() *config.ServerDetails { + return &sc.serverDetails } -func (sc *ScanDetails) SetXrayGraphScanParams(watches []string, jfrogProjectKey string) *ScanDetails { - sc.XrayGraphScanParams = createXrayScanParams(watches, jfrogProjectKey) - return sc +func (sc *ScanDetails) GitClient() vcsclient.VcsClient { + return sc.client } -func (sc *ScanDetails) SetFixableOnly(fixable bool) *ScanDetails { - sc.fixableOnly = fixable - return sc +func (sc *ScanDetails) FailOnSecurityIssues() bool { + return sc.failOnSecurityIssues } -func (sc *ScanDetails) SetMinSeverity(minSeverity string) *ScanDetails { - sc.minSeverityFilter = minSeverity - return sc +func (sc *ScanDetails) FixableOnly() bool { + return sc.fixableOnly } -func (sc *ScanDetails) SetBaseBranch(branch string) *ScanDetails { - sc.baseBranch = branch - return sc +func (sc *ScanDetails) MinSeverityFilter() string { + return sc.minSeverityFilter } -func (sc *ScanDetails) Client() vcsclient.VcsClient { - return sc.client +func (sc *ScanDetails) SetMinSeverityFilter(minSeverityFilter string) *ScanDetails { + sc.minSeverityFilter = minSeverityFilter + return sc } -func (sc *ScanDetails) BaseBranch() string { - return sc.baseBranch +func (sc *ScanDetails) SetFailOnSecurityIssues(toFail bool) *ScanDetails { + sc.failOnSecurityIssues = toFail + return sc } -func (sc *ScanDetails) FailOnInstallationErrors() bool { - return sc.failOnInstallationErrors +func (sc *ScanDetails) SetProject(project *Project) *ScanDetails { + sc.project = *project + return sc } -func (sc *ScanDetails) FixableOnly() bool { - return sc.fixableOnly +func (sc *ScanDetails) SetXrayGraphScanParams(watches []string, jfrogProjectKey string) *ScanDetails { + sc.xrayGraphScanParams = *createXrayScanParams(watches, jfrogProjectKey) + return sc } -func (sc *ScanDetails) MinSeverityFilter() string { - return sc.minSeverityFilter +func (sc *ScanDetails) SetFixableOnly(fixable bool) *ScanDetails { + sc.fixableOnly = fixable + return sc } -func (sc *ScanDetails) SetRepoOwner(owner string) *ScanDetails { - sc.RepoOwner = owner +func (sc *ScanDetails) SetMinSeverity(minSeverity string) *ScanDetails { + sc.minSeverityFilter = minSeverity return sc } -func (sc *ScanDetails) SetRepoName(repoName string) *ScanDetails { - sc.RepoName = repoName +func (sc *ScanDetails) SetServerDetails(serverDetails *config.ServerDetails) *ScanDetails { + sc.serverDetails = *serverDetails return sc } @@ -122,17 +130,17 @@ func (sc *ScanDetails) RunInstallAndAudit(workDirs ...string) (auditResults *aud } auditBasicParams := (&xrayutils.AuditBasicParams{}). - SetPipRequirementsFile(sc.PipRequirementsFile). - SetUseWrapper(*sc.UseWrapper). - SetDepsRepo(sc.DepsRepo). + SetPipRequirementsFile(sc.project.PipRequirementsFile). + SetUseWrapper(*sc.project.UseWrapper). + SetDepsRepo(sc.project.DepsRepo). SetIgnoreConfigFile(true). - SetServerDetails(sc.ServerDetails) + SetServerDetails(&sc.serverDetails) auditParams := audit.NewAuditParams(). - SetXrayGraphScanParams(sc.XrayGraphScanParams). + SetXrayGraphScanParams(&sc.xrayGraphScanParams). SetWorkingDirs(workDirs). - SetMinSeverityFilter(sc.MinSeverityFilter()). - SetFixableOnly(sc.FixableOnly()). + SetMinSeverityFilter(sc.minSeverityFilter). + SetFixableOnly(sc.fixableOnly). SetGraphBasicParams(auditBasicParams) auditResults, err = audit.RunAudit(auditParams) @@ -143,86 +151,32 @@ func (sc *ScanDetails) RunInstallAndAudit(workDirs ...string) (auditResults *aud } func (sc *ScanDetails) runInstallIfNeeded(workDir string) (err error) { - if sc.InstallCommandName == "" { + if sc.project.InstallCommandName == "" { return nil } restoreDir, err := Chdir(workDir) defer func() { err = errors.Join(err, restoreDir()) }() - log.Info(fmt.Sprintf("Executing '%s %s' at %s", sc.InstallCommandName, strings.Join(sc.InstallCommandArgs, " "), workDir)) + log.Info(fmt.Sprintf("Executing '%s %s' at %s", sc.project.InstallCommandName, strings.Join(sc.project.InstallCommandArgs, " "), workDir)) output, err := sc.runInstallCommand() - if err != nil && !sc.FailOnInstallationErrors() { - log.Info(installationCmdFailedErr, err.Error(), "\n", string(output)) - // failOnInstallationErrors set to 'false' + if err != nil && !sc.failOnSecurityIssues { + log.Info(installationCmdFailedMsg, err.Error(), "\n", string(output)) + // failOnSecurityIssues set to 'false' err = nil } return } func (sc *ScanDetails) runInstallCommand() ([]byte, error) { - if sc.DepsRepo == "" { + if sc.project.DepsRepo == "" { //#nosec G204 -- False positive - the subprocess only runs after the user's approval. - return exec.Command(sc.InstallCommandName, sc.InstallCommandArgs...).CombinedOutput() - } - - if _, exists := MapTechToResolvingFunc[sc.InstallCommandName]; !exists { - return nil, fmt.Errorf(sc.InstallCommandName, "isn't recognized as an install command") + return exec.Command(sc.project.InstallCommandName, sc.project.InstallCommandArgs...).CombinedOutput() } - log.Info("Resolving dependencies from", sc.ServerDetails.Url, "from repo", sc.DepsRepo) - return MapTechToResolvingFunc[sc.InstallCommandName](sc) -} - -func (sc *ScanDetails) SetXscGitInfoContext(scannedBranch, gitProject string, client vcsclient.VcsClient) *ScanDetails { - XscGitInfoContext, err := sc.createGitInfoContext(scannedBranch, gitProject, client) - if err != nil { - log.Debug("failed trying to create GitInfoContext for Xsc with the following error: ", err.Error()) - return sc - } - sc.XscGitInfoContext = XscGitInfoContext - return sc -} - -// CreateGitInfoContext Creates GitInfoContext for XSC scans, this is optional. -// ScannedBranch - name of the branch we are scanning. -// GitProject - [Optional] relevant for azure repos and Bitbucket server. -// Client vscClient -func (sc *ScanDetails) createGitInfoContext(scannedBranch, gitProject string, client vcsclient.VcsClient) (gitInfo *services.XscGitInfoContext, err error) { - latestCommit, err := client.GetLatestCommit(context.Background(), sc.RepoOwner, sc.RepoName, scannedBranch) - if err != nil { - return nil, fmt.Errorf("failed getting latest commit, repository: %s, branch: %s. error: %s ", sc.RepoName, scannedBranch, err.Error()) - } - // In some VCS providers, there are no git projects, fallback to the repository owner. - if gitProject == "" { - gitProject = sc.RepoOwner - } - gitInfo = &services.XscGitInfoContext{ - // Use Clone URLs as Repo Url, on browsers it will redirect to repository URLS. - GitRepoUrl: sc.Git.RepositoryCloneUrl, - GitRepoName: sc.RepoName, - GitProvider: sc.GitProvider.String(), - GitProject: gitProject, - BranchName: scannedBranch, - LastCommit: latestCommit.Url, - CommitHash: latestCommit.Hash, - CommitMessage: latestCommit.Message, - CommitAuthor: latestCommit.AuthorName, - } - return -} -func GetFullPathWorkingDirs(workingDirs []string, baseWd string) []string { - var fullPathWds []string - if len(workingDirs) != 0 { - for _, workDir := range workingDirs { - if workDir == RootDir { - fullPathWds = append(fullPathWds, baseWd) - continue - } - fullPathWds = append(fullPathWds, filepath.Join(baseWd, workDir)) - } - } else { - fullPathWds = append(fullPathWds, baseWd) + if _, exists := MapTechToResolvingFunc[sc.project.InstallCommandName]; !exists { + return nil, fmt.Errorf(sc.project.InstallCommandName, "isn't recognized as an install command") } - return fullPathWds + log.Info("Resolving dependencies from", sc.serverDetails.Url, "from repo", sc.project.DepsRepo) + return MapTechToResolvingFunc[sc.project.InstallCommandName](sc) } diff --git a/utils/scandetails_test.go b/utils/scandetails_test.go index 8810a3196..8ba8ed253 100644 --- a/utils/scandetails_test.go +++ b/utils/scandetails_test.go @@ -11,31 +11,31 @@ func TestCreateXrayScanParams(t *testing.T) { // Project scanDetails := &ScanDetails{} scanDetails.SetXrayGraphScanParams(nil, "") - assert.Empty(t, scanDetails.Watches) - assert.Equal(t, "", scanDetails.ProjectKey) - assert.True(t, scanDetails.IncludeVulnerabilities) - assert.False(t, scanDetails.IncludeLicenses) + assert.Empty(t, scanDetails.xrayGraphScanParams.Watches) + assert.Equal(t, "", scanDetails.xrayGraphScanParams.ProjectKey) + assert.True(t, scanDetails.xrayGraphScanParams.IncludeVulnerabilities) + assert.False(t, scanDetails.xrayGraphScanParams.IncludeLicenses) // Watches scanDetails.SetXrayGraphScanParams([]string{"watch-1", "watch-2"}, "") - assert.Equal(t, []string{"watch-1", "watch-2"}, scanDetails.Watches) - assert.Equal(t, "", scanDetails.ProjectKey) - assert.False(t, scanDetails.IncludeVulnerabilities) - assert.False(t, scanDetails.IncludeLicenses) + assert.Equal(t, []string{"watch-1", "watch-2"}, scanDetails.xrayGraphScanParams.Watches) + assert.Equal(t, "", scanDetails.xrayGraphScanParams.ProjectKey) + assert.False(t, scanDetails.xrayGraphScanParams.IncludeVulnerabilities) + assert.False(t, scanDetails.xrayGraphScanParams.IncludeLicenses) // Project scanDetails.SetXrayGraphScanParams(nil, "project") - assert.Empty(t, scanDetails.Watches) - assert.Equal(t, "project", scanDetails.ProjectKey) - assert.False(t, scanDetails.IncludeVulnerabilities) - assert.False(t, scanDetails.IncludeLicenses) + assert.Empty(t, scanDetails.xrayGraphScanParams.Watches) + assert.Equal(t, "project", scanDetails.xrayGraphScanParams.ProjectKey) + assert.False(t, scanDetails.xrayGraphScanParams.IncludeVulnerabilities) + assert.False(t, scanDetails.xrayGraphScanParams.IncludeLicenses) } func TestRunInstallIfNeeded(t *testing.T) { scanSetup := ScanDetails{ - Project: &Project{}, + project: Project{}, } - scanSetup.SetFailOnInstallationErrors(true) + scanSetup.SetFailOnSecurityIssues(true) assert.NoError(t, scanSetup.runInstallIfNeeded("")) tmpDir, err := fileutils.CreateTempDir() assert.NoError(t, err) @@ -47,20 +47,20 @@ func TestRunInstallIfNeeded(t *testing.T) { InstallCommandName: "echo", InstallCommandArgs: []string{"Hello"}, } - scanSetup.Project = params + scanSetup.SetProject(params) assert.NoError(t, scanSetup.runInstallIfNeeded(tmpDir)) - scanSetup.InstallCommandName = "not-exist" - scanSetup.InstallCommandArgs = []string{"1", "2"} - scanSetup.SetFailOnInstallationErrors(false) + scanSetup.project.InstallCommandName = "not-exist" + scanSetup.project.InstallCommandArgs = []string{"1", "2"} + scanSetup.SetFailOnSecurityIssues(false) assert.NoError(t, scanSetup.runInstallIfNeeded(tmpDir)) params = &Project{ InstallCommandName: "not-existed", InstallCommandArgs: []string{"1", "2"}, } - scanSetup.Project = params - scanSetup.SetFailOnInstallationErrors(true) + scanSetup.SetProject(params) + scanSetup.SetFailOnSecurityIssues(true) assert.Error(t, scanSetup.runInstallIfNeeded(tmpDir)) } diff --git a/utils/utils.go b/utils/utils.go index a2b146213..ab66745f3 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "os" + "path/filepath" "regexp" "sort" "strings" @@ -366,3 +367,19 @@ func GetSortedPullRequestComments(client vcsclient.VcsClient, repoOwner, repoNam }) return pullRequestsComments, nil } + +func GetFullPathWorkingDirs(workingDirs []string, baseWd string) []string { + var fullPathWds []string + if len(workingDirs) != 0 { + for _, workDir := range workingDirs { + if workDir == RootDir { + fullPathWds = append(fullPathWds, baseWd) + continue + } + fullPathWds = append(fullPathWds, filepath.Join(baseWd, workDir)) + } + } else { + fullPathWds = append(fullPathWds, baseWd) + } + return fullPathWds +}