diff --git a/commands/createfixpullrequests_test.go b/commands/createfixpullrequests_test.go
deleted file mode 100644
index 26b5f2f8d..000000000
--- a/commands/createfixpullrequests_test.go
+++ /dev/null
@@ -1,694 +0,0 @@
-package commands
-
-import (
- "context"
- "errors"
- "fmt"
- "github.com/jfrog/frogbot/commands/utils"
- "github.com/jfrog/froggit-go/vcsclient"
- "github.com/jfrog/froggit-go/vcsutils"
- "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
- "github.com/jfrog/jfrog-cli-core/v2/xray/formats"
- xrayutils "github.com/jfrog/jfrog-cli-core/v2/xray/utils"
- "github.com/jfrog/jfrog-client-go/utils/io/fileutils"
- "github.com/jfrog/jfrog-client-go/utils/log"
- "github.com/jfrog/jfrog-client-go/xray/services"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "net/http/httptest"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "testing"
-)
-
-var testPackagesData = []struct {
- packageType coreutils.Technology
- commandName string
- commandArgs []string
-}{
- {
- packageType: coreutils.Go,
- },
- {
- packageType: coreutils.Maven,
- },
- {
- packageType: coreutils.Gradle,
- },
- {
- packageType: coreutils.Npm,
- commandName: "npm",
- commandArgs: []string{"install"},
- },
- {
- packageType: coreutils.Yarn,
- commandName: "yarn",
- commandArgs: []string{"install"},
- },
- {
- packageType: coreutils.Dotnet,
- commandName: "dotnet",
- commandArgs: []string{"restore"},
- },
- {
- packageType: coreutils.Pip,
- },
- {
- packageType: coreutils.Pipenv,
- },
- {
- packageType: coreutils.Poetry,
- },
-}
-
-// These tests utilize pre-prepared git folders that correspond to specific use cases.
-// To modify these tests, you can change the folder name from "git"
-// to ".git",make the necessary changes,and then rename it back to "git".
-// Afterward, add the changes to the main repository.
-// It is crucial to maintain the desired state of the git repository.
-// Make sure it is checked out to the main branch, replicating an actual run.
-func TestCreateFixPullRequestsCmd_Run(t *testing.T) {
- tests := []struct {
- repoName string
- testDir string
- configPath string
- expectedDiff []string
- expectedBranches []string
- packageDescriptorPaths []string
- aggregateFixes bool
- }{
- {
- repoName: "aggregate",
- testDir: "createfixpullrequests/aggregate",
- expectedBranches: []string{"frogbot-update-npm-dependencies"},
- expectedDiff: []string{"diff --git a/package.json b/package.json\nindex c5ea932..1176f2d 100644\n--- a/package.json\n+++ b/package.json\n@@ -9,8 +9,8 @@\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n- \"uuid\": \"^9.0.0\",\n- \"minimist\":\"1.2.5\",\n- \"mpath\": \"0.7.0\"\n+ \"minimist\": \"^1.2.6\",\n+ \"mpath\": \"^0.8.4\",\n+ \"uuid\": \"^9.0.0\"\n }\n-}\n\\ No newline at end of file\n+}\n"},
- packageDescriptorPaths: []string{"package.json"},
- aggregateFixes: true,
- },
- {
- repoName: "aggregate-multi-dir",
- testDir: "createfixpullrequests/aggregate-multi-dir",
- expectedBranches: []string{"frogbot-update-npm-dependencies"},
- expectedDiff: []string{"diff --git a/npm1/package.json b/npm1/package.json\nindex ae09978..286211d 100644\n--- a/npm1/package.json\n+++ b/npm1/package.json\n@@ -9,8 +9,8 @@\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n- \"uuid\": \"^9.0.0\",\n- \"minimatch\":\"3.0.2\",\n- \"mpath\": \"0.7.0\"\n+ \"minimatch\": \"^3.0.5\",\n+ \"mpath\": \"^0.8.4\",\n+ \"uuid\": \"^9.0.0\"\n }\n-}\n\\ No newline at end of file\n+}\ndiff --git a/npm2/package.json b/npm2/package.json\nindex be180a6..14b5c7a 100644\n--- a/npm2/package.json\n+++ b/npm2/package.json\n@@ -1,5 +1,5 @@\n {\n \"dependencies\": {\n- \"minimist\": \"^1.2.5\"\n+ \"minimist\": \"^1.2.6\"\n }\n }\n"},
- packageDescriptorPaths: []string{"npm1/package.json", "npm2/package.json"},
- aggregateFixes: true,
- configPath: "testdata/createfixpullrequests/aggregate-multi-dir/.frogbot/frogbot-config.yml",
- },
- {
- repoName: "aggregate-multi-project",
- testDir: "createfixpullrequests/aggregate-multi-project",
- expectedBranches: []string{"frogbot-update-npm-dependencies", "frogbot-update-pip-dependencies"},
- expectedDiff: []string{"diff --git a/npm/package.json b/npm/package.json\nindex ae09978..286211d 100644\n--- a/npm/package.json\n+++ b/npm/package.json\n@@ -9,8 +9,8 @@\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n- \"uuid\": \"^9.0.0\",\n- \"minimatch\":\"3.0.2\",\n- \"mpath\": \"0.7.0\"\n+ \"minimatch\": \"^3.0.5\",\n+ \"mpath\": \"^0.8.4\",\n+ \"uuid\": \"^9.0.0\"\n }\n-}\n\\ No newline at end of file\n+}\n", "diff --git a/pip/requirements.txt b/pip/requirements.txt\nindex 65c9637..7788edc 100644\n--- a/pip/requirements.txt\n+++ b/pip/requirements.txt\n@@ -1,2 +1,2 @@\n pexpect==4.8.0\n-pyjwt==1.7.1\n\\ No newline at end of file\n+pyjwt==2.4.0\n\\ No newline at end of file\n"},
- packageDescriptorPaths: []string{"npm/package.json", "pip/requirements.txt"},
- aggregateFixes: true,
- configPath: "testdata/createfixpullrequests/aggregate-multi-project/.frogbot/frogbot-config.yml",
- },
- {
- repoName: "aggregate-no-vul",
- testDir: "createfixpullrequests/aggregate-no-vul",
- expectedBranches: []string{"main"}, // No branch should be created
- expectedDiff: []string{""},
- packageDescriptorPaths: []string{"package.json"},
- aggregateFixes: true,
- },
- {
- repoName: "aggregate-cant-fix",
- testDir: "createfixpullrequests/aggregate-cant-fix",
- expectedBranches: []string{"frogbot-update-pip-dependencies"},
- expectedDiff: []string{""}, // No diff expected
- packageDescriptorPaths: []string{"setup.py"}, // This is a build tool dependency which should not be fixed
- aggregateFixes: true,
- },
- {
- repoName: "non-aggregate",
- testDir: "createfixpullrequests/non-aggregate",
- expectedBranches: []string{"frogbot-minimist-e6e68f7e53c2b59c6bd946e00af797f7"},
- expectedDiff: []string{"diff --git a/package.json b/package.json\nindex 5c4b711..134c416 100644\n--- a/package.json\n+++ b/package.json\n@@ -9,6 +9,6 @@\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n- \"minimist\":\"1.2.5\"\n+ \"minimist\": \"^1.2.6\"\n }\n-}\n\\ No newline at end of file\n+}\n"},
- packageDescriptorPaths: []string{"package.json"},
- aggregateFixes: false,
- },
- }
- for _, test := range tests {
- t.Run(test.repoName, func(t *testing.T) {
- // Prepare
- serverParams, restoreEnv := verifyEnv(t)
- if test.aggregateFixes {
- assert.NoError(t, os.Setenv(utils.GitAggregateFixesEnv, "true"))
- defer func() {
- assert.NoError(t, os.Setenv(utils.GitAggregateFixesEnv, "false"))
- }()
- }
- var port string
- server := httptest.NewServer(createHttpHandler(t, &port, test.repoName))
- port = server.URL[strings.LastIndex(server.URL, ":")+1:]
- gitTestParams := utils.GitClientInfo{
- GitProvider: vcsutils.GitHub,
- VcsInfo: vcsclient.VcsInfo{
- Token: "123456",
- APIEndpoint: server.URL,
- },
- RepoName: test.repoName,
- }
- client, err := vcsclient.NewClientBuilder(vcsutils.GitHub).ApiEndpoint(server.URL).Token("123456").Build()
- assert.NoError(t, err)
-
- // Read config or resolve to default
- var configData []byte
- if test.configPath != "" {
- configData, err = utils.ReadConfigFromFileSystem(test.configPath)
- assert.NoError(t, err)
- } else {
- configData = []byte{}
- // Manual set of "JF_GIT_BASE_BRANCH"
- gitTestParams.Branches = []string{"main"}
- }
-
- envPath, cleanUp := utils.PrepareTestEnvironment(t, "", test.testDir)
- defer cleanUp()
- configAggregator, err := utils.BuildRepoAggregator(configData, &gitTestParams, &serverParams)
- assert.NoError(t, err)
- // Run
- var cmd = CreateFixPullRequestsCmd{dryRun: true, dryRunRepoPath: envPath}
- err = cmd.Run(configAggregator, client)
- // Validate
- assert.NoError(t, err)
- for _, branch := range test.expectedBranches {
- resultDiff, err := verifyDependencyFileDiff("main", branch, test.packageDescriptorPaths...)
- assert.NoError(t, err)
- assert.Contains(t, test.expectedDiff, string(resultDiff))
- }
- // Defers
- defer func() {
- restoreEnv()
- server.Close()
- }()
- })
- }
-}
-
-// Tests the lifecycle of aggregated pull request
-// No open pull request -> Open
-// If Pull request already active, compare scan results for current and remote branch
-// Same scan results -> do nothing.
-// Different scan results -> Update the pull request branch & body.
-func TestAggregatePullRequestLifecycle(t *testing.T) {
- mockPrId := int64(1)
- tests := []struct {
- repoName string
- testDir string
- expectedUpdate bool
- mockPullRequestResponse []vcsclient.PullRequestInfo
- }{
- {
- repoName: "aggregate-dont-update-pr",
- testDir: "createfixpullrequests/aggregate-dont-update-pr",
- expectedUpdate: false,
- mockPullRequestResponse: []vcsclient.PullRequestInfo{{ID: mockPrId,
- Body: `
-[comment]: <> (Checksum: 4608a55b621cb6337ac93487979ac09c)
-pr body
- `,
- Source: vcsclient.BranchInfo{Name: "frogbot-update-npm-dependencies"},
- Target: vcsclient.BranchInfo{Name: "main"},
- }},
- },
- {
- repoName: "aggregate-update-pr",
- testDir: "createfixpullrequests/aggregate-update-pr",
- expectedUpdate: true,
- mockPullRequestResponse: []vcsclient.PullRequestInfo{{ID: mockPrId,
- Body: `
-[comment]: <> (Checksum: 01373ac4d2c32e7da9be22f3e4b4e665)
-pr body
- `,
- Source: vcsclient.BranchInfo{Name: "frogbot-update-npm-dependencies"},
- Target: vcsclient.BranchInfo{Name: "remoteMain"},
- }},
- },
- }
- for _, test := range tests {
- t.Run(test.repoName, func(t *testing.T) {
- // Prepare
- serverParams, restoreEnv := verifyEnv(t)
- defer restoreEnv()
- assert.NoError(t, os.Setenv(utils.GitAggregateFixesEnv, "true"))
- defer func() {
- assert.NoError(t, os.Setenv(utils.GitAggregateFixesEnv, "false"))
- }()
- var port string
- server := httptest.NewServer(createHttpHandler(t, &port, test.repoName))
- defer func() {
- server.Close()
- }()
- port = server.URL[strings.LastIndex(server.URL, ":")+1:]
- gitTestParams := &utils.GitClientInfo{
- GitProvider: vcsutils.GitHub,
- VcsInfo: vcsclient.VcsInfo{
- Token: "123456",
- APIEndpoint: server.URL,
- }, RepoName: test.repoName,
- }
- // Set up mock VCS responses
- client := mockVcsClient(t)
- client.EXPECT().ListOpenPullRequestsWithBody(context.Background(), "", gitTestParams.RepoName).Return(test.mockPullRequestResponse, nil)
- if test.expectedUpdate {
- client.EXPECT().UpdatePullRequest(context.Background(), "", gitTestParams.RepoName, utils.GetAggregatedPullRequestTitle(coreutils.Npm), "", "", int(mockPrId), vcsutils.Open).Return(nil)
- }
- // Load default configurations
- var configData []byte
- // Manual set of "JF_GIT_BASE_BRANCH"
- gitTestParams.Branches = []string{"main"}
- envPath, cleanUp := utils.PrepareTestEnvironment(t, "", test.testDir)
- defer cleanUp()
- configAggregator, err := utils.BuildRepoAggregator(configData, gitTestParams, &serverParams)
- assert.NoError(t, err)
- // Run
- var cmd = CreateFixPullRequestsCmd{dryRun: true, dryRunRepoPath: envPath}
- err = cmd.Run(configAggregator, client)
- assert.NoError(t, err)
- })
- }
-}
-
-// / 1.0 --> 1.0 ≤ x
-// / (,1.0] --> x ≤ 1.0
-// / (,1.0) --> x < 1.0
-// / [1.0] --> x == 1.0
-// / (1.0,) --> 1.0 < x
-// / (1.0, 2.0) --> 1.0 < x < 2.0
-// / [1.0, 2.0] --> 1.0 ≤ x ≤ 2.0
-func TestParseVersionChangeString(t *testing.T) {
- tests := []struct {
- versionChangeString string
- expectedVersion string
- }{
- {"1.2.3", "1.2.3"},
- {"[1.2.3]", "1.2.3"},
- {"[1.2.3, 2.0.0]", "1.2.3"},
-
- {"(,1.2.3]", ""},
- {"(,1.2.3)", ""},
- {"(1.2.3,)", ""},
- {"(1.2.3, 2.0.0)", ""},
- }
-
- for _, test := range tests {
- t.Run(test.versionChangeString, func(t *testing.T) {
- assert.Equal(t, test.expectedVersion, parseVersionChangeString(test.versionChangeString))
- })
- }
-}
-
-func TestGenerateFixBranchName(t *testing.T) {
- tests := []struct {
- baseBranch string
- impactedPackage string
- fixVersion string
- expectedName string
- }{
- {"dev", "gopkg.in/yaml.v3", "3.0.0", "frogbot-gopkg.in/yaml.v3-d61bde82dc594e5ccc5a042fe224bf7c"},
- {"master", "gopkg.in/yaml.v3", "3.0.0", "frogbot-gopkg.in/yaml.v3-41405528994061bd108e3bbd4c039a03"},
- {"dev", "replace:colons:colons", "3.0.0", "frogbot-replace_colons_colons-89e555131b4a70a32fe9d9c44d6ff0fc"},
- }
- gitManager := utils.GitManager{}
- for _, test := range tests {
- t.Run(test.expectedName, func(t *testing.T) {
- branchName, err := gitManager.GenerateFixBranchName(test.baseBranch, test.impactedPackage, test.fixVersion)
- assert.NoError(t, err)
- assert.Equal(t, test.expectedName, branchName)
- })
- }
-}
-
-func TestPackageTypeFromScan(t *testing.T) {
- environmentVars, restoreEnv := verifyEnv(t)
- defer restoreEnv()
- testScan := &CreateFixPullRequestsCmd{OutputWriter: &utils.StandardOutput{}}
- trueVal := true
- params := utils.Params{
- Scan: utils.Scan{Projects: []utils.Project{{UseWrapper: &trueVal}}},
- }
- var frogbotParams = utils.Repository{
- Server: environmentVars,
- Params: params,
- }
- for _, pkg := range testPackagesData {
- // Create temp technology project
- projectPath := filepath.Join("testdata", "projects", pkg.packageType.ToString())
- t.Run(pkg.packageType.ToString(), func(t *testing.T) {
- tmpDir, err := fileutils.CreateTempDir()
- defer func() {
- err = fileutils.RemoveTempDir(tmpDir)
- }()
- assert.NoError(t, err)
- assert.NoError(t, fileutils.CopyDir(projectPath, tmpDir, true, nil))
- if pkg.packageType == coreutils.Gradle {
- assert.NoError(t, os.Chmod(filepath.Join(tmpDir, "gradlew"), 0777))
- assert.NoError(t, os.Chmod(filepath.Join(tmpDir, "gradlew.bat"), 0777))
- }
- frogbotParams.Projects[0].WorkingDirs = []string{tmpDir}
- files, err := fileutils.ListFiles(tmpDir, true)
- assert.NoError(t, err)
- for _, file := range files {
- log.Info(file)
- }
- frogbotParams.Projects[0].InstallCommandName = pkg.commandName
- frogbotParams.Projects[0].InstallCommandArgs = pkg.commandArgs
- scanSetup := utils.ScanDetails{
- XrayGraphScanParams: &services.XrayGraphScanParams{},
- Project: &frogbotParams.Projects[0],
- ServerDetails: &frogbotParams.Server,
- }
- testScan.details = &scanSetup
- scanResponse, err := testScan.scan(tmpDir)
- assert.NoError(t, err)
- verifyTechnologyNaming(t, scanResponse.ExtendedScanResults.XrayResults, pkg.packageType)
- })
- }
-}
-
-func TestGetMinimalFixVersion(t *testing.T) {
- tests := []struct {
- impactedVersionPackage string
- fixVersions []string
- expected string
- }{
- {impactedVersionPackage: "1.6.2", fixVersions: []string{"1.5.3", "1.6.1", "1.6.22", "1.7.0"}, expected: "1.6.22"},
- {impactedVersionPackage: "v1.6.2", fixVersions: []string{"1.5.3", "1.6.1", "1.6.22", "1.7.0"}, expected: "1.6.22"},
- {impactedVersionPackage: "1.7.1", fixVersions: []string{"1.5.3", "1.6.1", "1.6.22", "1.7.0"}, expected: ""},
- {impactedVersionPackage: "1.7.1", fixVersions: []string{"2.5.3"}, expected: "2.5.3"},
- {impactedVersionPackage: "v1.7.1", fixVersions: []string{"0.5.3", "0.9.9"}, expected: ""},
- }
- for _, test := range tests {
- t.Run(test.expected, func(t *testing.T) {
- expected := getMinimalFixVersion(test.impactedVersionPackage, test.fixVersions)
- assert.Equal(t, test.expected, expected)
- })
- }
-}
-
-func TestCreateVulnerabilitiesMap(t *testing.T) {
- cfp := &CreateFixPullRequestsCmd{}
-
- testCases := []struct {
- name string
- scanResults *xrayutils.ExtendedScanResults
- isMultipleRoots bool
- expectedMap map[string]*utils.VulnerabilityDetails
- }{
- {
- name: "Scan results with no violations and vulnerabilities",
- scanResults: &xrayutils.ExtendedScanResults{
- XrayResults: []services.ScanResponse{},
- },
- expectedMap: map[string]*utils.VulnerabilityDetails{},
- },
- {
- name: "Scan results with vulnerabilities and no violations",
- scanResults: &xrayutils.ExtendedScanResults{
- XrayResults: []services.ScanResponse{
- {
- Vulnerabilities: []services.Vulnerability{
- {
- Cves: []services.Cve{
- {Id: "CVE-2023-1234", CvssV3Score: "9.1"},
- {Id: "CVE-2023-4321", CvssV3Score: "8.9"},
- },
- Severity: "Critical",
- Components: map[string]services.Component{
- "vuln1": {
- FixedVersions: []string{"1.9.1", "2.0.3", "2.0.5"},
- ImpactPaths: [][]services.ImpactPathNode{{{ComponentId: "root"}, {ComponentId: "vuln1"}}},
- },
- },
- },
- {
- Cves: []services.Cve{
- {Id: "CVE-2022-1234", CvssV3Score: "7.1"},
- {Id: "CVE-2022-4321", CvssV3Score: "7.9"},
- },
- Severity: "High",
- Components: map[string]services.Component{
- "vuln2": {
- FixedVersions: []string{"2.4.1", "2.6.3", "2.8.5"},
- ImpactPaths: [][]services.ImpactPathNode{{{ComponentId: "root"}, {ComponentId: "vuln1"}, {ComponentId: "vuln2"}}},
- },
- },
- },
- },
- },
- },
- },
- expectedMap: map[string]*utils.VulnerabilityDetails{
- "vuln1": {
- SuggestedFixedVersion: "1.9.1",
- IsDirectDependency: true,
- Cves: []string{"CVE-2023-1234", "CVE-2023-4321"},
- },
- "vuln2": {
- SuggestedFixedVersion: "2.4.1",
- Cves: []string{"CVE-2022-1234", "CVE-2022-4321"},
- },
- },
- },
- {
- name: "Scan results with violations and no vulnerabilities",
- scanResults: &xrayutils.ExtendedScanResults{
- XrayResults: []services.ScanResponse{
- {
- Violations: []services.Violation{
- {
- ViolationType: "security",
- Cves: []services.Cve{
- {Id: "CVE-2023-1234", CvssV3Score: "9.1"},
- {Id: "CVE-2023-4321", CvssV3Score: "8.9"},
- },
- Severity: "Critical",
- Components: map[string]services.Component{
- "viol1": {
- FixedVersions: []string{"1.9.1", "2.0.3", "2.0.5"},
- ImpactPaths: [][]services.ImpactPathNode{{{ComponentId: "root"}, {ComponentId: "viol1"}}},
- },
- },
- },
- {
- ViolationType: "security",
- Cves: []services.Cve{
- {Id: "CVE-2022-1234", CvssV3Score: "7.1"},
- {Id: "CVE-2022-4321", CvssV3Score: "7.9"},
- },
- Severity: "High",
- Components: map[string]services.Component{
- "viol2": {
- FixedVersions: []string{"2.4.1", "2.6.3", "2.8.5"},
- ImpactPaths: [][]services.ImpactPathNode{{{ComponentId: "root"}, {ComponentId: "viol1"}, {ComponentId: "viol2"}}},
- },
- },
- },
- },
- },
- },
- },
- expectedMap: map[string]*utils.VulnerabilityDetails{
- "viol1": {
- SuggestedFixedVersion: "1.9.1",
- IsDirectDependency: true,
- Cves: []string{"CVE-2023-1234", "CVE-2023-4321"},
- },
- "viol2": {
- SuggestedFixedVersion: "2.4.1",
- Cves: []string{"CVE-2022-1234", "CVE-2022-4321"},
- },
- },
- },
- }
-
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- fixVersionsMap, err := cfp.createVulnerabilitiesMap(testCase.scanResults, testCase.isMultipleRoots)
- assert.NoError(t, err)
- for name, expectedVuln := range testCase.expectedMap {
- actualVuln, exists := fixVersionsMap[name]
- require.True(t, exists)
- assert.Equal(t, expectedVuln.IsDirectDependency, actualVuln.IsDirectDependency)
- assert.Equal(t, expectedVuln.SuggestedFixedVersion, actualVuln.SuggestedFixedVersion)
- assert.ElementsMatch(t, expectedVuln.Cves, actualVuln.Cves)
- }
- })
- }
-}
-
-// Verifies unsupported packages return specific error
-// Other logic is implemented inside each package-handler.
-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}
- err := testScan.updatePackageToFixedVersion(vulnDetails)
- assert.Error(t, err, "Expected error to occur")
- assert.IsType(t, &utils.ErrUnsupportedFix{}, err, "Expected unsupported fix error")
- }
- }
-}
-
-func TestGetRemoteBranchScanHash(t *testing.T) {
- prBody := `
-[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerMR.png)](https://github.com/jfrog/frogbot#readme)
-## 📦 Vulnerable Dependencies
-
-### ✍️ Summary
-
-
-
-| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |
-| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: |
-| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | $\color{}{\textsf{Undetermined}}$ |github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.1] |
-| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | $\color{}{\textsf{Undetermined}}$ |github.com/mholt/archiver/v3:v3.5.1 | github.com/mholt/archiver/v3:v3.5.1 | |
-| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableMediumSeverity.png)
Medium | $\color{}{\textsf{Undetermined}}$ |github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.3] |
-
-
-
-## 👇 Details
-
-
-
- github.com/nats-io/nats-streaming-server v0.21.0
-
-
-- **Severity** 🔥 High
-- **Contextual Analysis:** $\color{}{\textsf{Undetermined}}$
-- **Package Name:** github.com/nats-io/nats-streaming-server
-- **Current Version:** v0.21.0
-- **Fixed Version:** [0.24.1]
-- **CVEs:** CVE-2022-24450
-
-
-
-
-
-
- github.com/mholt/archiver/v3 v3.5.1
-
-
-- **Severity** 🔥 High
-- **Contextual Analysis:** $\color{}{\textsf{Undetermined}}$
-- **Package Name:** github.com/mholt/archiver/v3
-- **Current Version:** v3.5.1
-
-
-
-
-
-
- github.com/nats-io/nats-streaming-server v0.21.0
-
-
-- **Severity** 🎃 Medium
-- **Contextual Analysis:** $\color{}{\textsf{Undetermined}}$
-- **Package Name:** github.com/nats-io/nats-streaming-server
-- **Current Version:** v0.21.0
-- **Fixed Version:** [0.24.3]
-- **CVEs:** CVE-2022-26652
-
-
-
-
-
-## 🛠️ Infrastructure as Code
-
-
-
-
-| SEVERITY | FILE | LINE:COLUMN | FINDING |
-| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: |
-| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableLowSeverity.png)
Low | test.js | 1:20 | kms_key_id='' was detected |
-| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | test2.js | 4:30 | Deprecated TLS version was detected |
-
-
-
-
-
-
-[JFrog Frogbot](https://github.com/jfrog/frogbot#readme)
-
-
-
-[Comment]: <> (Checksum: myhash4321)
-`
- cfp := &CreateFixPullRequestsCmd{}
- result := cfp.getRemoteBranchScanHash(prBody)
- assert.Equal(t, "myhash4321", result)
- prBody = `
-random body
-`
- result = cfp.getRemoteBranchScanHash(prBody)
- assert.Equal(t, "", result)
-}
-
-func TestPreparePullRequestDetails(t *testing.T) {
- cfp := CreateFixPullRequestsCmd{OutputWriter: &utils.StandardOutput{}, gitManager: &utils.GitManager{}}
- vulnerabilities := []formats.VulnerabilityOrViolationRow{
- {
- Summary: "summary",
- Severity: "High",
- ImpactedDependencyName: "package1",
- ImpactedDependencyVersion: "1.0.0",
- FixedVersions: []string{"1.0.0", "2.0.0"},
- Cves: []formats.CveRow{{Id: "CVE-2022-1234"}},
- },
- }
- 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)
- vulnerabilities = append(vulnerabilities, formats.VulnerabilityOrViolationRow{
- Summary: "summary",
- Severity: "Critical",
- ImpactedDependencyName: "package2",
- ImpactedDependencyVersion: "2.0.0",
- FixedVersions: []string{"2.0.0", "3.0.0"},
- Cves: []formats.CveRow{{Id: "CVE-2022-4321"}},
- })
- cfp.aggregateFixes = true
- expectedPrBody = "\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n\n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS |\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, 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)
-}
-
-func verifyTechnologyNaming(t *testing.T, scanResponse []services.ScanResponse, expectedType coreutils.Technology) {
- for _, resp := range scanResponse {
- for _, vulnerability := range resp.Vulnerabilities {
- assert.Equal(t, expectedType.ToString(), vulnerability.Technology)
- }
- }
-}
-
-// Executing git diff to ensure that the intended changes to the dependent file have been made
-func verifyDependencyFileDiff(baseBranch string, fixBranch string, packageDescriptorPaths ...string) (output []byte, err error) {
- log.Debug(fmt.Sprintf("Checking differences in %s between branches %s and %s", packageDescriptorPaths, baseBranch, fixBranch))
- // Suppress condition always false warning
- //goland:noinspection ALL
- var args []string
- if coreutils.IsWindows() {
- args = []string{"/c", "git", "diff", baseBranch, fixBranch}
- args = append(args, packageDescriptorPaths...)
- output, err = exec.Command("cmd", args...).Output()
- } else {
- args = []string{"diff", baseBranch, fixBranch}
- args = append(args, packageDescriptorPaths...)
- output, err = exec.Command("git", args...).Output()
- }
- if exitError, ok := err.(*exec.ExitError); ok {
- err = errors.New("git error: " + string(exitError.Stderr))
- }
- return
-}
diff --git a/commands/scanandfixrepos_test.go b/commands/scanandfixrepos_test.go
deleted file mode 100644
index 1c7768e7e..000000000
--- a/commands/scanandfixrepos_test.go
+++ /dev/null
@@ -1,148 +0,0 @@
-package commands
-
-import (
- "bytes"
- "fmt"
- "github.com/go-git/go-git/v5"
- "github.com/go-git/go-git/v5/config"
- "github.com/go-git/go-git/v5/plumbing"
- "github.com/go-git/go-git/v5/plumbing/object"
- "github.com/go-git/go-git/v5/plumbing/protocol/packp"
- "github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
- "github.com/jfrog/frogbot/commands/utils"
- "github.com/jfrog/froggit-go/vcsclient"
- "github.com/jfrog/froggit-go/vcsutils"
- "github.com/mholt/archiver/v3"
- "github.com/stretchr/testify/assert"
- "net/http"
- "net/http/httptest"
- "os"
- "path/filepath"
- "strings"
- "testing"
- "time"
-)
-
-const cmdDirName = "scanandfixrepos"
-
-var testScanAndFixReposConfigPath = filepath.Join("testdata", "config", "frogbot-config-scan-and-fix-repos.yml")
-var testRepositories = []string{"pip-repo", "npm-repo", "mvn-repo"}
-
-func TestScanAndFixRepos(t *testing.T) {
- serverParams, restoreEnv := verifyEnv(t)
- defer restoreEnv()
-
- var port string
- server := httptest.NewServer(createHttpHandler(t, &port, testRepositories...))
- defer server.Close()
- port = server.URL[strings.LastIndex(server.URL, ":")+1:]
-
- gitTestParams := utils.GitClientInfo{
- GitProvider: vcsutils.GitHub,
- RepoOwner: "jfrog",
- VcsInfo: vcsclient.VcsInfo{
- Token: "123456",
- APIEndpoint: server.URL,
- },
- }
-
- client, err := vcsclient.NewClientBuilder(vcsutils.GitHub).ApiEndpoint(server.URL).Token("123456").Build()
- assert.NoError(t, err)
-
- configData, err := utils.ReadConfigFromFileSystem(testScanAndFixReposConfigPath)
- assert.NoError(t, err)
-
- tmpDir, cleanUp := utils.PrepareTestEnvironment(t, "", cmdDirName)
- defer cleanUp()
-
- createReposGitEnvironment(t, tmpDir, port, testRepositories...)
- configAggregator, err := utils.BuildRepoAggregator(configData, &gitTestParams, &serverParams)
- assert.NoError(t, err)
-
- var cmd = ScanAndFixRepositories{dryRun: true}
- assert.NoError(t, cmd.Run(configAggregator, client))
-}
-
-func createReposGitEnvironment(t *testing.T, wd, port string, repositories ...string) {
- for _, repository := range repositories {
- fullWdPath := filepath.Join(wd, repository)
- dotGit, err := git.PlainInit(fullWdPath, false)
- assert.NoError(t, err)
- _, err = dotGit.CreateRemote(&config.RemoteConfig{
- Name: "origin",
- URLs: []string{fmt.Sprintf("http://127.0.0.1:%s/%s", port, repository)},
- })
- assert.NoError(t, err)
- worktree, err := dotGit.Worktree()
- assert.NoError(t, err)
- assert.NoError(t, worktree.AddWithOptions(&git.AddOptions{All: true}))
- _, err = worktree.Commit("first commit", &git.CommitOptions{
- Author: &object.Signature{
- Name: "JFrog-Frogbot",
- Email: "eco-system+frogbot@jfrog.com",
- When: time.Now(),
- },
- })
- assert.NoError(t, err)
- assert.NoError(t, archiver.Archive([]string{fullWdPath}, repository+".tar.gz"))
- }
-}
-
-func createHttpHandler(t *testing.T, port *string, projectNames ...string) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- for _, projectName := range projectNames {
- if r.RequestURI == fmt.Sprintf("/%s/info/refs?service=git-upload-pack", projectName) {
- hash := plumbing.NewHash("5e3021cf22da163f0d312d8fcf299abaa79726fb")
- capabilities := capability.NewList()
- assert.NoError(t, capabilities.Add(capability.SymRef, "HEAD:/refs/heads/master"))
- ar := &packp.AdvRefs{
- References: map[string]plumbing.Hash{
- "refs/heads/master": plumbing.NewHash("5e3021cf22da163f0d312d8fcf299abaa79726fb"),
- },
- Head: &hash,
- Capabilities: capabilities,
- }
- var buf bytes.Buffer
- assert.NoError(t, ar.Encode(&buf))
- _, err := w.Write(buf.Bytes())
- assert.NoError(t, err)
- w.WriteHeader(http.StatusOK)
- return
- }
- if r.RequestURI == fmt.Sprintf("/repos/jfrog/%s/pulls", projectName) {
- w.WriteHeader(http.StatusOK)
- return
- }
- if r.RequestURI == fmt.Sprintf("/%s", projectName) {
- file, err := os.ReadFile(fmt.Sprintf("%s.tar.gz", projectName))
- assert.NoError(t, err)
- _, err = w.Write(file)
- assert.NoError(t, err)
- return
- }
- if r.RequestURI == fmt.Sprintf("/repos/jfrog/%s/tarball/master", projectName) {
- w.Header().Add("Location", fmt.Sprintf("http://127.0.0.1:%s/%s", *port, projectName))
- w.WriteHeader(http.StatusFound)
- _, err := w.Write([]byte{})
- assert.NoError(t, err)
- return
- }
- if r.RequestURI == fmt.Sprintf("/repos/jfrog/%s/commits?page=1&per_page=1&sha=master", projectName) {
- w.WriteHeader(http.StatusOK)
- rawJson := "[\n {\n \"url\": \"https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e\",\n \"sha\": \"6dcb09b5b57875f334f61aebed695e2e4193db5e\",\n \"node_id\": \"MDY6Q29tbWl0NmRjYjA5YjViNTc4NzVmMzM0ZjYxYWViZWQ2OTVlMmU0MTkzZGI1ZQ==\",\n \"html_url\": \"https://github.com/octocat/Hello-World/commit/6dcb09b5b57875f334f61aebed695e2e4193db5e\",\n \"comments_url\": \"https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/comments\",\n \"commit\": {\n \"url\": \"https://api.github.com/repos/octocat/Hello-World/git/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e\",\n \"author\": {\n \"name\": \"Monalisa Octocat\",\n \"email\": \"support@github.com\",\n \"date\": \"2011-04-14T16:00:49Z\"\n },\n \"committer\": {\n \"name\": \"Monalisa Octocat\",\n \"email\": \"support@github.com\",\n \"date\": \"2011-04-14T16:00:49Z\"\n },\n \"message\": \"Fix all the bugs\",\n \"tree\": {\n \"url\": \"https://api.github.com/repos/octocat/Hello-World/tree/6dcb09b5b57875f334f61aebed695e2e4193db5e\",\n \"sha\": \"6dcb09b5b57875f334f61aebed695e2e4193db5e\"\n },\n \"comment_count\": 0,\n \"verification\": {\n \"verified\": false,\n \"reason\": \"unsigned\",\n \"signature\": null,\n \"payload\": null\n }\n },\n \"author\": {\n \"login\": \"octocat\",\n \"id\": 1,\n \"node_id\": \"MDQ6VXNlcjE=\",\n \"avatar_url\": \"https://github.com/images/error/octocat_happy.gif\",\n \"gravatar_id\": \"\",\n \"url\": \"https://api.github.com/users/octocat\",\n \"html_url\": \"https://github.com/octocat\",\n \"followers_url\": \"https://api.github.com/users/octocat/followers\",\n \"following_url\": \"https://api.github.com/users/octocat/following{/other_user}\",\n \"gists_url\": \"https://api.github.com/users/octocat/gists{/gist_id}\",\n \"starred_url\": \"https://api.github.com/users/octocat/starred{/owner}{/repo}\",\n \"subscriptions_url\": \"https://api.github.com/users/octocat/subscriptions\",\n \"organizations_url\": \"https://api.github.com/users/octocat/orgs\",\n \"repos_url\": \"https://api.github.com/users/octocat/repos\",\n \"events_url\": \"https://api.github.com/users/octocat/events{/privacy}\",\n \"received_events_url\": \"https://api.github.com/users/octocat/received_events\",\n \"type\": \"User\",\n \"site_admin\": false\n },\n \"committer\": {\n \"login\": \"octocat\",\n \"id\": 1,\n \"node_id\": \"MDQ6VXNlcjE=\",\n \"avatar_url\": \"https://github.com/images/error/octocat_happy.gif\",\n \"gravatar_id\": \"\",\n \"url\": \"https://api.github.com/users/octocat\",\n \"html_url\": \"https://github.com/octocat\",\n \"followers_url\": \"https://api.github.com/users/octocat/followers\",\n \"following_url\": \"https://api.github.com/users/octocat/following{/other_user}\",\n \"gists_url\": \"https://api.github.com/users/octocat/gists{/gist_id}\",\n \"starred_url\": \"https://api.github.com/users/octocat/starred{/owner}{/repo}\",\n \"subscriptions_url\": \"https://api.github.com/users/octocat/subscriptions\",\n \"organizations_url\": \"https://api.github.com/users/octocat/orgs\",\n \"repos_url\": \"https://api.github.com/users/octocat/repos\",\n \"events_url\": \"https://api.github.com/users/octocat/events{/privacy}\",\n \"received_events_url\": \"https://api.github.com/users/octocat/received_events\",\n \"type\": \"User\",\n \"site_admin\": false\n },\n \"parents\": [\n {\n \"url\": \"https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e\",\n \"sha\": \"6dcb09b5b57875f334f61aebed695e2e4193db5e\"\n }\n ]\n }\n]"
- b := []byte(rawJson)
- _, err := w.Write(b)
- assert.NoError(t, err)
- return
- }
- if r.RequestURI == fmt.Sprintf("/repos/jfrog/%v/code-scanning/sarifs", projectName) {
- w.WriteHeader(http.StatusAccepted)
- rawJson := "{\n \"id\": \"47177e22-5596-11eb-80a1-c1e54ef945c6\",\n \"url\": \"https://api.github.com/repos/octocat/hello-world/code-scanning/sarifs/47177e22-5596-11eb-80a1-c1e54ef945c6\"\n}"
- b := []byte(rawJson)
- _, err := w.Write(b)
- assert.NoError(t, err)
- return
- }
- }
- }
-}
diff --git a/commands/scanpullrequest_test.go b/commands/scanpullrequest_test.go
deleted file mode 100644
index 924a73bb7..000000000
--- a/commands/scanpullrequest_test.go
+++ /dev/null
@@ -1,878 +0,0 @@
-package commands
-
-import (
- "bytes"
- "context"
- "errors"
- "fmt"
- "github.com/jfrog/frogbot/commands/utils"
- "github.com/jfrog/froggit-go/vcsclient"
- "github.com/jfrog/froggit-go/vcsutils"
- coreconfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
- "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
- audit "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/generic"
- "github.com/jfrog/jfrog-cli-core/v2/xray/formats"
- utils2 "github.com/jfrog/jfrog-cli-core/v2/xray/utils"
- "github.com/jfrog/jfrog-client-go/utils/io/fileutils"
- "github.com/jfrog/jfrog-client-go/utils/log"
- "github.com/jfrog/jfrog-client-go/xray/services"
- "github.com/stretchr/testify/assert"
- clitool "github.com/urfave/cli/v2"
- "io"
- "net/http"
- "net/http/httptest"
- "os"
- "path/filepath"
- "strings"
- "testing"
- "time"
-)
-
-const (
- testMultiDirProjConfigPath = "testdata/config/frogbot-config-multi-dir-test-proj.yml"
- testMultiDirProjConfigPathNoFail = "testdata/config/frogbot-config-multi-dir-test-proj-no-fail.yml"
- testProjSubdirConfigPath = "testdata/config/frogbot-config-test-proj-subdir.yml"
- testCleanProjConfigPath = "testdata/config/frogbot-config-clean-test-proj.yml"
- testProjConfigPath = "testdata/config/frogbot-config-test-proj.yml"
- testProjConfigPathNoFail = "testdata/config/frogbot-config-test-proj-no-fail.yml"
- testSourceBranchName = "pr"
- testTargetBranchName = "master"
-)
-
-func TestCreateVulnerabilitiesRows(t *testing.T) {
- // Previous scan with only one violation - XRAY-1
- previousScan := services.ScanResponse{
- Violations: []services.Violation{{
- IssueId: "XRAY-1",
- Summary: "summary-1",
- Severity: "high",
- Cves: []services.Cve{},
- ViolationType: "security",
- Components: map[string]services.Component{"component-A": {}, "component-B": {}},
- }},
- }
-
- // Current scan with 2 violations - XRAY-1 and XRAY-2
- currentScan := services.ScanResponse{
- Violations: []services.Violation{
- {
- IssueId: "XRAY-1",
- Summary: "summary-1",
- Severity: "high",
- ViolationType: "security",
- Components: map[string]services.Component{"component-A": {}, "component-B": {}},
- },
- {
- IssueId: "XRAY-2",
- Summary: "summary-2",
- ViolationType: "security",
- Severity: "low",
- Components: map[string]services.Component{"component-C": {}, "component-D": {}},
- },
- },
- }
-
- // Run createNewIssuesRows and make sure that only the XRAY-2 violation exists in the results
- rows, err := createNewIssuesRows(
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}}},
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}},
- )
- assert.NoError(t, err)
- assert.Len(t, rows, 2)
- assert.Equal(t, "XRAY-2", rows[0].IssueId)
- assert.Equal(t, "low", rows[0].Severity)
- assert.Equal(t, "XRAY-2", rows[1].IssueId)
- assert.Equal(t, "low", rows[1].Severity)
-
- impactedPackageOne := rows[0].ImpactedDependencyName
- impactedPackageTwo := rows[1].ImpactedDependencyName
- assert.ElementsMatch(t, []string{"component-C", "component-D"}, []string{impactedPackageOne, impactedPackageTwo})
-}
-
-func TestCreateVulnerabilitiesRowsCaseNoPrevViolations(t *testing.T) {
- // Previous scan with no violation
- previousScan := services.ScanResponse{
- Violations: []services.Violation{},
- }
-
- // Current scan with 2 violations - XRAY-1 and XRAY-2
- currentScan := services.ScanResponse{
- Violations: []services.Violation{
- {
- IssueId: "XRAY-1",
- Summary: "summary-1",
- Severity: "high",
- ViolationType: "security",
- Components: map[string]services.Component{"component-A": {}},
- },
- {
- IssueId: "XRAY-2",
- Summary: "summary-2",
- ViolationType: "security",
- Severity: "low",
- Components: map[string]services.Component{"component-C": {}},
- },
- },
- }
-
- expected := []formats.VulnerabilityOrViolationRow{
- {
- IssueId: "XRAY-1",
- Severity: "high",
- ImpactedDependencyName: "component-A",
- },
- {
- IssueId: "XRAY-2",
- Severity: "low",
- ImpactedDependencyName: "component-C",
- },
- }
-
- // Run createNewIssuesRows and expect both XRAY-1 and XRAY-2 violation in the results
- rows, err := createNewIssuesRows(
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}}},
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}},
- )
- assert.NoError(t, err)
- assert.Len(t, rows, 2)
- assert.ElementsMatch(t, expected, rows)
-}
-
-func TestGetNewViolationsCaseNoNewViolations(t *testing.T) {
- // Previous scan with 2 violations - XRAY-1 and XRAY-2
- previousScan := services.ScanResponse{
- Violations: []services.Violation{
- {
- IssueId: "XRAY-1",
- Severity: "high",
- ViolationType: "security",
- Components: map[string]services.Component{"component-A": {}},
- },
- {
- IssueId: "XRAY-2",
- Summary: "summary-2",
- ViolationType: "security",
- Severity: "low",
- Components: map[string]services.Component{"component-C": {}},
- },
- },
- }
-
- // Current scan with no violation
- currentScan := services.ScanResponse{
- Violations: []services.Violation{},
- }
-
- // Run createNewIssuesRows and expect no violations in the results
- rows, err := createNewIssuesRows(
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}}},
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}},
- )
- assert.NoError(t, err)
- assert.Len(t, rows, 0)
-}
-
-func TestGetAllVulnerabilities(t *testing.T) {
- // Current scan with 2 vulnerabilities - XRAY-1 and XRAY-2
- currentScan := services.ScanResponse{
- Vulnerabilities: []services.Vulnerability{
- {
- IssueId: "XRAY-1",
- Summary: "summary-1",
- Severity: "high",
- Components: map[string]services.Component{"component-A": {}, "component-B": {}},
- },
- {
- IssueId: "XRAY-2",
- Summary: "summary-2",
- Severity: "low",
- Components: map[string]services.Component{"component-C": {}, "component-D": {}},
- },
- },
- }
-
- expected := []formats.VulnerabilityOrViolationRow{
- {
- Summary: "summary-1",
- IssueId: "XRAY-1",
- Severity: "high",
- ImpactedDependencyName: "component-A",
- },
- {
- Summary: "summary-1",
- IssueId: "XRAY-1",
- Severity: "high",
- ImpactedDependencyName: "component-B",
- },
- {
- Summary: "summary-2",
- IssueId: "XRAY-2",
- Severity: "low",
- ImpactedDependencyName: "component-C",
- },
- {
- Summary: "summary-2",
- IssueId: "XRAY-2",
- Severity: "low",
- ImpactedDependencyName: "component-D",
- },
- }
-
- // Run createAllIssuesRows and make sure that XRAY-1 and XRAY-2 vulnerabilities exists in the results
- rows, err := getScanVulnerabilitiesRows(&audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}})
- assert.NoError(t, err)
- assert.Len(t, rows, 4)
- assert.ElementsMatch(t, expected, rows)
-}
-
-func TestGetNewVulnerabilities(t *testing.T) {
- // Previous scan with only one vulnerability - XRAY-1
- previousScan := services.ScanResponse{
- Vulnerabilities: []services.Vulnerability{{
- IssueId: "XRAY-1",
- Summary: "summary-1",
- Severity: "high",
- Cves: []services.Cve{{Id: "CVE-2023-1234"}},
- Components: map[string]services.Component{"component-A": {}, "component-B": {}},
- Technology: coreutils.Maven.ToString(),
- }},
- }
-
- // Current scan with 2 vulnerabilities - XRAY-1 and XRAY-2
- currentScan := services.ScanResponse{
- Vulnerabilities: []services.Vulnerability{
- {
- IssueId: "XRAY-1",
- Summary: "summary-1",
- Severity: "high",
- Cves: []services.Cve{{Id: "CVE-2023-1234"}},
- Components: map[string]services.Component{"component-A": {}, "component-B": {}},
- Technology: coreutils.Maven.ToString(),
- },
- {
- IssueId: "XRAY-2",
- Summary: "summary-2",
- Severity: "low",
- Cves: []services.Cve{{Id: "CVE-2023-4321"}},
- Components: map[string]services.Component{"component-C": {}, "component-D": {}},
- Technology: coreutils.Yarn.ToString(),
- },
- },
- }
-
- expected := []formats.VulnerabilityOrViolationRow{
- {
- Summary: "summary-2",
- Applicable: "Applicable",
- IssueId: "XRAY-2",
- Severity: "low",
- ImpactedDependencyName: "component-C",
- Cves: []formats.CveRow{{Id: "CVE-2023-4321"}},
- Technology: coreutils.Yarn,
- },
- {
- Summary: "summary-2",
- Applicable: "Applicable",
- IssueId: "XRAY-2",
- Severity: "low",
- Cves: []formats.CveRow{{Id: "CVE-2023-4321"}},
- ImpactedDependencyName: "component-D",
- Technology: coreutils.Yarn,
- },
- }
-
- // Run createNewIssuesRows and make sure that only the XRAY-2 vulnerability exists in the results
- rows, err := createNewIssuesRows(
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}, EntitledForJas: true, ApplicabilityScanResults: map[string]string{"CVE-2023-4321": "Applicable"}}},
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}, EntitledForJas: true, ApplicabilityScanResults: map[string]string{"CVE-2023-4321": "Applicable"}}},
- )
- assert.NoError(t, err)
- assert.Len(t, rows, 2)
- assert.ElementsMatch(t, expected, rows)
-}
-
-func TestGetNewVulnerabilitiesCaseNoPrevVulnerabilities(t *testing.T) {
- // Previous scan with no vulnerabilities
- previousScan := services.ScanResponse{
- Vulnerabilities: []services.Vulnerability{},
- }
-
- // Current scan with 2 vulnerabilities - XRAY-1 and XRAY-2
- currentScan := services.ScanResponse{
- Vulnerabilities: []services.Vulnerability{
- {
- IssueId: "XRAY-1",
- Summary: "summary-1",
- Severity: "high",
- ExtendedInformation: &services.ExtendedInformation{FullDescription: "description-1"},
- Components: map[string]services.Component{"component-A": {}},
- },
- {
- IssueId: "XRAY-2",
- Summary: "summary-2",
- Severity: "low",
- ExtendedInformation: &services.ExtendedInformation{FullDescription: "description-2"},
- Components: map[string]services.Component{"component-B": {}},
- },
- },
- }
-
- expected := []formats.VulnerabilityOrViolationRow{
- {
- Summary: "summary-2",
- IssueId: "XRAY-2",
- Severity: "low",
- ImpactedDependencyName: "component-B",
- JfrogResearchInformation: &formats.JfrogResearchInformation{Details: "description-2"},
- },
- {
- Summary: "summary-1",
- IssueId: "XRAY-1",
- Severity: "high",
- ImpactedDependencyName: "component-A",
- JfrogResearchInformation: &formats.JfrogResearchInformation{Details: "description-1"},
- },
- }
-
- // Run createNewIssuesRows and expect both XRAY-1 and XRAY-2 vulnerability in the results
- rows, err := createNewIssuesRows(
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}}},
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}},
- )
- assert.NoError(t, err)
- assert.Len(t, rows, 2)
- assert.ElementsMatch(t, expected, rows)
-}
-
-func TestGetNewVulnerabilitiesCaseNoNewVulnerabilities(t *testing.T) {
- // Previous scan with 2 vulnerabilities - XRAY-1 and XRAY-2
- previousScan := services.ScanResponse{
- Vulnerabilities: []services.Vulnerability{
- {
- IssueId: "XRAY-1",
- Summary: "summary-1",
- Severity: "high",
- Components: map[string]services.Component{"component-A": {}},
- },
- {
- IssueId: "XRAY-2",
- Summary: "summary-2",
- Severity: "low",
- Components: map[string]services.Component{"component-B": {}},
- },
- },
- }
-
- // Current scan with no vulnerabilities
- currentScan := services.ScanResponse{
- Vulnerabilities: []services.Vulnerability{},
- }
-
- // Run createNewIssuesRows and expect no vulnerability in the results
- rows, err := createNewIssuesRows(
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}}},
- &audit.Results{ExtendedScanResults: &utils2.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}},
- )
- assert.NoError(t, err)
- assert.Len(t, rows, 0)
-}
-
-func TestCreatePullRequestMessageNoVulnerabilities(t *testing.T) {
- vulnerabilities := []formats.VulnerabilityOrViolationRow{}
- message := createPullRequestMessage(vulnerabilities, nil, &utils.StandardOutput{})
-
- expectedMessageByte, err := os.ReadFile(filepath.Join("testdata", "messages", "novulnerabilities.md"))
- assert.NoError(t, err)
- expectedMessage := strings.ReplaceAll(string(expectedMessageByte), "\r\n", "\n")
- assert.Equal(t, expectedMessage, message)
-
- outputWriter := &utils.StandardOutput{}
- outputWriter.SetVcsProvider(vcsutils.GitLab)
- message = createPullRequestMessage(vulnerabilities, nil, outputWriter)
-
- expectedMessageByte, err = os.ReadFile(filepath.Join("testdata", "messages", "novulnerabilitiesMR.md"))
- assert.NoError(t, err)
- expectedMessage = strings.ReplaceAll(string(expectedMessageByte), "\r\n", "\n")
- assert.Equal(t, expectedMessage, message)
-}
-
-func TestCreatePullRequestMessage(t *testing.T) {
- vulnerabilities := []formats.VulnerabilityOrViolationRow{
- {
- Severity: "High",
- Applicable: "Undetermined",
- ImpactedDependencyName: "github.com/nats-io/nats-streaming-server",
- ImpactedDependencyVersion: "v0.21.0",
- FixedVersions: []string{"[0.24.1]"},
- Components: []formats.ComponentRow{
- {
- Name: "github.com/nats-io/nats-streaming-server",
- Version: "v0.21.0",
- },
- },
- Cves: []formats.CveRow{{Id: "CVE-2022-24450"}},
- },
- {
- Severity: "High",
- Applicable: "Undetermined",
- ImpactedDependencyName: "github.com/mholt/archiver/v3",
- ImpactedDependencyVersion: "v3.5.1",
- Components: []formats.ComponentRow{
- {
- Name: "github.com/mholt/archiver/v3",
- Version: "v3.5.1",
- },
- },
- Cves: []formats.CveRow{},
- },
- {
- Severity: "Medium",
- Applicable: "Undetermined",
- ImpactedDependencyName: "github.com/nats-io/nats-streaming-server",
- ImpactedDependencyVersion: "v0.21.0",
- FixedVersions: []string{"[0.24.3]"},
- Components: []formats.ComponentRow{
- {
- Name: "github.com/nats-io/nats-streaming-server",
- Version: "v0.21.0",
- },
- },
- Cves: []formats.CveRow{{Id: "CVE-2022-26652"}},
- },
- }
- iac := []formats.IacSecretsRow{
- {
- Severity: "Low",
- File: "test.js",
- LineColumn: "1:20",
- Text: "kms_key_id='' was detected",
- Type: "aws_cloudtrail_encrypt",
- },
- {
- Severity: "High",
- File: "test2.js",
- LineColumn: "4:30",
- Text: "Deprecated TLS version was detected",
- Type: "aws_cloudfront_tls_version",
- },
- }
- writerOutput := &utils.StandardOutput{}
- writerOutput.SetJasOutputFlags(true, true)
- message := createPullRequestMessage(vulnerabilities, iac, writerOutput)
-
- 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 | 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 | Undetermined | 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 | Undetermined | 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 = "\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 | Undetermined | 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 | Undetermined | 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 | Undetermined | 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)
-}
-
-func TestRunInstallIfNeeded(t *testing.T) {
- scanSetup := utils.ScanDetails{
- Project: &utils.Project{},
- }
- scanSetup.SetFailOnInstallationErrors(true)
- assert.NoError(t, runInstallIfNeeded(&scanSetup, ""))
- tmpDir, err := fileutils.CreateTempDir()
- assert.NoError(t, err)
- defer func() {
- err = fileutils.RemoveTempDir(tmpDir)
- assert.NoError(t, err)
- }()
- params := &utils.Project{
- InstallCommandName: "echo",
- InstallCommandArgs: []string{"Hello"},
- }
- scanSetup.Project = params
- assert.NoError(t, runInstallIfNeeded(&scanSetup, tmpDir))
-
- scanSetup.InstallCommandName = "not-exist"
- scanSetup.InstallCommandArgs = []string{"1", "2"}
- scanSetup.SetFailOnInstallationErrors(false)
- assert.NoError(t, runInstallIfNeeded(&scanSetup, tmpDir))
-
- params = &utils.Project{
- InstallCommandName: "not-existed",
- InstallCommandArgs: []string{"1", "2"},
- }
- scanSetup.Project = params
- scanSetup.SetFailOnInstallationErrors(true)
- assert.Error(t, runInstallIfNeeded(&scanSetup, tmpDir))
-}
-
-func TestScanPullRequest(t *testing.T) {
- testScanPullRequest(t, testProjConfigPath, "test-proj", true)
-}
-
-func TestScanPullRequestNoFail(t *testing.T) {
- testScanPullRequest(t, testProjConfigPathNoFail, "test-proj", false)
-}
-
-func TestScanPullRequestSubdir(t *testing.T) {
- testScanPullRequest(t, testProjSubdirConfigPath, "test-proj-subdir", true)
-}
-
-func TestScanPullRequestNoIssues(t *testing.T) {
- testScanPullRequest(t, testCleanProjConfigPath, "clean-test-proj", false)
-}
-
-func TestScanPullRequestMultiWorkDir(t *testing.T) {
- testScanPullRequest(t, testMultiDirProjConfigPath, "multi-dir-test-proj", true)
-}
-
-func TestScanPullRequestMultiWorkDirNoFail(t *testing.T) {
- testScanPullRequest(t, testMultiDirProjConfigPathNoFail, "multi-dir-test-proj", false)
-}
-
-func testScanPullRequest(t *testing.T, configPath, projectName string, failOnSecurityIssues bool) {
- params, restoreEnv := verifyEnv(t)
- defer restoreEnv()
-
- // Create mock GitLab server
- server := httptest.NewServer(createGitLabHandler(t, projectName))
- defer server.Close()
-
- configAggregator, client := prepareConfigAndClient(t, configPath, server, params)
- _, cleanUp := utils.PrepareTestEnvironment(t, projectName, "scanpullrequest")
- defer cleanUp()
-
- // Run "frogbot scan pull request"
- var scanPullRequest ScanPullRequestCmd
- err := scanPullRequest.Run(configAggregator, client)
- if failOnSecurityIssues {
- assert.EqualErrorf(t, err, securityIssueFoundErr, "Error should be: %v, got: %v", securityIssueFoundErr, err)
- } else {
- assert.NoError(t, err)
- }
-
- // Check env sanitize
- err = utils.SanitizeEnv()
- assert.NoError(t, err)
- utils.AssertSanitizedEnv(t)
-}
-
-func TestVerifyGitHubFrogbotEnvironment(t *testing.T) {
- // Init mock
- client := mockVcsClient(t)
- environment := "frogbot"
- client.EXPECT().GetRepositoryInfo(context.Background(), gitParams.RepoOwner, gitParams.RepoName).Return(vcsclient.RepositoryInfo{}, nil)
- client.EXPECT().GetRepositoryEnvironmentInfo(context.Background(), gitParams.RepoOwner, gitParams.RepoName, environment).Return(vcsclient.RepositoryEnvironmentInfo{Reviewers: []string{"froggy"}}, nil)
- assert.NoError(t, os.Setenv(utils.GitHubActionsEnv, "true"))
-
- // Run verifyGitHubFrogbotEnvironment
- err := verifyGitHubFrogbotEnvironment(client, gitParams)
- assert.NoError(t, err)
-}
-
-func TestVerifyGitHubFrogbotEnvironmentNoEnv(t *testing.T) {
- // Redirect log to avoid negative output
- previousLogger := redirectLogOutputToNil()
- defer log.SetLogger(previousLogger)
-
- // Init mock
- client := mockVcsClient(t)
- environment := "frogbot"
- client.EXPECT().GetRepositoryInfo(context.Background(), gitParams.RepoOwner, gitParams.RepoName).Return(vcsclient.RepositoryInfo{}, nil)
- client.EXPECT().GetRepositoryEnvironmentInfo(context.Background(), gitParams.RepoOwner, gitParams.RepoName, environment).Return(vcsclient.RepositoryEnvironmentInfo{}, errors.New("404"))
- assert.NoError(t, os.Setenv(utils.GitHubActionsEnv, "true"))
-
- // Run verifyGitHubFrogbotEnvironment
- err := verifyGitHubFrogbotEnvironment(client, gitParams)
- assert.ErrorContains(t, err, noGitHubEnvErr)
-}
-
-func TestVerifyGitHubFrogbotEnvironmentNoReviewers(t *testing.T) {
- // Init mock
- client := mockVcsClient(t)
- environment := "frogbot"
- client.EXPECT().GetRepositoryInfo(context.Background(), gitParams.RepoOwner, gitParams.RepoName).Return(vcsclient.RepositoryInfo{}, nil)
- client.EXPECT().GetRepositoryEnvironmentInfo(context.Background(), gitParams.RepoOwner, gitParams.RepoName, environment).Return(vcsclient.RepositoryEnvironmentInfo{}, nil)
- assert.NoError(t, os.Setenv(utils.GitHubActionsEnv, "true"))
-
- // Run verifyGitHubFrogbotEnvironment
- err := verifyGitHubFrogbotEnvironment(client, gitParams)
- assert.ErrorContains(t, err, noGitHubEnvReviewersErr)
-}
-
-func TestVerifyGitHubFrogbotEnvironmentOnPrem(t *testing.T) {
- repoConfig := &utils.Repository{
- Params: utils.Params{Git: utils.Git{GitClientInfo: utils.GitClientInfo{
- VcsInfo: vcsclient.VcsInfo{APIEndpoint: "https://acme.vcs.io"}}},
- },
- }
-
- // Run verifyGitHubFrogbotEnvironment
- err := verifyGitHubFrogbotEnvironment(&vcsclient.GitHubClient{}, repoConfig)
- assert.NoError(t, err)
-}
-
-func prepareConfigAndClient(t *testing.T, configPath string, server *httptest.Server, serverParams coreconfig.ServerDetails) (utils.RepoAggregator, vcsclient.VcsClient) {
- gitTestParams := &utils.GitClientInfo{
- GitProvider: vcsutils.GitHub,
- RepoOwner: "jfrog",
- VcsInfo: vcsclient.VcsInfo{
- Token: "123456",
- APIEndpoint: server.URL,
- },
- }
- utils.SetEnvAndAssert(t, map[string]string{utils.GitPullRequestIDEnv: "1"})
-
- configData, err := utils.ReadConfigFromFileSystem(configPath)
- assert.NoError(t, err)
- configAggregator, err := utils.BuildRepoAggregator(configData, gitTestParams, &serverParams)
- assert.NoError(t, err)
-
- client, err := vcsclient.NewClientBuilder(vcsutils.GitLab).ApiEndpoint(server.URL).Token("123456").Build()
- assert.NoError(t, err)
- return configAggregator, client
-}
-
-func TestScanPullRequestError(t *testing.T) {
- app := clitool.App{Commands: GetCommands()}
- assert.Error(t, app.Run([]string{"frogbot", "spr"}))
-}
-
-// 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 {
- // Return 200 on ping
- case r.RequestURI == "/api/v4/":
- w.WriteHeader(http.StatusOK)
- // Mimic get pull request by ID
- 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)
- // Mimic download specific branch to scan
- 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)
- // Download repository mock
- 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)
- _, err = w.Write(repoFile)
- assert.NoError(t, err)
- return
- // clean-test-proj should not include any vulnerabilities so assertion is not needed.
- 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 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)
- assert.NotEmpty(t, buf.String())
-
- var expectedResponse []byte
- switch {
- case strings.Contains(projectName, "multi-dir"):
- expectedResponse, err = os.ReadFile(filepath.Join("..", "expectedResponseMultiDir.json"))
- case strings.Contains(projectName, "pip"):
- expectedResponse, err = os.ReadFile(filepath.Join("..", "expectedResponsePip.json"))
- default:
- expectedResponse, err = os.ReadFile(filepath.Join("..", "expectedResponse.json"))
- }
- assert.NoError(t, err)
- assert.JSONEq(t, string(expectedResponse), buf.String())
-
- w.WriteHeader(http.StatusOK)
- _, err = w.Write([]byte("{}"))
- assert.NoError(t, err)
- 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)
- }
- }
-}
-
-// Check connection details with JFrog instance.
-// Return a callback method that restores the credentials after the test is done.
-func verifyEnv(t *testing.T) (server coreconfig.ServerDetails, restoreFunc func()) {
- url := strings.TrimSuffix(os.Getenv(utils.JFrogUrlEnv), "/")
- username := os.Getenv(utils.JFrogUserEnv)
- password := os.Getenv(utils.JFrogPasswordEnv)
- token := os.Getenv(utils.JFrogTokenEnv)
- if url == "" {
- assert.FailNow(t, fmt.Sprintf("'%s' is not set", utils.JFrogUrlEnv))
- }
- if token == "" && (username == "" || password == "") {
- assert.FailNow(t, fmt.Sprintf("'%s' or '%s' and '%s' are not set", utils.JFrogTokenEnv, utils.JFrogUserEnv, utils.JFrogPasswordEnv))
- }
- server.Url = url
- server.XrayUrl = url + "/xray/"
- server.ArtifactoryUrl = url + "/artifactory/"
- server.User = username
- server.Password = password
- server.AccessToken = token
- restoreFunc = func() {
- utils.SetEnvAndAssert(t, map[string]string{
- utils.JFrogUrlEnv: url,
- utils.JFrogTokenEnv: token,
- utils.JFrogUserEnv: username,
- utils.JFrogPasswordEnv: password,
- utils.GitAggregateFixesEnv: "FALSE",
- })
- }
- return
-}
-
-func TestGetFullPathWorkingDirs(t *testing.T) {
- sampleProject := utils.Project{
- WorkingDirs: []string{filepath.Join("a", "b"), filepath.Join("a", "b", "c"), ".", filepath.Join("c", "d", "e", "f")},
- }
- baseWd := "tempDir"
- fullPathWds := getFullPathWorkingDirs(sampleProject.WorkingDirs, baseWd)
- expectedWds := []string{filepath.Join("tempDir", "a", "b"), filepath.Join("tempDir", "a", "b", "c"), "tempDir", filepath.Join("tempDir", "c", "d", "e", "f")}
- for _, expectedWd := range expectedWds {
- assert.Contains(t, fullPathWds, expectedWd)
- }
-}
-
-func TestCreateNewIacRows(t *testing.T) {
- testCases := []struct {
- name string
- targetIacResults []utils2.IacOrSecretResult
- sourceIacResults []utils2.IacOrSecretResult
- expectedAddedIacVulnerabilities []formats.IacSecretsRow
- }{
- {
- name: "No vulnerabilities in source IaC results",
- targetIacResults: []utils2.IacOrSecretResult{
- {
- Severity: "High",
- File: "file1",
- LineColumn: "1:10",
- Type: "Secret",
- Text: "Sensitive information",
- },
- },
- sourceIacResults: []utils2.IacOrSecretResult{},
- expectedAddedIacVulnerabilities: []formats.IacSecretsRow{},
- },
- {
- name: "No vulnerabilities in target IaC results",
- targetIacResults: []utils2.IacOrSecretResult{},
- sourceIacResults: []utils2.IacOrSecretResult{
- {
- Severity: "High",
- File: "file1",
- LineColumn: "1:10",
- Type: "Secret",
- Text: "Sensitive information",
- },
- },
- expectedAddedIacVulnerabilities: []formats.IacSecretsRow{
- {
- Severity: "High",
- File: "file1",
- LineColumn: "1:10",
- Type: "Secret",
- Text: "Sensitive information",
- SeverityNumValue: 10,
- },
- },
- },
- {
- name: "Some new vulnerabilities in source IaC results",
- targetIacResults: []utils2.IacOrSecretResult{
- {
- Severity: "High",
- File: "file1",
- LineColumn: "1:10",
- Type: "Secret",
- Text: "Sensitive information",
- },
- },
- sourceIacResults: []utils2.IacOrSecretResult{
- {
- Severity: "Medium",
- File: "file2",
- LineColumn: "2:5",
- Type: "Secret",
- Text: "Confidential data",
- },
- },
- expectedAddedIacVulnerabilities: []formats.IacSecretsRow{
- {
- Severity: "Medium",
- SeverityNumValue: 8,
- File: "file2",
- LineColumn: "2:5",
- Text: "Confidential data",
- Type: "Secret",
- },
- },
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- addedIacVulnerabilities := createNewIacRows(tc.targetIacResults, tc.sourceIacResults)
- assert.ElementsMatch(t, tc.expectedAddedIacVulnerabilities, addedIacVulnerabilities)
- })
- }
-}
-
-func TestDeletePreviousPullRequestMessages(t *testing.T) {
- repository := &utils.Repository{
- Params: utils.Params{
- Git: utils.Git{
- GitClientInfo: utils.GitClientInfo{RepoName: "repo", RepoOwner: "owner"},
- PullRequestID: 17,
- },
- },
- OutputWriter: &utils.StandardOutput{},
- }
- client := mockVcsClient(t)
-
- // Test with comment returned
- client.EXPECT().ListPullRequestComments(context.Background(), "owner", "repo", 17).Return([]vcsclient.CommentInfo{
- {ID: 20, Content: utils.GetBanner(utils.NoVulnerabilityPrBannerSource) + "text \n table\n text text text", Created: time.Unix(3, 0)},
- }, nil)
- client.EXPECT().DeletePullRequestComment(context.Background(), "owner", "repo", 17, 20).Return(nil).AnyTimes()
- err := deleteExistingPullRequestComment(repository, client)
- assert.NoError(t, err)
-
- // Test with no comment returned
- client.EXPECT().ListPullRequestComments(context.Background(), "owner", "repo", 17).Return([]vcsclient.CommentInfo{}, nil)
- err = deleteExistingPullRequestComment(repository, client)
- assert.NoError(t, err)
-
- // Test with error returned
- client.EXPECT().ListPullRequestComments(context.Background(), "owner", "repo", 17).Return(nil, errors.New("error"))
- err = deleteExistingPullRequestComment(repository, client)
- assert.Error(t, err)
-}
-
-// Set new logger with output redirection to a null logger. This is useful for negative tests.
-// Caller is responsible to set the old log back.
-func redirectLogOutputToNil() (previousLog log.Log) {
- previousLog = log.Logger
- newLog := log.NewLogger(log.ERROR, nil)
- newLog.SetOutputWriter(io.Discard)
- newLog.SetLogsWriter(io.Discard, 0)
- log.SetLogger(newLog)
- return previousLog
-}
diff --git a/commands/scanpullrequests_test.go b/commands/scanpullrequests_test.go
index 57f07c4bc..eaac53917 100644
--- a/commands/scanpullrequests_test.go
+++ b/commands/scanpullrequests_test.go
@@ -3,17 +3,17 @@ package commands
import (
"context"
"fmt"
- "github.com/jfrog/froggit-go/vcsutils"
- "github.com/stretchr/testify/assert"
- "path/filepath"
- "testing"
- "time"
-
"github.com/golang/mock/gomock"
"github.com/jfrog/frogbot/commands/testdata"
"github.com/jfrog/frogbot/commands/utils"
"github.com/jfrog/froggit-go/vcsclient"
+ coreconfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
+ "github.com/stretchr/testify/assert"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
)
var gitParams = &utils.Repository{
@@ -37,71 +37,12 @@ type MockParams struct {
}
//go:generate go run github.com/golang/mock/mockgen@v1.6.0 -destination=testdata/vcsclientmock.go -package=testdata github.com/jfrog/froggit-go/vcsclient VcsClient
-func TestShouldScanPullRequestNewPR(t *testing.T) {
- // Init mock
- client := mockVcsClient(t)
- prID := 0
- client.EXPECT().ListPullRequestComments(context.Background(), gitParams.RepoOwner, gitParams.RepoName, prID).Return([]vcsclient.CommentInfo{}, nil)
- // Run handleFrogbotLabel
- shouldScan, err := shouldScanPullRequest(*gitParams, client, prID)
- assert.NoError(t, err)
- assert.True(t, shouldScan)
-}
-
-func TestShouldScanPullRequestReScan(t *testing.T) {
- // Init mock
- client := mockVcsClient(t)
- prID := 0
- client.EXPECT().ListPullRequestComments(context.Background(), gitParams.RepoOwner, gitParams.RepoName, prID).Return([]vcsclient.CommentInfo{
- {Content: utils.GetSimplifiedTitle(utils.VulnerabilitiesPrBannerSource) + "text \n table\n text text text", Created: time.Unix(1, 0)},
- {Content: utils.RescanRequestComment, Created: time.Unix(1, 1)},
- }, nil)
- shouldScan, err := shouldScanPullRequest(*gitParams, client, prID)
- assert.NoError(t, err)
- assert.True(t, shouldScan)
-}
-
-func TestShouldNotScanPullRequestReScan(t *testing.T) {
- // Init mock
- client := mockVcsClient(t)
- prID := 0
- client.EXPECT().ListPullRequestComments(context.Background(), gitParams.RepoOwner, gitParams.RepoName, prID).Return([]vcsclient.CommentInfo{
- {Content: utils.GetSimplifiedTitle(utils.VulnerabilitiesPrBannerSource) + "text \n table\n text text text", Created: time.Unix(1, 0)},
- {Content: utils.RescanRequestComment, Created: time.Unix(1, 1)},
- {Content: utils.GetSimplifiedTitle(utils.NoVulnerabilityPrBannerSource) + "text \n table\n text text text", Created: time.Unix(3, 0)},
- }, nil)
- shouldScan, err := shouldScanPullRequest(*gitParams, client, prID)
- assert.NoError(t, err)
- assert.False(t, shouldScan)
-}
-
-func TestShouldNotScanPullRequest(t *testing.T) {
- // Init mock
- client := mockVcsClient(t)
- prID := 0
- client.EXPECT().ListPullRequestComments(context.Background(), gitParams.RepoOwner, gitParams.RepoName, prID).Return([]vcsclient.CommentInfo{
- {Content: utils.GetSimplifiedTitle(utils.NoVulnerabilityPrBannerSource) + "text \n table\n text text text", Created: time.Unix(3, 0)},
- }, nil)
- shouldScan, err := shouldScanPullRequest(*gitParams, client, prID)
- assert.NoError(t, err)
- assert.False(t, shouldScan)
-}
func mockVcsClient(t *testing.T) *testdata.MockVcsClient {
mockCtrl := gomock.NewController(t)
return testdata.NewMockVcsClient(mockCtrl)
}
-func TestShouldNotScanPullRequestError(t *testing.T) {
- // Init mock
- client := mockVcsClient(t)
- prID := 0
- client.EXPECT().ListPullRequestComments(context.Background(), gitParams.RepoOwner, gitParams.RepoName, prID).Return([]vcsclient.CommentInfo{}, fmt.Errorf("Bad Request"))
- shouldScan, err := shouldScanPullRequest(*gitParams, client, prID)
- assert.Error(t, err)
- assert.False(t, shouldScan)
-}
-
func TestScanAllPullRequestsMultiRepo(t *testing.T) {
server, restoreEnv := verifyEnv(t)
defer restoreEnv()
@@ -156,44 +97,6 @@ func TestScanAllPullRequestsMultiRepo(t *testing.T) {
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) {
- // This integration test, requires JFrog platform connection details
- server, restoreEnv := verifyEnv(t)
- defer restoreEnv()
- falseVal := false
- gitParams.Git.GitProvider = vcsutils.BitbucketServer
- params := utils.Params{
- Scan: utils.Scan{
- FailOnSecurityIssues: &falseVal,
- Projects: []utils.Project{{
- InstallCommandName: "npm",
- InstallCommandArgs: []string{"i"},
- WorkingDirs: []string{"."},
- UseWrapper: &utils.TrueVal,
- }},
- },
- Git: gitParams.Git,
- }
- repoParams := &utils.Repository{
- OutputWriter: &utils.SimplifiedOutput{},
- Server: server,
- Params: params,
- }
- paramsAggregator := utils.RepoAggregator{}
- paramsAggregator = append(paramsAggregator, *repoParams)
- var frogbotMessages []string
- client := getMockClient(t, &frogbotMessages, MockParams{repoParams.RepoName, repoParams.RepoOwner, "test-proj-with-vulnerability", "test-proj"})
- scanAllPullRequestsCmd := &ScanAllPullRequestsCmd{}
- 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 {
// Init mock
client := mockVcsClient(t)
@@ -229,3 +132,34 @@ func fakeRepoDownload(_ context.Context, _, _, testProject, targetDir string) er
}
return fileutils.CopyDir(sourceDir, targetDir, true, []string{})
}
+
+// Check connection details with JFrog instance.
+// Return a callback method that restores the credentials after the test is done.
+func verifyEnv(t *testing.T) (server coreconfig.ServerDetails, restoreFunc func()) {
+ url := strings.TrimSuffix(os.Getenv(utils.JFrogUrlEnv), "/")
+ username := os.Getenv(utils.JFrogUserEnv)
+ password := os.Getenv(utils.JFrogPasswordEnv)
+ token := os.Getenv(utils.JFrogTokenEnv)
+ if url == "" {
+ assert.FailNow(t, fmt.Sprintf("'%s' is not set", utils.JFrogUrlEnv))
+ }
+ if token == "" && (username == "" || password == "") {
+ assert.FailNow(t, fmt.Sprintf("'%s' or '%s' and '%s' are not set", utils.JFrogTokenEnv, utils.JFrogUserEnv, utils.JFrogPasswordEnv))
+ }
+ server.Url = url
+ server.XrayUrl = url + "/xray/"
+ server.ArtifactoryUrl = url + "/artifactory/"
+ server.User = username
+ server.Password = password
+ server.AccessToken = token
+ restoreFunc = func() {
+ utils.SetEnvAndAssert(t, map[string]string{
+ utils.JFrogUrlEnv: url,
+ utils.JFrogTokenEnv: token,
+ utils.JFrogUserEnv: username,
+ utils.JFrogPasswordEnv: password,
+ utils.GitAggregateFixesEnv: "FALSE",
+ })
+ }
+ return
+}