diff --git a/commands/createfixpullrequests.go b/commands/createfixpullrequests.go index 699eeab97..99400f3f0 100644 --- a/commands/createfixpullrequests.go +++ b/commands/createfixpullrequests.go @@ -310,11 +310,11 @@ func (cfp *CreateFixPullRequestsCmd) openFixingPullRequest(fixBranchName string, if err = cfp.gitManager.Push(false, fixBranchName); err != nil { return } - scanHash, err := utils.VulnerabilityDetailsToMD5Hash(vulnDetails) + scanHash, err := utils.VulnerabilityDetailsToMD5Hash(vulnDetails.VulnerabilityOrViolationRow) if err != nil { return err } - pullRequestTitle, prBody := cfp.preparePullRequestDetails(scanHash, []formats.VulnerabilityOrViolationRow{*vulnDetails.VulnerabilityOrViolationRow}) + pullRequestTitle, prBody := cfp.preparePullRequestDetails(scanHash, []formats.VulnerabilityOrViolationRow{vulnDetails.VulnerabilityOrViolationRow}) log.Debug("Creating Pull Request form:", fixBranchName, " to:", cfp.details.Branch()) return cfp.details.Client().CreatePullRequest(context.Background(), cfp.details.RepoOwner, cfp.details.RepoName, fixBranchName, cfp.details.Branch(), pullRequestTitle, prBody) } @@ -329,14 +329,11 @@ func (cfp *CreateFixPullRequestsCmd) openAggregatedPullRequest(fixBranchName str if err = cfp.gitManager.Push(true, fixBranchName); err != nil { return } - scanHash, err := utils.VulnerabilityDetailsToMD5Hash(vulnerabilities...) + vulnerabilityRows := utils.ExtractVunerabilitiesDetailsToRows(vulnerabilities) + scanHash, err := utils.VulnerabilityDetailsToMD5Hash(vulnerabilityRows...) if err != nil { return } - var vulnerabilityRows []formats.VulnerabilityOrViolationRow - for _, vulnerability := range vulnerabilities { - vulnerabilityRows = append(vulnerabilityRows, *vulnerability.VulnerabilityOrViolationRow) - } pullRequestTitle, prBody := cfp.preparePullRequestDetails(scanHash, vulnerabilityRows) if pullRequestInfo == nil { log.Info("Creating Pull Request from:", fixBranchName, "to:", cfp.details.Branch()) @@ -454,7 +451,7 @@ func (cfp *CreateFixPullRequestsCmd) addVulnerabilityToFixVersionsMap(vulnerabil return err } // First appearance of a version that fixes the current impacted package - newVulnDetails := utils.NewVulnerabilityDetails(vulnerability, vulnFixVersion) + newVulnDetails := utils.NewVulnerabilityDetails(*vulnerability, vulnFixVersion) newVulnDetails.SetIsDirectDependency(isDirectDependency) vulnerabilitiesMap[vulnerability.ImpactedDependencyName] = newVulnDetails } @@ -561,7 +558,8 @@ func (cfp *CreateFixPullRequestsCmd) isUpdateRequired(fixedVulnerabilities []*ut } log.Info("Aggregated pull request already exists, verifying if update is needed...") log.Debug("Comparing current scan results to existing", prInfo.Target.Name, "scan results") - currentScanHash, err := utils.VulnerabilityDetailsToMD5Hash(fixedVulnerabilities...) + fixedVulnerabilitiesRows := utils.ExtractVunerabilitiesDetailsToRows(fixedVulnerabilities) + currentScanHash, err := utils.VulnerabilityDetailsToMD5Hash(fixedVulnerabilitiesRows...) if err != nil { return } diff --git a/commands/createfixpullrequests_test.go b/commands/createfixpullrequests_test.go index 1828040b1..83f027b80 100644 --- a/commands/createfixpullrequests_test.go +++ b/commands/createfixpullrequests_test.go @@ -520,7 +520,7 @@ func TestUpdatePackageToFixedVersion(t *testing.T) { var testScan CreateFixPullRequestsCmd for tech, buildToolsDependencies := range utils.BuildToolsDependenciesMap { for _, impactedDependency := range buildToolsDependencies { - vulnDetails := &utils.VulnerabilityDetails{SuggestedFixedVersion: "3.3.3", VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: tech, ImpactedDependencyName: impactedDependency}, IsDirectDependency: true} + vulnDetails := &utils.VulnerabilityDetails{SuggestedFixedVersion: "3.3.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: tech, ImpactedDependencyName: impactedDependency}, IsDirectDependency: true} err := testScan.updatePackageToFixedVersion(vulnDetails) assert.Error(t, err, "Expected error to occur") assert.IsType(t, &utils.ErrUnsupportedFix{}, err, "Expected unsupported fix error") @@ -634,7 +634,7 @@ func TestPreparePullRequestDetails(t *testing.T) { Cves: []formats.CveRow{{Id: "CVE-2022-1234"}}, }, } - expectedPrBody := "[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | | package1:1.0.0 | 1.0.0

2.0.0 |\n\n
\n\n## 👇 Details\n\n\n\n\n- **Severity** 🔥 High\n- **Package Name:** package1\n- **Current Version:** 1.0.0\n- **Fixed Versions:** 1.0.0,2.0.0\n- **CVE:** CVE-2022-1234\n\n**Description:**\n\nsummary\n\n\n\n\n---\n\n
\n\n**Frogbot** also supports **Contextual Analysis**. This feature is 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[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n" + 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 |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | | package1:1.0.0 | 1.0.0

2.0.0 |\n\n
\n\n## 👇 Details\n\n\n\n\n- **Severity** 🔥 High\n- **Package Name:** package1\n- **Current Version:** 1.0.0\n- **Fixed Versions:** 1.0.0,2.0.0\n- **CVE:** CVE-2022-1234\n\n**Description:**\n\nsummary\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[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n" prTitle, prBody := cfp.preparePullRequestDetails("hash", vulnerabilities) assert.Equal(t, "[🐸 Frogbot] Update version of package1 to 1.0.0", prTitle) assert.Equal(t, expectedPrBody, prBody) @@ -647,12 +647,12 @@ func TestPreparePullRequestDetails(t *testing.T) { Cves: []formats.CveRow{{Id: "CVE-2022-4321"}}, }) cfp.aggregateFixes = true - expectedPrBody = "[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | | package1:1.0.0 | 1.0.0

2.0.0 |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableCriticalSeverity.png)
Critical | | package2:2.0.0 | 2.0.0

3.0.0 |\n\n
\n\n## 👇 Details\n\n\n
\n package1 1.0.0 \n
\n\n- **Severity** 🔥 High\n- **Package Name:** package1\n- **Current Version:** 1.0.0\n- **Fixed Versions:** 1.0.0,2.0.0\n- **CVE:** CVE-2022-1234\n\n**Description:**\n\nsummary\n\n\n\n
\n\n\n
\n package2 2.0.0 \n
\n\n- **Severity** 💀 Critical\n- **Package Name:** package2\n- **Current Version:** 2.0.0\n- **Fixed Versions:** 2.0.0,3.0.0\n- **CVE:** CVE-2022-4321\n\n**Description:**\n\nsummary\n\n\n\n
\n\n\n---\n\n
\n\n**Frogbot** also supports **Contextual Analysis**. This feature is 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[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n\n[comment]: <> (Checksum: hash)\n" + 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 |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | | package1:1.0.0 | 1.0.0

2.0.0 |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableCriticalSeverity.png)
Critical | | package2:2.0.0 | 2.0.0

3.0.0 |\n\n
\n\n## 👇 Details\n\n\n
\n package1 1.0.0 \n
\n\n- **Severity** 🔥 High\n- **Package Name:** package1\n- **Current Version:** 1.0.0\n- **Fixed Versions:** 1.0.0,2.0.0\n- **CVE:** CVE-2022-1234\n\n**Description:**\n\nsummary\n\n\n\n
\n\n\n
\n package2 2.0.0 \n
\n\n- **Severity** 💀 Critical\n- **Package Name:** package2\n- **Current Version:** 2.0.0\n- **Fixed Versions:** 2.0.0,3.0.0\n- **CVE:** CVE-2022-4321\n\n**Description:**\n\nsummary\n\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[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n\n[comment]: <> (Checksum: hash)\n" prTitle, prBody = cfp.preparePullRequestDetails("hash", vulnerabilities) assert.Equal(t, utils.GetAggregatedPullRequestTitle(""), prTitle) assert.Equal(t, expectedPrBody, prBody) cfp.OutputWriter = &utils.SimplifiedOutput{} - expectedPrBody = "**🚨 This automated pull request was created by Frogbot and fixes the below:**\n\n\n---\n## 📦 Vulnerable Dependencies\n---\n\n### ✍️ Summary \n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| High | | package1:1.0.0 | 1.0.0, 2.0.0 |\n| Critical | | package2:2.0.0 | 2.0.0, 3.0.0 |\n\n---\n### 👇 Details\n---\n\n\n#### package1 1.0.0\n\n\n- **Severity** 🔥 High\n- **Package Name:** package1\n- **Current Version:** 1.0.0\n- **Fixed Versions:** 1.0.0,2.0.0\n- **CVE:** CVE-2022-1234\n\n**Description:**\n\nsummary\n\n\n\n\n#### package2 2.0.0\n\n\n- **Severity** 💀 Critical\n- **Package Name:** package2\n- **Current Version:** 2.0.0\n- **Fixed Versions:** 2.0.0,3.0.0\n- **CVE:** CVE-2022-4321\n\n**Description:**\n\nsummary\n\n\n\n\n---\n\n\n**Frogbot** also supports **Contextual Analysis**. This feature is included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system.\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n[comment]: <> (Checksum: hash)\n" + expectedPrBody = "**🚨 This automated pull request was created by Frogbot and fixes the below:**\n\n\n---\n## 📦 Vulnerable Dependencies\n---\n\n### ✍️ Summary \n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| High | | package1:1.0.0 | 1.0.0, 2.0.0 |\n| Critical | | package2:2.0.0 | 2.0.0, 3.0.0 |\n\n---\n### 👇 Details\n---\n\n\n#### package1 1.0.0\n\n\n- **Severity** 🔥 High\n- **Package Name:** package1\n- **Current Version:** 1.0.0\n- **Fixed Versions:** 1.0.0,2.0.0\n- **CVE:** CVE-2022-1234\n\n**Description:**\n\nsummary\n\n\n\n\n#### package2 2.0.0\n\n\n- **Severity** 💀 Critical\n- **Package Name:** package2\n- **Current Version:** 2.0.0\n- **Fixed Versions:** 2.0.0,3.0.0\n- **CVE:** CVE-2022-4321\n\n**Description:**\n\nsummary\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[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n[comment]: <> (Checksum: hash)\n" prTitle, prBody = cfp.preparePullRequestDetails("hash", vulnerabilities) assert.Equal(t, utils.GetAggregatedPullRequestTitle(""), prTitle) assert.Equal(t, expectedPrBody, prBody) diff --git a/commands/scanpullrequest.go b/commands/scanpullrequest.go index d2dede312..c525c112f 100644 --- a/commands/scanpullrequest.go +++ b/commands/scanpullrequest.go @@ -58,25 +58,30 @@ func (cmd *ScanPullRequestCmd) Run(configAggregator utils.RepoAggregator, client // a. Audit the dependencies of the source and the target branches. // b. Compare the vulnerabilities found in source and target branches, and show only the new vulnerabilities added by the pull request. // Otherwise, only the source branch is scanned and all found vulnerabilities are being displayed. -func scanPullRequest(repoConfig *utils.Repository, client vcsclient.VcsClient, pullRequestDetails vcsclient.PullRequestInfo) error { +func scanPullRequest(repo *utils.Repository, client vcsclient.VcsClient, pullRequestDetails vcsclient.PullRequestInfo) error { log.Info("Scanning Pull Request ID:", pullRequestDetails.ID, "Source:", pullRequestDetails.Source.Name, "Target:", pullRequestDetails.Target.Name) log.Info("-----------------------------------------------------------") // Audit PR code - vulnerabilitiesRows, iacRows, err := auditPullRequest(repoConfig, client, pullRequestDetails) + vulnerabilitiesRows, iacRows, err := auditPullRequest(repo, client, pullRequestDetails) if err != nil { return err } + // Delete previous Frogbot pull request message if exists + if err = deletePreviousPullRequestMessages(repo, client); err != nil { + return err + } + // Create a pull request message - message := createPullRequestMessage(vulnerabilitiesRows, iacRows, repoConfig.OutputWriter) + message := createPullRequestMessage(vulnerabilitiesRows, iacRows, repo.OutputWriter) // Add comment to the pull request - if err = client.AddPullRequestComment(context.Background(), repoConfig.RepoOwner, repoConfig.RepoName, message, repoConfig.PullRequestID); err != nil { + if err = client.AddPullRequestComment(context.Background(), repo.RepoOwner, repo.RepoName, message, repo.PullRequestID); err != nil { return errors.New("couldn't add pull request comment: " + err.Error()) } // Fail the Frogbot task if a security issue is found and Frogbot isn't configured to avoid the failure. - if repoConfig.FailOnSecurityIssues != nil && *repoConfig.FailOnSecurityIssues && len(vulnerabilitiesRows) > 0 { + if repo.FailOnSecurityIssues != nil && *repo.FailOnSecurityIssues && len(vulnerabilitiesRows) > 0 { err = errors.New(securityIssueFoundErr) } return err @@ -368,3 +373,24 @@ func createPullRequestMessage(vulnerabilitiesRows []formats.VulnerabilityOrViola } return writer.VulnerabiltiesTitle(true) + writer.VulnerabilitiesContent(vulnerabilitiesRows) + writer.IacContent(iacRows) + writer.UntitledForJasMsg() + writer.Footer() } + +func deletePreviousPullRequestMessages(repository *utils.Repository, client vcsclient.VcsClient) error { + comments, err := utils.GetSortedPullRequestComments(client, repository.RepoOwner, repository.RepoName, repository.PullRequestID) + if err != nil { + return err + } + + var commentID int + for _, comment := range comments { + if repository.OutputWriter.IsFrogbotResultComment(comment.Content) { + commentID = int(comment.ID) + break + } + } + + if e := client.DeletePullRequestComment(context.Background(), repository.RepoOwner, repository.RepoName, repository.PullRequestID, commentID); e != nil { + err = errors.Join(err, e) + } + + return err +} diff --git a/commands/scanpullrequest_test.go b/commands/scanpullrequest_test.go index bcd1c291d..e94dab56c 100644 --- a/commands/scanpullrequest_test.go +++ b/commands/scanpullrequest_test.go @@ -459,12 +459,12 @@ func TestCreatePullRequestMessage(t *testing.T) { writerOutput.SetEntitledForJas(true) message := createPullRequestMessage(vulnerabilities, iac, writerOutput) - expectedMessage := "[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.1] |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | github.com/mholt/archiver/v3:v3.5.1 | github.com/mholt/archiver/v3:v3.5.1 | |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableMediumSeverity.png)
Medium | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.3] |\n\n
\n\n## 👇 Details\n\n\n
\n github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/nats-io/nats-streaming-server\n- **Current Version:** v0.21.0\n- **Fixed Version:** [0.24.1]\n- **CVE:** CVE-2022-24450\n\n\n
\n\n\n
\n github.com/mholt/archiver/v3 v3.5.1 \n
\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/mholt/archiver/v3\n- **Current Version:** v3.5.1\n\n\n
\n\n\n
\n github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n- **Severity** 🎃 Medium\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/nats-io/nats-streaming-server\n- **Current Version:** v0.21.0\n- **Fixed Version:** [0.24.3]\n- **CVE:** CVE-2022-26652\n\n\n
\n\n\n## 🛠️ Infrastructure as Code \n\n
\n\n\n| SEVERITY | FILE | LINE:COLUMN | FINDING |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableLowSeverity.png)
Low | test.js | 1:20 | kms_key_id='' was detected |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | test2.js | 4:30 | Deprecated TLS version was detected |\n\n
\n\n\n
\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n" + expectedMessage := "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.1] |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | github.com/mholt/archiver/v3:v3.5.1 | github.com/mholt/archiver/v3:v3.5.1 | |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableMediumSeverity.png)
Medium | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.3] |\n\n
\n\n## 👇 Details\n\n\n
\n github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/nats-io/nats-streaming-server\n- **Current Version:** v0.21.0\n- **Fixed Version:** [0.24.1]\n- **CVE:** CVE-2022-24450\n\n\n
\n\n\n
\n github.com/mholt/archiver/v3 v3.5.1 \n
\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/mholt/archiver/v3\n- **Current Version:** v3.5.1\n\n\n
\n\n\n
\n github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n- **Severity** 🎃 Medium\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/nats-io/nats-streaming-server\n- **Current Version:** v0.21.0\n- **Fixed Version:** [0.24.3]\n- **CVE:** CVE-2022-26652\n\n\n
\n\n\n## 🛠️ Infrastructure as Code \n\n
\n\n\n| SEVERITY | FILE | LINE:COLUMN | FINDING |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableLowSeverity.png)
Low | test.js | 1:20 | kms_key_id='' was detected |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | test2.js | 4:30 | Deprecated TLS version was detected |\n\n
\n\n\n
\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n" assert.Equal(t, expectedMessage, message) writerOutput.SetVcsProvider(vcsutils.GitLab) message = createPullRequestMessage(vulnerabilities, iac, writerOutput) - expectedMessage = "[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerMR.png)](https://github.com/jfrog/frogbot#readme)\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.1] |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | github.com/mholt/archiver/v3:v3.5.1 | github.com/mholt/archiver/v3:v3.5.1 | |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableMediumSeverity.png)
Medium | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.3] |\n\n
\n\n## 👇 Details\n\n\n
\n github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/nats-io/nats-streaming-server\n- **Current Version:** v0.21.0\n- **Fixed Version:** [0.24.1]\n- **CVE:** CVE-2022-24450\n\n\n
\n\n\n
\n github.com/mholt/archiver/v3 v3.5.1 \n
\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/mholt/archiver/v3\n- **Current Version:** v3.5.1\n\n\n
\n\n\n
\n github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n- **Severity** 🎃 Medium\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/nats-io/nats-streaming-server\n- **Current Version:** v0.21.0\n- **Fixed Version:** [0.24.3]\n- **CVE:** CVE-2022-26652\n\n\n
\n\n\n## 🛠️ Infrastructure as Code \n\n
\n\n\n| SEVERITY | FILE | LINE:COLUMN | FINDING |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableLowSeverity.png)
Low | test.js | 1:20 | kms_key_id='' was detected |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | test2.js | 4:30 | Deprecated TLS version was detected |\n\n
\n\n\n
\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n" + expectedMessage = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerMR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.1] |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | github.com/mholt/archiver/v3:v3.5.1 | github.com/mholt/archiver/v3:v3.5.1 | |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableMediumSeverity.png)
Medium | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.3] |\n\n
\n\n## 👇 Details\n\n\n
\n github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/nats-io/nats-streaming-server\n- **Current Version:** v0.21.0\n- **Fixed Version:** [0.24.1]\n- **CVE:** CVE-2022-24450\n\n\n
\n\n\n
\n github.com/mholt/archiver/v3 v3.5.1 \n
\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/mholt/archiver/v3\n- **Current Version:** v3.5.1\n\n\n
\n\n\n
\n github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n- **Severity** 🎃 Medium\n- **Contextual Analysis:** Undetermined\n- **Package Name:** github.com/nats-io/nats-streaming-server\n- **Current Version:** v0.21.0\n- **Fixed Version:** [0.24.3]\n- **CVE:** CVE-2022-26652\n\n\n
\n\n\n## 🛠️ Infrastructure as Code \n\n
\n\n\n| SEVERITY | FILE | LINE:COLUMN | FINDING |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableLowSeverity.png)
Low | test.js | 1:20 | kms_key_id='' was detected |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | test2.js | 4:30 | Deprecated TLS version was detected |\n\n
\n\n\n
\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n" assert.Equal(t, expectedMessage, message) } @@ -638,29 +638,26 @@ func TestScanPullRequestError(t *testing.T) { // Create HTTP handler to mock GitLab server func createGitLabHandler(t *testing.T, projectName string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - switch r.RequestURI { + switch { // Return 200 on ping - case "/api/v4/": + case r.RequestURI == "/api/v4/": w.WriteHeader(http.StatusOK) - return // Mimic get pull request by ID - case fmt.Sprintf("/api/v4/projects/jfrog%s/merge_requests/1", "%2F"+projectName): + case r.RequestURI == fmt.Sprintf("/api/v4/projects/jfrog%s/merge_requests/1", "%2F"+projectName): w.WriteHeader(http.StatusOK) expectedResponse, err := os.ReadFile(filepath.Join("..", "expectedPullRequestDetailsResponse.json")) assert.NoError(t, err) _, err = w.Write(expectedResponse) assert.NoError(t, err) - return // Mimic download specific branch to scan - case fmt.Sprintf("/api/v4/projects/jfrog%s/repository/archive.tar.gz?sha=%s", "%2F"+projectName, testSourceBranchName): + case r.RequestURI == fmt.Sprintf("/api/v4/projects/jfrog%s/repository/archive.tar.gz?sha=%s", "%2F"+projectName, testSourceBranchName): w.WriteHeader(http.StatusOK) repoFile, err := os.ReadFile(filepath.Join("..", projectName, "sourceBranch.gz")) assert.NoError(t, err) _, err = w.Write(repoFile) assert.NoError(t, err) - return // Download repository mock - case fmt.Sprintf("/api/v4/projects/jfrog%s/repository/archive.tar.gz?sha=%s", "%2F"+projectName, testTargetBranchName): + case r.RequestURI == fmt.Sprintf("/api/v4/projects/jfrog%s/repository/archive.tar.gz?sha=%s", "%2F"+projectName, testTargetBranchName): w.WriteHeader(http.StatusOK) repoFile, err := os.ReadFile(filepath.Join("..", projectName, "targetBranch.gz")) assert.NoError(t, err) @@ -668,13 +665,19 @@ func createGitLabHandler(t *testing.T, projectName string) http.HandlerFunc { assert.NoError(t, err) return // clean-test-proj should not include any vulnerabilities so assertion is not needed. - case fmt.Sprintf("/api/v4/projects/jfrog%s/merge_requests/1/notes", "%2Fclean-test-proj"): + case r.RequestURI == fmt.Sprintf("/api/v4/projects/jfrog%s/merge_requests/1/notes", "%2Fclean-test-proj") && r.Method == http.MethodPost: w.WriteHeader(http.StatusOK) _, err := w.Write([]byte("{}")) assert.NoError(t, err) return + case r.RequestURI == fmt.Sprintf("/api/v4/projects/jfrog%s/merge_requests/1/notes", "%2Fclean-test-proj") && r.Method == http.MethodGet: + w.WriteHeader(http.StatusOK) + comments, err := os.ReadFile(filepath.Join("..", "commits.json")) + assert.NoError(t, err) + _, err = w.Write(comments) + assert.NoError(t, err) // Return 200 when using the REST that creates the comment - case fmt.Sprintf("/api/v4/projects/jfrog%s/merge_requests/1/notes", "%2F"+projectName): + case r.RequestURI == fmt.Sprintf("/api/v4/projects/jfrog%s/merge_requests/1/notes", "%2F"+projectName) && r.Method == http.MethodPost: buf := new(bytes.Buffer) _, err := buf.ReadFrom(r.Body) assert.NoError(t, err) @@ -695,7 +698,12 @@ func createGitLabHandler(t *testing.T, projectName string) http.HandlerFunc { w.WriteHeader(http.StatusOK) _, err = w.Write([]byte("{}")) assert.NoError(t, err) - return + case r.RequestURI == fmt.Sprintf("/api/v4/projects/jfrog%s/merge_requests/1/notes", "%2F"+projectName) && r.Method == http.MethodGet: + w.WriteHeader(http.StatusOK) + comments, err := os.ReadFile(filepath.Join("..", "commits.json")) + assert.NoError(t, err) + _, err = w.Write(comments) + assert.NoError(t, err) } } } diff --git a/commands/scanpullrequests.go b/commands/scanpullrequests.go index d311aae0c..648977551 100644 --- a/commands/scanpullrequests.go +++ b/commands/scanpullrequests.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "github.com/jfrog/jfrog-client-go/utils/log" - "sort" "strings" "github.com/jfrog/frogbot/commands/utils" @@ -58,14 +57,10 @@ func scanAllPullRequests(repo utils.Repository, client vcsclient.VcsClient) (err } func shouldScanPullRequest(repo utils.Repository, client vcsclient.VcsClient, prID int) (shouldScan bool, err error) { - pullRequestsComments, err := client.ListPullRequestComments(context.Background(), repo.RepoOwner, repo.RepoName, prID) + pullRequestsComments, err := utils.GetSortedPullRequestComments(client, repo.RepoOwner, repo.RepoName, prID) if err != nil { return } - // Sort the comment according to time created, the newest comment should be the first one. - sort.Slice(pullRequestsComments, func(i, j int) bool { - return pullRequestsComments[i].Created.After(pullRequestsComments[j].Created) - }) for _, comment := range pullRequestsComments { // If this a 're-scan' request comment diff --git a/commands/scanpullrequests_test.go b/commands/scanpullrequests_test.go index dd24678b8..e4b717643 100644 --- a/commands/scanpullrequests_test.go +++ b/commands/scanpullrequests_test.go @@ -126,13 +126,13 @@ func TestScanAllPullRequestsMultiRepo(t *testing.T) { } configAggregator := utils.RepoAggregator{ - { - OutputWriter: &utils.SimplifiedOutput{}, + utils.Repository{ + OutputWriter: &utils.StandardOutput{}, Server: server, Params: firstRepoParams, }, - { - OutputWriter: &utils.SimplifiedOutput{}, + utils.Repository{ + OutputWriter: &utils.StandardOutput{}, Server: server, Params: secondRepoParams, }, @@ -147,6 +147,14 @@ func TestScanAllPullRequestsMultiRepo(t *testing.T) { err := scanAllPullRequestsCmd.Run(configAggregator, client) assert.NoError(t, err) assert.Len(t, frogbotMessages, 4) + expectedMessage := "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableCritical.png)
Critical | Not Applicable |minimist:1.2.5 | minimist:1.2.5 | [0.2.4]

[1.2.6] |\n\n
\n\n## 👇 Details\n\n\n\n\n- **Severity** 💀 Critical\n- **Contextual Analysis:** Not Applicable\n- **Package Name:** minimist\n- **Current Version:** 1.2.5\n- **Fixed Versions:** [0.2.4],[1.2.6]\n- **CVE:** CVE-2021-44906\n\n**Description:**\n\n[Minimist](https://github.com/substack/minimist) is a simple and very popular argument parser. It is used by more than 14 million by Mar 2022. This package developers stopped developing it since April 2020 and its community released a [newer version](https://github.com/meszaros-lajos-gyorgy/minimist-lite) supported by the community.\n\n\nAn incomplete fix for [CVE-2020-7598](https://nvd.nist.gov/vuln/detail/CVE-2020-7598) partially blocked prototype pollution attacks. Researchers discovered that it does not check for constructor functions which means they can be overridden. This behavior can be triggered easily when using it insecurely (which is the common usage). For example:\n```\nvar argv = parse(['--_.concat.constructor.prototype.y', '123']);\nt.equal((function(){}).foo, undefined);\nt.equal(argv.y, undefined);\n```\nIn this example, `prototype.y` is assigned with `123` which will be derived to every newly created object. \n\nThis vulnerability can be triggered when the attacker-controlled input is parsed using Minimist without any validation. As always with prototype pollution, the impact depends on the code that follows the attack, but denial of service is almost always guaranteed.\n\n**Remediation:**\n\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n\n\n
\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n" + assert.Equal(t, expectedMessage, frogbotMessages[0]) + expectedMessage = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/noVulnerabilityBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n
\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n" + assert.Equal(t, expectedMessage, frogbotMessages[1]) + expectedMessage = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined |pip-example:1.2.3 | pyjwt:1.7.1 | [2.4.0] |\n\n
\n\n## 👇 Details\n\n\n\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** pyjwt\n- **Current Version:** 1.7.1\n- **Fixed Version:** [2.4.0]\n- **CVE:** CVE-2022-29217\n\n**Description:**\n\n[PyJWT](https://pypi.org/project/PyJWT) is a Python implementation of the RFC 7519 standard (JSON Web Tokens). [JSON Web Tokens](https://jwt.io/) are an open, industry standard method for representing claims securely between two parties. A JWT comes with an inline signature that is meant to be verified by the receiving application. JWT supports multiple standard algorithms, and the algorithm itself is **specified in the JWT token itself**.\n\nThe PyJWT library uses the signature-verification algorithm that is specified in the JWT token (that is completely attacker-controlled), however - it requires the validating application to pass an `algorithms` kwarg that specifies the expected algorithms in order to avoid key confusion. Unfortunately - a non-default value `algorithms=jwt.algorithms.get_default_algorithms()` exists that allows all algorithms.\nThe PyJWT library also tries to mitigate key confusions in this case, by making sure that public keys are not used as an HMAC secret. For example, HMAC secrets that begin with `-----BEGIN PUBLIC KEY-----` are rejected when encoding a JWT.\n\nIt has been discovered that due to missing key-type checks, in cases where -\n1. The vulnerable application expects to receive a JWT signed with an Elliptic-Curve key (one of the algorithms `ES256`, `ES384`, `ES512`, `EdDSA`)\n2. The vulnerable application decodes the JWT token using the non-default kwarg `algorithms=jwt.algorithms.get_default_algorithms()` (or alternatively, `algorithms` contain both an HMAC-based algorithm and an EC-based algorithm)\n\nAn attacker can create an HMAC-signed (ex. `HS256`) JWT token, using the (well-known!) EC public key as the HMAC key. The validating application will accept this JWT token as a valid token.\n\nFor example, an application might have planned to validate an `EdDSA`-signed token that was generated as follows -\n```python\n# Making a good jwt token that should work by signing it with the private key\nencoded_good = jwt.encode({\"test\": 1234}, priv_key_bytes, algorithm=\"EdDSA\")\n```\nAn attacker in posession of the public key can generate an `HMAC`-signed token to confuse PyJWT - \n```python\n# Using HMAC with the public key to trick the receiver to think that the public key is a HMAC secret\nencoded_bad = jwt.encode({\"test\": 1234}, pub_key_bytes, algorithm=\"HS256\")\n```\n\nThe following vulnerable `decode` call will accept BOTH of the above tokens as valid - \n```\ndecoded = jwt.decode(encoded_good, pub_key_bytes, \nalgorithms=jwt.algorithms.get_default_algorithms())\n```\n\n**Remediation:**\n\n##### Development mitigations\n\nUse a specific algorithm instead of `jwt.algorithms.get_default_algorithms`.\nFor example, replace the following call - \n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=jwt.algorithms.get_default_algorithms())`\nWith -\n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=[\"ES256\"])`\n\n\n\n\n
\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n" + assert.Equal(t, expectedMessage, frogbotMessages[2]) + expectedMessage = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/noVulnerabilityBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n
\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n" + assert.Equal(t, expectedMessage, frogbotMessages[3]) } func TestScanAllPullRequests(t *testing.T) { @@ -180,6 +188,10 @@ func TestScanAllPullRequests(t *testing.T) { err := scanAllPullRequestsCmd.Run(paramsAggregator, client) assert.NoError(t, err) assert.Len(t, frogbotMessages, 2) + expectedMessage := "**🚨 Frogbot scanned this pull request and found the below:**\n\n---\n## 📦 Vulnerable Dependencies\n---\n\n### ✍️ Summary \n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| Critical | Not Applicable | minimist:1.2.5 | minimist:1.2.5 | [0.2.4], [1.2.6] |\n\n---\n### 👇 Details\n---\n\n\n#### minimist 1.2.5\n\n\n- **Severity** 💀 Critical\n- **Contextual Analysis:** Not Applicable\n- **Package Name:** minimist\n- **Current Version:** 1.2.5\n- **Fixed Versions:** [0.2.4],[1.2.6]\n- **CVE:** CVE-2021-44906\n\n**Description:**\n\n[Minimist](https://github.com/substack/minimist) is a simple and very popular argument parser. It is used by more than 14 million by Mar 2022. This package developers stopped developing it since April 2020 and its community released a [newer version](https://github.com/meszaros-lajos-gyorgy/minimist-lite) supported by the community.\n\n\nAn incomplete fix for [CVE-2020-7598](https://nvd.nist.gov/vuln/detail/CVE-2020-7598) partially blocked prototype pollution attacks. Researchers discovered that it does not check for constructor functions which means they can be overridden. This behavior can be triggered easily when using it insecurely (which is the common usage). For example:\n```\nvar argv = parse(['--_.concat.constructor.prototype.y', '123']);\nt.equal((function(){}).foo, undefined);\nt.equal(argv.y, undefined);\n```\nIn this example, `prototype.y` is assigned with `123` which will be derived to every newly created object. \n\nThis vulnerability can be triggered when the attacker-controlled input is parsed using Minimist without any validation. As always with prototype pollution, the impact depends on the code that follows the attack, but denial of service is almost always guaranteed.\n\n**Remediation:**\n\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n\n\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)" + assert.Equal(t, expectedMessage, frogbotMessages[0]) + expectedMessage = "**👍 Frogbot scanned this pull request and found that it did not add vulnerable dependencies.** \n\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)" + assert.Equal(t, expectedMessage, frogbotMessages[1]) } func getMockClient(t *testing.T, frogbotMessages *[]string, mockParams ...MockParams) *testdata.MockVcsClient { @@ -199,6 +211,7 @@ func getMockClient(t *testing.T, frogbotMessages *[]string, mockParams ...MockPa *frogbotMessages = append(*frogbotMessages, content) return nil }).AnyTimes() + client.EXPECT().DeletePullRequestComment(context.Background(), params.repoOwner, params.repoName, gomock.Any(), gomock.Any()).Return(nil).AnyTimes() // Return private repositories visibility client.EXPECT().GetRepositoryInfo(context.Background(), gomock.Any(), gomock.Any()).Return(vcsclient.RepositoryInfo{RepositoryVisibility: vcsclient.Private}, nil).AnyTimes() } diff --git a/commands/testdata/messages/novulnerabilities.md b/commands/testdata/messages/novulnerabilities.md index d80599e7b..59a0c4b1a 100644 --- a/commands/testdata/messages/novulnerabilities.md +++ b/commands/testdata/messages/novulnerabilities.md @@ -1,7 +1,13 @@ +
+ [![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/noVulnerabilityBannerPR.png)](https://github.com/jfrog/frogbot#readme) + +
+ +
-**Frogbot** also supports **Contextual Analysis**. This feature is included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system. +**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.
diff --git a/commands/testdata/messages/novulnerabilitiesMR.md b/commands/testdata/messages/novulnerabilitiesMR.md index 7c0ec2ab8..ccd40cc6f 100644 --- a/commands/testdata/messages/novulnerabilitiesMR.md +++ b/commands/testdata/messages/novulnerabilitiesMR.md @@ -1,7 +1,13 @@ +
+ [![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/noVulnerabilityBannerMR.png)](https://github.com/jfrog/frogbot#readme) + +
+ +
-**Frogbot** also supports **Contextual Analysis**. This feature is included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system. +**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.
diff --git a/commands/testdata/scanpullrequest/commits.json b/commands/testdata/scanpullrequest/commits.json new file mode 100644 index 000000000..721616e33 --- /dev/null +++ b/commands/testdata/scanpullrequest/commits.json @@ -0,0 +1,77 @@ +[ + { + "id": 1487055035, + "type": null, + "body": "added 1 commit\n\n\u003cul\u003e\u003cli\u003e99ef9ac7 - merge\u003c/li\u003e\u003c/ul\u003e\n\n[Compare with previous version](/test/multi-example-project/-/merge_requests/1/diffs?diff_id=743652694\u0026start_sha=e2dc35785eec29f35b2aae95d39df2b99db2274e)", + "attachment": null, + "author": { + "id": 13377328, + "username": "test", + "name": "Test", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/005f2d268f06e85fcae3e48c96217dd3?s=80\u0026d=identicon", + "web_url": "https://gitlab.com/test" + }, + "created_at": "2023-07-25T12:28:13.095Z", + "updated_at": "2023-07-25T12:28:13.097Z", + "system": true, + "noteable_id": 218824340, + "noteable_type": "MergeRequest", + "project_id": 45341022, + "resolvable": false, + "confidential": false, + "internal": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 1419499611, + "type": null, + "body": "\u003cdetails\u003e\n\u003csummary\u003e\u003ch4\u003elodash 4.17.0\u003ch4\u003e\u003c/summary\u003e\n\n## Vulnerability Details\n\n- **Severity:** 👌 High\n- **Contextual Analysis:** Not Applicable\n- **Package Name:** lodash\n- **Current Version:** 4.17.19\n- **Upgrade to Version:** 4.17.20\n- **CVEs:** CVE-2020-8203\n\n**Description:**\n\n[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.\n\n**Remediation:**\n##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases.\n\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ch4\u003eprotobufjs 6.11.12\u003ch4\u003e\u003c/summary\u003e\n\n## Vulnerability Details\n\n- **Severity:** 🔥 High\n- **Contextual Analysis:** Applicable\n- **Package Name:** protobufjs\n- **Current Version:** 6.11.2\n- **Upgrade to Version:** 6.11.3\n- **CVEs:** CVE-2022-25878\n\n**Description:**\n\n[Protocol Buffers](https://developers.google.com/protocol-buffers) or \"protobufs\" are a language-neutral, platform-neutral, extensible way of serializing structured data. [protobuf.js](https://www.npmjs.com/package/protobufjs) is a JavaScript library that allows creating and consuming protobufs.\n\nMultiple prototype pollution vulnerabilities were detected in the `protobuf.js` library. Namely these can occur when:\n1. `util.setProperty` receives untrusted input in arguments 2 \u0026 3 -\n```js\nprotobuf.util.setProperty({}, \"__proto__.someprop\", \"somevalue\");\n```\n\n2. `ReflectionObject.setParsedOption` receives untrusted input in arguments 2 \u0026 3\n```js\nlet obj = new protobuf.ReflectionObject(\"Test\")\nobj.setParsedOption({}, \"somevalue\", \"__proto__.someprop\");\n```\n\n3. `parse` receives untrusted input (an untrusted `.proto` definition) -\n```js\nlet p = `option (foo).__proto__.someprop= \"somevalue\";` \nprotobuf.parse(p)\n```\n\n4. `load` receives an untrusted `.proto` file -\n```js\nprotobuf.load(\"/path/to/untrusted.proto\", function(err, root) { ... });\n```\n\n**Remediation:**\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n\u003c/details\u003e\n\n---\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/vulnerabilitiesBanner.png)](https://github.com/jfrog/frogbot#readme)\n\n[What is Frogbot?](https://github.com/jfrog/frogbot#readme)", + "attachment": null, + "author": { + "id": 13377328, + "username": "test", + "name": "Test", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/005f2d268f06e85fcae3e48c96217dd3?s=80\u0026d=identicon", + "web_url": "https://gitlab.com/test" + }, + "created_at": "2023-06-06T08:30:07.783Z", + "updated_at": "2023-06-06T08:31:11.997Z", + "system": false, + "noteable_id": 218824340, + "noteable_type": "MergeRequest", + "project_id": 45341022, + "resolvable": false, + "confidential": false, + "internal": false, + "noteable_iid": 1, + "commands_changes": {} + }, + { + "id": 1417804152, + "type": null, + "body": "## Vulnerability Details\n\n- **Severity:** High\n- **Contextual Analysis:** $\\color{red}{\\textsf{Applicable}}$\n- **Package Name:** protobufjs\n- **Current Version:** 6.11.2\n- **Upgrade to Version:** 6.11.3\n- **CVEs:** CVE-2022-25878\n\n**Summary:**\n\n[Protocol Buffers](https://developers.google.com/protocol-buffers) or \"protobufs\" are a language-neutral, platform-neutral, extensible way of serializing structured data. [protobuf.js](https://www.npmjs.com/package/protobufjs) is a JavaScript library that allows creating and consuming protobufs.\n\nMultiple prototype pollution vulnerabilities were detected in the `protobuf.js` library. Namely these can occur when:\n1. `util.setProperty` receives untrusted input in arguments 2 \u0026 3 -\n```js\nprotobuf.util.setProperty({}, \"__proto__.someprop\", \"somevalue\");\n```\n\n2. `ReflectionObject.setParsedOption` receives untrusted input in arguments 2 \u0026 3\n```js\nlet obj = new protobuf.ReflectionObject(\"Test\")\nobj.setParsedOption({}, \"somevalue\", \"__proto__.someprop\");\n```\n\n3. `parse` receives untrusted input (an untrusted `.proto` definition) -\n```js\nlet p = `option (foo).__proto__.someprop= \"somevalue\";` \nprotobuf.parse(p)\n```\n\n4. `load` receives an untrusted `.proto` file -\n```js\nprotobuf.load(\"/path/to/untrusted.proto\", function(err, root) { ... });\n```\n\n**Remediation:**\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.", + "attachment": null, + "author": { + "id": 13377328, + "username": "test", + "name": "Test", + "state": "active", + "avatar_url": "https://secure.gravatar.com/avatar/005f2d268f06e85fcae3e48c96217dd3?s=80\u0026d=identicon", + "web_url": "https://gitlab.com/test" + }, + "created_at": "2023-06-05T07:51:05.607Z", + "updated_at": "2023-06-11T12:51:06.872Z", + "system": false, + "noteable_id": 218824340, + "noteable_type": "MergeRequest", + "project_id": 45341022, + "resolvable": false, + "confidential": false, + "internal": false, + "noteable_iid": 1, + "commands_changes": {} + } +] \ No newline at end of file diff --git a/commands/testdata/scanpullrequest/expectedResponse.json b/commands/testdata/scanpullrequest/expectedResponse.json index 13f7063a6..d76a2e437 100644 --- a/commands/testdata/scanpullrequest/expectedResponse.json +++ b/commands/testdata/scanpullrequest/expectedResponse.json @@ -1 +1,3 @@ -{"body":"[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n\u003cdiv align=\"center\"\u003e\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableCritical.png)\u003cbr\u003eCritical | Not Applicable |minimist:1.2.5 | minimist:1.2.5 | [0.2.4]\u003cbr\u003e\u003cbr\u003e[1.2.6] |\n\n\u003c/div\u003e\n\n## 👇 Details\n\n\n\n\n- **Severity** 💀 Critical\n- **Contextual Analysis:** Not Applicable\n- **Package Name:** minimist\n- **Current Version:** 1.2.5\n- **Fixed Versions:** [0.2.4],[1.2.6]\n- **CVE:** CVE-2021-44906\n\n**Description:**\n\n[Minimist](https://github.com/substack/minimist) is a simple and very popular argument parser. It is used by more than 14 million by Mar 2022. This package developers stopped developing it since April 2020 and its community released a [newer version](https://github.com/meszaros-lajos-gyorgy/minimist-lite) supported by the community.\n\n\nAn incomplete fix for [CVE-2020-7598](https://nvd.nist.gov/vuln/detail/CVE-2020-7598) partially blocked prototype pollution attacks. Researchers discovered that it does not check for constructor functions which means they can be overridden. This behavior can be triggered easily when using it insecurely (which is the common usage). For example:\n```\nvar argv = parse(['--_.concat.constructor.prototype.y', '123']);\nt.equal((function(){}).foo, undefined);\nt.equal(argv.y, undefined);\n```\nIn this example, `prototype.y` is assigned with `123` which will be derived to every newly created object. \n\nThis vulnerability can be triggered when the attacker-controlled input is parsed using Minimist without any validation. As always with prototype pollution, the impact depends on the code that follows the attack, but denial of service is almost always guaranteed.\n\n**Remediation:**\n\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n\n\n\u003cdiv align=\"center\"\u003e\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e\n"} \ No newline at end of file +{ + "body": "\u003cdiv align='center'\u003e\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n\u003cdiv align=\"center\"\u003e\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableCritical.png)\u003cbr\u003eCritical | Not Applicable |minimist:1.2.5 | minimist:1.2.5 | [0.2.4]\u003cbr\u003e\u003cbr\u003e[1.2.6] |\n\n\u003c/div\u003e\n\n## 👇 Details\n\n\n\n\n- **Severity** 💀 Critical\n- **Contextual Analysis:** Not Applicable\n- **Package Name:** minimist\n- **Current Version:** 1.2.5\n- **Fixed Versions:** [0.2.4],[1.2.6]\n- **CVE:** CVE-2021-44906\n\n**Description:**\n\n[Minimist](https://github.com/substack/minimist) is a simple and very popular argument parser. It is used by more than 14 million by Mar 2022. This package developers stopped developing it since April 2020 and its community released a [newer version](https://github.com/meszaros-lajos-gyorgy/minimist-lite) supported by the community.\n\n\nAn incomplete fix for [CVE-2020-7598](https://nvd.nist.gov/vuln/detail/CVE-2020-7598) partially blocked prototype pollution attacks. Researchers discovered that it does not check for constructor functions which means they can be overridden. This behavior can be triggered easily when using it insecurely (which is the common usage). For example:\n```\nvar argv = parse(['--_.concat.constructor.prototype.y', '123']);\nt.equal((function(){}).foo, undefined);\nt.equal(argv.y, undefined);\n```\nIn this example, `prototype.y` is assigned with `123` which will be derived to every newly created object. \n\nThis vulnerability can be triggered when the attacker-controlled input is parsed using Minimist without any validation. As always with prototype pollution, the impact depends on the code that follows the attack, but denial of service is almost always guaranteed.\n\n**Remediation:**\n\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n\n\n\u003cdiv align=\"center\"\u003e\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e\n" +} \ No newline at end of file diff --git a/commands/testdata/scanpullrequest/expectedResponseMultiDir.json b/commands/testdata/scanpullrequest/expectedResponseMultiDir.json index 78070e639..0b7e72e38 100644 --- a/commands/testdata/scanpullrequest/expectedResponseMultiDir.json +++ b/commands/testdata/scanpullrequest/expectedResponseMultiDir.json @@ -1 +1,3 @@ -{"body":"[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n\u003cdiv align=\"center\"\u003e\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableHigh.png)\u003cbr\u003e High | Not Applicable |minimatch:3.0.4 | minimatch:3.0.4 | [3.0.5] |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)\u003cbr\u003e High | Undetermined |pyjwt:1.7.1 | pyjwt:1.7.1 | [2.4.0] |\n\n\u003c/div\u003e\n\n## 👇 Details\n\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003cb\u003eminimatch 3.0.4\u003c/b\u003e \u003c/summary\u003e\n\u003cbr\u003e\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Not Applicable\n- **Package Name:** minimatch\n- **Current Version:** 3.0.4\n- **Fixed Version:** [3.0.5]\n- **CVE:** CVE-2022-3517\n\n**Description:**\n\nA vulnerability was found in the minimatch package. This flaw allows a Regular Expression Denial of Service (ReDoS) when calling the braceExpand function with specific arguments, resulting in a Denial of Service.\n\n\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003cb\u003epyjwt 1.7.1\u003c/b\u003e \u003c/summary\u003e\n\u003cbr\u003e\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** pyjwt\n- **Current Version:** 1.7.1\n- **Fixed Version:** [2.4.0]\n- **CVE:** CVE-2022-29217\n\n**Description:**\n\n[PyJWT](https://pypi.org/project/PyJWT) is a Python implementation of the RFC 7519 standard (JSON Web Tokens). [JSON Web Tokens](https://jwt.io/) are an open, industry standard method for representing claims securely between two parties. A JWT comes with an inline signature that is meant to be verified by the receiving application. JWT supports multiple standard algorithms, and the algorithm itself is **specified in the JWT token itself**.\n\nThe PyJWT library uses the signature-verification algorithm that is specified in the JWT token (that is completely attacker-controlled), however - it requires the validating application to pass an `algorithms` kwarg that specifies the expected algorithms in order to avoid key confusion. Unfortunately - a non-default value `algorithms=jwt.algorithms.get_default_algorithms()` exists that allows all algorithms.\nThe PyJWT library also tries to mitigate key confusions in this case, by making sure that public keys are not used as an HMAC secret. For example, HMAC secrets that begin with `-----BEGIN PUBLIC KEY-----` are rejected when encoding a JWT.\n\nIt has been discovered that due to missing key-type checks, in cases where -\n1. The vulnerable application expects to receive a JWT signed with an Elliptic-Curve key (one of the algorithms `ES256`, `ES384`, `ES512`, `EdDSA`)\n2. The vulnerable application decodes the JWT token using the non-default kwarg `algorithms=jwt.algorithms.get_default_algorithms()` (or alternatively, `algorithms` contain both an HMAC-based algorithm and an EC-based algorithm)\n\nAn attacker can create an HMAC-signed (ex. `HS256`) JWT token, using the (well-known!) EC public key as the HMAC key. The validating application will accept this JWT token as a valid token.\n\nFor example, an application might have planned to validate an `EdDSA`-signed token that was generated as follows -\n```python\n# Making a good jwt token that should work by signing it with the private key\nencoded_good = jwt.encode({\"test\": 1234}, priv_key_bytes, algorithm=\"EdDSA\")\n```\nAn attacker in posession of the public key can generate an `HMAC`-signed token to confuse PyJWT - \n```python\n# Using HMAC with the public key to trick the receiver to think that the public key is a HMAC secret\nencoded_bad = jwt.encode({\"test\": 1234}, pub_key_bytes, algorithm=\"HS256\")\n```\n\nThe following vulnerable `decode` call will accept BOTH of the above tokens as valid - \n```\ndecoded = jwt.decode(encoded_good, pub_key_bytes, \nalgorithms=jwt.algorithms.get_default_algorithms())\n```\n\n**Remediation:**\n\n##### Development mitigations\n\nUse a specific algorithm instead of `jwt.algorithms.get_default_algorithms`.\nFor example, replace the following call - \n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=jwt.algorithms.get_default_algorithms())`\nWith -\n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=[\"ES256\"])`\n\n\n\n\u003c/details\u003e\n\n\n\u003cdiv align=\"center\"\u003e\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e\n"} \ No newline at end of file +{ + "body": "\u003cdiv align='center'\u003e\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n\u003cdiv align=\"center\"\u003e\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableHigh.png)\u003cbr\u003e High | Not Applicable |minimatch:3.0.4 | minimatch:3.0.4 | [3.0.5] |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)\u003cbr\u003e High | Undetermined |pyjwt:1.7.1 | pyjwt:1.7.1 | [2.4.0] |\n\n\u003c/div\u003e\n\n## 👇 Details\n\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003cb\u003eminimatch 3.0.4\u003c/b\u003e \u003c/summary\u003e\n\u003cbr\u003e\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Not Applicable\n- **Package Name:** minimatch\n- **Current Version:** 3.0.4\n- **Fixed Version:** [3.0.5]\n- **CVE:** CVE-2022-3517\n\n**Description:**\n\nA vulnerability was found in the minimatch package. This flaw allows a Regular Expression Denial of Service (ReDoS) when calling the braceExpand function with specific arguments, resulting in a Denial of Service.\n\n\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003cb\u003epyjwt 1.7.1\u003c/b\u003e \u003c/summary\u003e\n\u003cbr\u003e\n\n- **Severity** 🔥 High\n- **Contextual Analysis:** Undetermined\n- **Package Name:** pyjwt\n- **Current Version:** 1.7.1\n- **Fixed Version:** [2.4.0]\n- **CVE:** CVE-2022-29217\n\n**Description:**\n\n[PyJWT](https://pypi.org/project/PyJWT) is a Python implementation of the RFC 7519 standard (JSON Web Tokens). [JSON Web Tokens](https://jwt.io/) are an open, industry standard method for representing claims securely between two parties. A JWT comes with an inline signature that is meant to be verified by the receiving application. JWT supports multiple standard algorithms, and the algorithm itself is **specified in the JWT token itself**.\n\nThe PyJWT library uses the signature-verification algorithm that is specified in the JWT token (that is completely attacker-controlled), however - it requires the validating application to pass an `algorithms` kwarg that specifies the expected algorithms in order to avoid key confusion. Unfortunately - a non-default value `algorithms=jwt.algorithms.get_default_algorithms()` exists that allows all algorithms.\nThe PyJWT library also tries to mitigate key confusions in this case, by making sure that public keys are not used as an HMAC secret. For example, HMAC secrets that begin with `-----BEGIN PUBLIC KEY-----` are rejected when encoding a JWT.\n\nIt has been discovered that due to missing key-type checks, in cases where -\n1. The vulnerable application expects to receive a JWT signed with an Elliptic-Curve key (one of the algorithms `ES256`, `ES384`, `ES512`, `EdDSA`)\n2. The vulnerable application decodes the JWT token using the non-default kwarg `algorithms=jwt.algorithms.get_default_algorithms()` (or alternatively, `algorithms` contain both an HMAC-based algorithm and an EC-based algorithm)\n\nAn attacker can create an HMAC-signed (ex. `HS256`) JWT token, using the (well-known!) EC public key as the HMAC key. The validating application will accept this JWT token as a valid token.\n\nFor example, an application might have planned to validate an `EdDSA`-signed token that was generated as follows -\n```python\n# Making a good jwt token that should work by signing it with the private key\nencoded_good = jwt.encode({\"test\": 1234}, priv_key_bytes, algorithm=\"EdDSA\")\n```\nAn attacker in posession of the public key can generate an `HMAC`-signed token to confuse PyJWT - \n```python\n# Using HMAC with the public key to trick the receiver to think that the public key is a HMAC secret\nencoded_bad = jwt.encode({\"test\": 1234}, pub_key_bytes, algorithm=\"HS256\")\n```\n\nThe following vulnerable `decode` call will accept BOTH of the above tokens as valid - \n```\ndecoded = jwt.decode(encoded_good, pub_key_bytes, \nalgorithms=jwt.algorithms.get_default_algorithms())\n```\n\n**Remediation:**\n\n##### Development mitigations\n\nUse a specific algorithm instead of `jwt.algorithms.get_default_algorithms`.\nFor example, replace the following call - \n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=jwt.algorithms.get_default_algorithms())`\nWith -\n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=[\"ES256\"])`\n\n\n\n\u003c/details\u003e\n\n\n\u003cdiv align=\"center\"\u003e\n\n[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e\n" +} \ No newline at end of file diff --git a/commands/utils/icons.go b/commands/utils/icons.go index 6f89a2fa9..96ae79926 100644 --- a/commands/utils/icons.go +++ b/commands/utils/icons.go @@ -41,7 +41,8 @@ func getApplicableIconTags(iconName IconName) string { } func GetBanner(banner ImageSource) string { - return "[" + GetIconTag(banner) + "](https://github.com/jfrog/frogbot#readme)" + formattedBanner := "[" + GetIconTag(banner) + "](https://github.com/jfrog/frogbot#readme)" + return fmt.Sprintf("
\n\n%s\n\n
\n\n", formattedBanner) } func GetIconTag(imageSource ImageSource) string { diff --git a/commands/utils/icons_test.go b/commands/utils/icons_test.go index 7ac6c50c6..5e37bbe51 100644 --- a/commands/utils/icons_test.go +++ b/commands/utils/icons_test.go @@ -23,12 +23,12 @@ func TestGetSeverityTagNotApplicable(t *testing.T) { } func TestGetVulnerabilitiesBanners(t *testing.T) { - assert.Equal(t, "[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/noVulnerabilityBannerPR.png)](https://github.com/jfrog/frogbot#readme)", GetBanner(NoVulnerabilityPrBannerSource)) - assert.Equal(t, "[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)", GetBanner(VulnerabilitiesPrBannerSource)) - assert.Equal(t, "[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerMR.png)](https://github.com/jfrog/frogbot#readme)", GetBanner(VulnerabilitiesMrBannerSource)) - assert.Equal(t, "[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/noVulnerabilityBannerMR.png)](https://github.com/jfrog/frogbot#readme)", GetBanner(NoVulnerabilityMrBannerSource)) - assert.Equal(t, "[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerMR.png)](https://github.com/jfrog/frogbot#readme)", GetBanner(VulnerabilitiesFixMrBannerSource)) - assert.Equal(t, "[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerPR.png)](https://github.com/jfrog/frogbot#readme)", GetBanner(VulnerabilitiesFixPrBannerSource)) + assert.Equal(t, "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/noVulnerabilityBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n", GetBanner(NoVulnerabilityPrBannerSource)) + assert.Equal(t, "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n", GetBanner(VulnerabilitiesPrBannerSource)) + assert.Equal(t, "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerMR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n", GetBanner(VulnerabilitiesMrBannerSource)) + assert.Equal(t, "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/noVulnerabilityBannerMR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n", GetBanner(NoVulnerabilityMrBannerSource)) + assert.Equal(t, "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerMR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n", GetBanner(VulnerabilitiesFixMrBannerSource)) + assert.Equal(t, "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n", GetBanner(VulnerabilitiesFixPrBannerSource)) } func TestGetSimplifiedTitle(t *testing.T) { diff --git a/commands/utils/packagehandlers/packagehandlers_test.go b/commands/utils/packagehandlers/packagehandlers_test.go index e250aa550..907747d0b 100644 --- a/commands/utils/packagehandlers/packagehandlers_test.go +++ b/commands/utils/packagehandlers/packagehandlers_test.go @@ -41,21 +41,21 @@ func TestGoPackageHandler_UpdateDependency(t *testing.T) { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "0.0.0-20201216223049-8b5274cf687f", IsDirectDependency: false, - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyName: "golang.org/x/crypto"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyName: "golang.org/x/crypto"}, }, fixSupported: true, }, { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.7.7", IsDirectDependency: true, - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyName: "github.com/gin-gonic/gin"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyName: "github.com/gin-gonic/gin"}, }, fixSupported: true, }, { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.3.0", IsDirectDependency: true, - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyName: "github.com/google/uuid"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyName: "github.com/google/uuid"}, }, fixSupported: true, }, } @@ -83,49 +83,49 @@ func TestPythonPackageHandler_UpdateDependency(t *testing.T) { {dependencyFixTest: dependencyFixTest{ vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.25.9", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "urllib3"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "urllib3"}, }}, requirementsPath: "requirements.txt"}, {dependencyFixTest: dependencyFixTest{ vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.25.9", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyName: "urllib3"}}}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyName: "urllib3"}}}, requirementsPath: "pyproejct.toml"}, {dependencyFixTest: dependencyFixTest{ vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.25.9", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Pipenv, ImpactedDependencyName: "urllib3"}}}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pipenv, ImpactedDependencyName: "urllib3"}}}, requirementsPath: "Pipfile"}, {dependencyFixTest: dependencyFixTest{ vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.4.0", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "pyjwt"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "pyjwt"}, IsDirectDependency: true}, fixSupported: true}, requirementsPath: "requirements.txt"}, {dependencyFixTest: dependencyFixTest{ vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.4.0", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "Pyjwt"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "Pyjwt"}, IsDirectDependency: true}, fixSupported: true}, requirementsPath: "requirements.txt"}, {dependencyFixTest: dependencyFixTest{ vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.4.0", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "pyjwt"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "pyjwt"}, IsDirectDependency: true}, fixSupported: true}, requirementsPath: "setup.py"}, {dependencyFixTest: dependencyFixTest{ vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.4.0", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyName: "pyjwt"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyName: "pyjwt"}, IsDirectDependency: true}, fixSupported: true}, requirementsPath: "pyproject.toml"}, {dependencyFixTest: dependencyFixTest{ vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.4.0", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyName: "pyjwt"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyName: "pyjwt"}, IsDirectDependency: true}, fixSupported: true}, requirementsPath: "pyproject.toml"}, @@ -177,14 +177,14 @@ func TestNpmPackageHandler_UpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "0.8.4", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Npm, ImpactedDependencyName: "mpath"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Npm, ImpactedDependencyName: "mpath"}, }, fixSupported: false, }, { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "3.0.2", IsDirectDependency: true, - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Npm, ImpactedDependencyName: "minimatch"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Npm, ImpactedDependencyName: "minimatch"}, }, fixSupported: true, }, } @@ -212,14 +212,14 @@ func TestYarnPackageHandler_UpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.2.6", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Yarn, ImpactedDependencyName: "minimist"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Yarn, ImpactedDependencyName: "minimist"}, }, fixSupported: false, }, { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.2.6", IsDirectDependency: true, - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Yarn, ImpactedDependencyName: "minimist"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Yarn, ImpactedDependencyName: "minimist"}, }, fixSupported: true, }, } @@ -245,11 +245,11 @@ func TestMavenPackageHandler_UpdateDependency(t *testing.T) { tests := []dependencyFixTest{ {vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.7", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Maven, ImpactedDependencyName: "commons-io:commons-io"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Maven, ImpactedDependencyName: "commons-io:commons-io"}, IsDirectDependency: true}, fixSupported: true}, {vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "4.3.20", - VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{Technology: coreutils.Maven, ImpactedDependencyName: "org.springframework:spring-core"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Maven, ImpactedDependencyName: "org.springframework:spring-core"}, IsDirectDependency: false}, fixSupported: false}, } for _, test := range tests { diff --git a/commands/utils/simplifiedoutput.go b/commands/utils/simplifiedoutput.go index dfcb4426d..ead8caeef 100644 --- a/commands/utils/simplifiedoutput.go +++ b/commands/utils/simplifiedoutput.go @@ -143,7 +143,7 @@ func (smo *SimplifiedOutput) FormattedSeverity(severity, _ string) string { func (smo *SimplifiedOutput) UntitledForJasMsg() string { msg := "" if !smo.entitledForJas { - msg = "\n\n**Frogbot** also supports **Contextual Analysis**. This feature is included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system." + msg = "\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." } return msg } diff --git a/commands/utils/standardoutput.go b/commands/utils/standardoutput.go index 3976dc6ec..683b1c6dc 100644 --- a/commands/utils/standardoutput.go +++ b/commands/utils/standardoutput.go @@ -60,7 +60,10 @@ func (so *StandardOutput) VulnerabilitiesTableHeader() string { } func (so *StandardOutput) IsFrogbotResultComment(comment string) bool { - return strings.Contains(comment, GetIconTag(NoVulnerabilityPrBannerSource)) || strings.Contains(comment, GetIconTag(VulnerabilitiesPrBannerSource)) + return strings.Contains(comment, GetIconTag(NoVulnerabilityPrBannerSource)) || + strings.Contains(comment, GetIconTag(VulnerabilitiesPrBannerSource)) || + strings.Contains(comment, GetIconTag(NoVulnerabilityMrBannerSource)) || + strings.Contains(comment, GetIconTag(VulnerabilitiesMrBannerSource)) } func (so *StandardOutput) SetVcsProvider(provider vcsutils.VcsProvider) { @@ -168,7 +171,7 @@ func (so *StandardOutput) UntitledForJasMsg() string { `
-**Frogbot** also supports **Contextual Analysis**. This feature is included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system. +**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.
` diff --git a/commands/utils/standardoutput_test.go b/commands/utils/standardoutput_test.go index 3284e4a05..3a869c7c7 100644 --- a/commands/utils/standardoutput_test.go +++ b/commands/utils/standardoutput_test.go @@ -99,6 +99,14 @@ func TestStandardOutput_IsFrogbotResultComment(t *testing.T) { comment: "This is a comment with the " + GetIconTag(VulnerabilitiesPrBannerSource) + " icon", expected: true, }, + { + comment: "This is a comment with the " + GetIconTag(VulnerabilitiesMrBannerSource) + " icon", + expected: true, + }, + { + comment: "This is a comment with the " + GetIconTag(NoVulnerabilityMrBannerSource) + " icon", + expected: true, + }, { comment: "This is a comment with no icons", expected: false, diff --git a/commands/utils/utils.go b/commands/utils/utils.go index 2a4999a1a..682d98360 100644 --- a/commands/utils/utils.go +++ b/commands/utils/utils.go @@ -69,7 +69,7 @@ func (err *ErrUnsupportedFix) Error() string { // VulnerabilityDetails serves as a container for essential information regarding a vulnerability that is going to be addressed and resolved type VulnerabilityDetails struct { - *formats.VulnerabilityOrViolationRow + formats.VulnerabilityOrViolationRow // Suggested fix version SuggestedFixedVersion string // States whether the dependency is direct or transitive @@ -78,7 +78,7 @@ type VulnerabilityDetails struct { Cves []string } -func NewVulnerabilityDetails(vulnerability *formats.VulnerabilityOrViolationRow, fixVersion string) *VulnerabilityDetails { +func NewVulnerabilityDetails(vulnerability formats.VulnerabilityOrViolationRow, fixVersion string) *VulnerabilityDetails { vulnDetails := &VulnerabilityDetails{ VulnerabilityOrViolationRow: vulnerability, SuggestedFixedVersion: fixVersion, @@ -104,6 +104,14 @@ func (vd *VulnerabilityDetails) UpdateFixVersionIfMax(fixVersion string) { } } +func ExtractVunerabilitiesDetailsToRows(vulnDetails []*VulnerabilityDetails) []formats.VulnerabilityOrViolationRow { + var rows []formats.VulnerabilityOrViolationRow + for _, vuln := range vulnDetails { + rows = append(rows, vuln.VulnerabilityOrViolationRow) + } + return rows +} + type ErrMissingEnv struct { VariableName string } @@ -170,13 +178,13 @@ func Md5Hash(values ...string) (string, error) { return hex.EncodeToString(hash.Sum(nil)), nil } -// Generates MD5Hash from a vulnerabilityDetails +// Generates MD5Hash from a VulnerabilityOrViolationRow // The map can be returned in different order from Xray, so we need to sort the strings before hashing. -func VulnerabilityDetailsToMD5Hash(vulnerabilities ...*VulnerabilityDetails) (string, error) { +func VulnerabilityDetailsToMD5Hash(vulnerabilities ...formats.VulnerabilityOrViolationRow) (string, error) { hash := crypto.MD5.New() var keys []string for _, vuln := range vulnerabilities { - keys = append(keys, GetUniqueID(*vuln.VulnerabilityOrViolationRow)) + keys = append(keys, GetUniqueID(vuln)) } sort.Strings(keys) for key, value := range keys { @@ -292,3 +300,15 @@ func BuildServerConfigFile(server *config.ServerDetails) (previousJFrogHomeDir, func GetUniqueID(vulnerability formats.VulnerabilityOrViolationRow) string { return vulnerability.ImpactedDependencyName + vulnerability.ImpactedDependencyVersion + vulnerability.IssueId } + +func GetSortedPullRequestComments(client vcsclient.VcsClient, repoOwner, repoName string, prID int) ([]vcsclient.CommentInfo, error) { + pullRequestsComments, err := client.ListPullRequestComments(context.Background(), repoOwner, repoName, prID) + if err != nil { + return nil, err + } + // Sort the comment according to time created, the newest comment should be the first one. + sort.Slice(pullRequestsComments, func(i, j int) bool { + return pullRequestsComments[i].Created.After(pullRequestsComments[j].Created) + }) + return pullRequestsComments, nil +} diff --git a/commands/utils/utils_test.go b/commands/utils/utils_test.go index fe37cc1ff..470814620 100644 --- a/commands/utils/utils_test.go +++ b/commands/utils/utils_test.go @@ -136,29 +136,30 @@ func TestFixVersionsMapToMd5Hash(t *testing.T) { }{ { vulnerabilities: []*VulnerabilityDetails{ - {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg", Technology: coreutils.Npm}, IsDirectDependency: false}}, + {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg", Technology: coreutils.Npm}, IsDirectDependency: false}}, expectedHash: "8a5f1a3a7f11a825f3e0546f74d5dd18", }, { vulnerabilities: []*VulnerabilityDetails{ - {SuggestedFixedVersion: "5.2.3", VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg", Technology: coreutils.Go}, IsDirectDependency: false}, - {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg2", Technology: coreutils.Go}, IsDirectDependency: false}}, + {SuggestedFixedVersion: "5.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg", Technology: coreutils.Go}, IsDirectDependency: false}, + {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg2", Technology: coreutils.Go}, IsDirectDependency: false}}, expectedHash: "984b2585da84b62146f8d2ec0fd12e0e", }, { // The Same map with different order should be the same hash. vulnerabilities: []*VulnerabilityDetails{ - {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg2", Technology: coreutils.Go}, IsDirectDependency: false}, - {SuggestedFixedVersion: "5.2.3", VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg", Technology: coreutils.Go}, IsDirectDependency: false}}, + {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg2", Technology: coreutils.Go}, IsDirectDependency: false}, + {SuggestedFixedVersion: "5.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg", Technology: coreutils.Go}, IsDirectDependency: false}}, expectedHash: "984b2585da84b62146f8d2ec0fd12e0e", }, { vulnerabilities: []*VulnerabilityDetails{ - {SuggestedFixedVersion: "0.2.33", VulnerabilityOrViolationRow: &formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "myNuget", Technology: coreutils.Nuget}, IsDirectDependency: false}}, + {SuggestedFixedVersion: "0.2.33", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "myNuget", Technology: coreutils.Nuget}, IsDirectDependency: false}}, expectedHash: "1708946f489ed70c754dd1ceef49b50b", }, } for _, test := range tests { t.Run(test.expectedHash, func(t *testing.T) { - hash, err := VulnerabilityDetailsToMD5Hash(test.vulnerabilities...) + vulnRows := ExtractVunerabilitiesDetailsToRows(test.vulnerabilities) + hash, err := VulnerabilityDetailsToMD5Hash(vulnRows...) assert.NoError(t, err) assert.Equal(t, test.expectedHash, hash) }) @@ -339,3 +340,34 @@ func TestBuildServerConfigFile(t *testing.T) { assert.NoError(t, err) assert.Equal(t, expectedConfigurationFile, string(actualConfigurationFile)) } + +func TestExtractVunerabilitiesDetailsToRows(t *testing.T) { + testCases := []struct { + name string + vulnDetails []*VulnerabilityDetails + expectedRows []formats.VulnerabilityOrViolationRow + }{ + { + name: "No Vulnerabilities", + vulnDetails: []*VulnerabilityDetails{}, + expectedRows: []formats.VulnerabilityOrViolationRow{}, + }, + { + name: "Single Vulnerability", + vulnDetails: []*VulnerabilityDetails{{VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{IssueId: "1"}}}, + expectedRows: []formats.VulnerabilityOrViolationRow{{IssueId: "1"}}, + }, + { + name: "Multiple Vulnerabilities", + vulnDetails: []*VulnerabilityDetails{{VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{IssueId: "1"}}, {VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{IssueId: "2"}}}, + expectedRows: []formats.VulnerabilityOrViolationRow{{IssueId: "1"}, {IssueId: "2"}}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actualRows := ExtractVunerabilitiesDetailsToRows(tc.vulnDetails) + assert.ElementsMatch(t, tc.expectedRows, actualRows) + }) + } +} diff --git a/go.mod b/go.mod index 2e445fcc9..f445908e1 100644 --- a/go.mod +++ b/go.mod @@ -3,27 +3,28 @@ module github.com/jfrog/frogbot go 1.20 require ( - github.com/go-git/go-git/v5 v5.7.0 + github.com/go-git/go-git/v5 v5.8.1 github.com/golang/mock v1.6.0 github.com/jfrog/build-info-go v1.9.6 - github.com/jfrog/froggit-go v1.11.0 + github.com/jfrog/froggit-go v1.12.0 github.com/jfrog/gofrog v1.3.0 github.com/jfrog/jfrog-cli-core/v2 v2.39.3 github.com/jfrog/jfrog-client-go v1.31.2 github.com/mholt/archiver/v3 v3.5.1 github.com/stretchr/testify v1.8.4 - github.com/urfave/cli/v2 v2.25.1 + github.com/urfave/cli/v2 v2.25.7 github.com/xeipuuv/gojsonschema v1.2.0 - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 + golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/BurntSushi/toml v1.2.1 // indirect + dario.cat/mergo v1.0.0 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect github.com/CycloneDX/cyclonedx-go v0.7.1 // indirect - github.com/Microsoft/go-winio v0.5.2 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect github.com/VividCortex/ewma v1.2.0 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/acomagu/bufpipe v1.0.4 // indirect @@ -44,7 +45,7 @@ require ( github.com/gocarina/gocsv v0.0.0-20230406101422-6445c2b15027 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.2 // indirect github.com/google/go-github/v45 v45.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect @@ -54,7 +55,6 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.6.8 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/imdario/mergo v0.3.15 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jedib0t/go-pretty/v6 v6.4.6 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect @@ -83,7 +83,7 @@ require ( github.com/rivo/uniseg v0.4.3 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect - github.com/skeema/knownhosts v1.1.1 // indirect + github.com/skeema/knownhosts v1.2.0 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -100,20 +100,18 @@ require ( github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/crypto v0.9.0 // indirect - golang.org/x/net v0.10.0 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/mod v0.11.0 // indirect + golang.org/x/net v0.12.0 // indirect golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.1.0 // indirect + golang.org/x/tools v0.6.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) - -//replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20230720085538-4befe41129f8 - -// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20230611131847-a3b84a9004c3 diff --git a/go.sum b/go.sum index 7d922a09e..f5f69f9fd 100644 --- a/go.sum +++ b/go.sum @@ -35,17 +35,21 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CycloneDX/cyclonedx-go v0.7.1 h1:5w1SxjGm9MTMNTuRbEPyw21ObdbaagTWF/KfF0qHTRE= github.com/CycloneDX/cyclonedx-go v0.7.1/go.mod h1:N/nrdWQI2SIjaACyyDs/u7+ddCkyl/zkNs8xFsHF2Ps= -github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 h1:JMDGhoQvXNTqH6Y3MC0IUw6tcZvaUdujNqzK2HYWZc8= -github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= @@ -112,8 +116,8 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmS github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4= github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= -github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE= -github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8= +github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A= +github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -152,8 +156,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -212,16 +216,14 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= -github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jedib0t/go-pretty/v6 v6.4.6 h1:v6aG9h6Uby3IusSSEjHaZNXpHFhzqMmjXcPq1Rjl9Jw= github.com/jedib0t/go-pretty/v6 v6.4.6/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs= github.com/jfrog/build-info-go v1.9.6 h1:lCJ2j5uXAlJsSwDe5J8WD7Co1f/hUlZvMfwfb5AzLJU= github.com/jfrog/build-info-go v1.9.6/go.mod h1:GbuFS+viHCKZYx9nWHYu7ab1DgQkFdtVN3BJPUNb2D4= -github.com/jfrog/froggit-go v1.11.0 h1:LdQbihrJWh+G3G+5KmDOIyWmzr1F21zwK4X1t99ooeE= -github.com/jfrog/froggit-go v1.11.0/go.mod h1:XTFf4RqWwZsF9pdERt0Ra5gO1O3iqIq7Npx2tEQSGAQ= +github.com/jfrog/froggit-go v1.12.0 h1:vBTOty90e8TaEknA+ozWyG+p9Ts+hPaLK+656iV5q1M= +github.com/jfrog/froggit-go v1.12.0/go.mod h1:XTFf4RqWwZsF9pdERt0Ra5gO1O3iqIq7Npx2tEQSGAQ= github.com/jfrog/gofrog v1.3.0 h1:o4zgsBZE4QyDbz2M7D4K6fXPTBJht+8lE87mS9bw7Gk= github.com/jfrog/gofrog v1.3.0/go.mod h1:IFMc+V/yf7rA5WZ74CSbXe+Lgf0iApEQLxRZVzKRUR0= github.com/jfrog/jfrog-cli-core/v2 v2.39.3 h1:GtBwEAchuvI4c8ZwaJ6CKN/KavMlEu5+DwNX9OesYMI= @@ -246,7 +248,7 @@ github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -314,14 +316,14 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE= -github.com/skeema/knownhosts v1.1.1/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= +github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= +github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= @@ -354,8 +356,8 @@ github.com/ulikunitz/xz v0.5.9 h1:RsKRIA2MO8x56wkkcd3LbtcE/uMszhb6DpRf+3uwa3I= github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8= github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= -github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw= -github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/vbauerster/mpb/v7 v7.5.3 h1:BkGfmb6nMrrBQDFECR/Q7RkKCw7ylMetCb4079CGs4w= github.com/vbauerster/mpb/v7 v7.5.3/go.mod h1:i+h4QY6lmLvBNK2ah1fSreiw3ajskRlBp9AhY/PnuOE= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= @@ -400,8 +402,8 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -412,8 +414,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -440,6 +442,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -479,8 +483,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -571,15 +575,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -592,8 +596,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -648,6 +652,7 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=