github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/cmd/detectExecuteScan_test.go (about)

     1  //go:build unit
     2  // +build unit
     3  
     4  package cmd
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"fmt"
    10  
    11  	"io"
    12  	"net/http"
    13  	"os"
    14  	"path/filepath"
    15  	"testing"
    16  
    17  	bd "github.com/SAP/jenkins-library/pkg/blackduck"
    18  	piperGithub "github.com/SAP/jenkins-library/pkg/github"
    19  	piperhttp "github.com/SAP/jenkins-library/pkg/http"
    20  	"github.com/SAP/jenkins-library/pkg/mock"
    21  	"github.com/SAP/jenkins-library/pkg/orchestrator"
    22  
    23  	"github.com/google/go-github/v45/github"
    24  	"github.com/stretchr/testify/assert"
    25  )
    26  
    27  type detectTestUtilsBundle struct {
    28  	expectedError   error
    29  	downloadedFiles map[string]string // src, dest
    30  	*mock.ShellMockRunner
    31  	*mock.FilesMock
    32  	customEnv    []string
    33  	orchestrator *orchestratorConfigProviderMock
    34  }
    35  
    36  func (d *detectTestUtilsBundle) GetProvider() orchestrator.OrchestratorSpecificConfigProviding {
    37  	return d.orchestrator
    38  }
    39  
    40  func (d *detectTestUtilsBundle) GetIssueService() *github.IssuesService {
    41  	return nil
    42  }
    43  
    44  func (d *detectTestUtilsBundle) GetSearchService() *github.SearchService {
    45  	return nil
    46  }
    47  
    48  type orchestratorConfigProviderMock struct {
    49  	orchestrator.UnknownOrchestratorConfigProvider
    50  	isPullRequest bool
    51  }
    52  
    53  func (o *orchestratorConfigProviderMock) IsPullRequest() bool {
    54  	return o.isPullRequest
    55  }
    56  
    57  type httpMockClient struct {
    58  	responseBodyForURL map[string]string
    59  	errorMessageForURL map[string]string
    60  	header             map[string]http.Header
    61  }
    62  
    63  func (c *httpMockClient) SetOptions(opts piperhttp.ClientOptions) {}
    64  func (c *httpMockClient) SendRequest(method, url string, body io.Reader, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
    65  	c.header[url] = header
    66  	response := http.Response{
    67  		StatusCode: 200,
    68  		Body:       io.NopCloser(bytes.NewReader([]byte(""))),
    69  	}
    70  
    71  	if c.errorMessageForURL[url] != "" {
    72  		response.StatusCode = 400
    73  		return &response, fmt.Errorf(c.errorMessageForURL[url])
    74  	}
    75  
    76  	if c.responseBodyForURL[url] != "" {
    77  		response.Body = io.NopCloser(bytes.NewReader([]byte(c.responseBodyForURL[url])))
    78  		return &response, nil
    79  	}
    80  
    81  	return &response, nil
    82  }
    83  
    84  func newBlackduckMockSystem(config detectExecuteScanOptions) blackduckSystem {
    85  	myTestClient := httpMockClient{
    86  		responseBodyForURL: map[string]string{
    87  			"https://my.blackduck.system/api/tokens/authenticate":                                                                               authContent,
    88  			"https://my.blackduck.system/api/projects?q=name%3ASHC-PiperTest":                                                                   projectContent,
    89  			"https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0":                         projectVersionContent,
    90  			"https://my.blackduck.system/api/projects/5ca86e11/versions/a6c94786/components?limit=999&offset=0":                                 componentsContent,
    91  			"https://my.blackduck.system/api/projects/5ca86e11/versions/a6c94786/vunlerable-bom-components?limit=999&offset=0":                  vulnerabilitiesContent,
    92  			"https://my.blackduck.system/api/projects/5ca86e11/versions/a6c94786/components?filter=policyCategory%3Alicense&limit=999&offset=0": componentsContent,
    93  			"https://my.blackduck.system/api/projects/5ca86e11/versions/a6c94786/policy-status":                                                 policyStatusContent,
    94  			"https://my.blackduck.system/api/projects?q=name%3ARapid_scan_on_PRs":                                                               projectContentRapidScan,
    95  			"https://my.blackduck.system/api/projects/654ggfdgf-1983-4e7b-97d4-eb1a0aeffbbf/versions?limit=100&offset=0":                        projectVersionContentRapid,
    96  		},
    97  		header: map[string]http.Header{},
    98  	}
    99  	sys := blackduckSystem{
   100  		Client: bd.NewClient(config.Token, config.ServerURL, &myTestClient),
   101  	}
   102  	return sys
   103  }
   104  
   105  const (
   106  	authContent = `{
   107          "bearerToken":"bearerTestToken",
   108          "expiresInMilliseconds":7199997
   109      }`
   110  	projectContent = `{
   111          "totalCount": 1,
   112          "items": [
   113              {
   114                  "name": "SHC-PiperTest",
   115                  "_meta": {
   116                      "href": "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf",
   117                      "links": [
   118                          {
   119                              "rel": "versions",
   120                              "href": "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions"
   121                          }
   122                      ]
   123                  }
   124              }
   125          ]
   126      }`
   127  	projectVersionContent = `{
   128          "totalCount": 1,
   129          "items": [
   130              {
   131                  "versionName": "1.0",
   132                  "_meta": {
   133                      "href": "https://my.blackduck.system/api/projects/5ca86e11-1983-4e7b-97d4-eb1a0aeffbbf/versions/a6c94786-0ee6-414f-9054-90d549c69c36",
   134                      "links": [
   135                          {
   136                              "rel": "components",
   137                              "href": "https://my.blackduck.system/api/projects/5ca86e11/versions/a6c94786/components"
   138                          },
   139                          {
   140                              "rel": "vulnerable-components",
   141                              "href": "https://my.blackduck.system/api/projects/5ca86e11/versions/a6c94786/vunlerable-bom-components"
   142                          },
   143                          {
   144                              "rel": "policy-status",
   145                              "href": "https://my.blackduck.system/api/projects/5ca86e11/versions/a6c94786/policy-status"
   146                          }
   147                      ]
   148                  }
   149              }
   150          ]
   151      }`
   152  	componentsContent = `{
   153          "totalCount": 3,
   154          "items" : [
   155              {
   156                  "componentName": "Spring Framework",
   157                  "componentVersionName": "5.3.9",
   158                  "policyStatus": "IN_VIOLATION"
   159              }, {
   160                  "componentName": "Apache Tomcat",
   161                  "componentVersionName": "9.0.52",
   162                  "policyStatus": "IN_VIOLATION"
   163              }, {
   164                  "componentName": "Apache Log4j",
   165                  "componentVersionName": "4.5.16",
   166                  "policyStatus": "UNKNOWN"
   167              }
   168          ]
   169      }`
   170  	vulnerabilitiesContent = `{
   171          "totalCount": 3,
   172          "items": [
   173              {
   174                  "componentName": "Spring Framework",
   175                  "componentVersionName": "5.3.9",
   176                  "vulnerabilityWithRemediation" : {
   177                      "vulnerabilityName" : "BDSA-2019-2021",
   178                      "baseScore" : 7.5,
   179                      "overallScore" : 7.5,
   180                      "severity" : "HIGH",
   181                      "remediationStatus" : "IGNORED",
   182                      "description" : "description"
   183                  }
   184              }, {
   185                  "componentName": "Apache Log4j",
   186                  "componentVersionName": "4.5.16",
   187                  "vulnerabilityWithRemediation" : {
   188                      "vulnerabilityName" : "BDSA-2020-4711",
   189                      "baseScore" : 7.5,
   190                      "overallScore" : 7.5,
   191                      "severity" : "HIGH",
   192                      "remediationStatus" : "IGNORED",
   193                      "description" : "description"
   194                  }
   195              }, {
   196                  "componentName": "Apache Log4j",
   197                  "componentVersionName": "4.5.16",
   198                  "vulnerabilityWithRemediation" : {
   199                      "vulnerabilityName" : "BDSA-2020-4712",
   200                      "baseScore" : 4.5,
   201                      "overallScore" : 4.5,
   202                      "severity" : "MEDIUM",
   203                      "remediationStatus" : "IGNORED",
   204                      "description" : "description"
   205                  }
   206              }
   207          ]
   208      }`
   209  	policyStatusContent = `{
   210          "overallStatus": "IN_VIOLATION",
   211          "componentVersionPolicyViolationDetails": {
   212              "name": "IN_VIOLATION",
   213              "severityLevels": [{"name":"BLOCKER", "value": 1}, {"name": "CRITICAL", "value": 1}]
   214          }
   215      }`
   216  	projectContentRapidScan = `{
   217          "totalCount": 1,
   218          "items": [
   219              {
   220                  "name": "Rapid_scan_on_PRs",
   221                  "_meta": {
   222                      "href": "https://my.blackduck.system/api/projects/654ggfdgf-1983-4e7b-97d4-eb1a0aeffbbf",
   223                      "links": [
   224                          {
   225                              "rel": "versions",
   226                              "href": "https://my.blackduck.system/api/projects/654ggfdgf-1983-4e7b-97d4-eb1a0aeffbbf/versions"
   227                          }
   228                      ]
   229                  }
   230              }
   231          ]
   232      }`
   233  	projectVersionContentRapid = `{
   234          "totalCount": 1,
   235          "items": [
   236              {
   237                  "versionName": "1.0",
   238                  "_meta": {
   239                      "href": "https://my.blackduck.system/api/projects/654ggfdgf-1983-4e7b-97d4-eb1a0aeffbbf/versions/54357fds-0ee6-414f-9054-90d549c69c36",
   240                      "links": [
   241                          {
   242                              "rel": "components",
   243                              "href": "https://my.blackduck.system/api/projects/5ca86e11/versions/654784382/components"
   244                          },
   245                          {
   246                              "rel": "vulnerable-components",
   247                              "href": "https://my.blackduck.system/api/projects/5ca86e11/versions/654784382/vunlerable-bom-components"
   248                          },
   249                          {
   250                              "rel": "policy-status",
   251                              "href": "https://my.blackduck.system/api/projects/5ca86e11/versions/654784382/policy-status"
   252                          }
   253                      ]
   254                  }
   255              }
   256          ]
   257      }`
   258  )
   259  
   260  func (c *detectTestUtilsBundle) RunExecutable(string, ...string) error {
   261  	panic("not expected to be called in test")
   262  }
   263  
   264  func (c *detectTestUtilsBundle) SetOptions(piperhttp.ClientOptions) {
   265  }
   266  
   267  func (c *detectTestUtilsBundle) GetOsEnv() []string {
   268  	return c.customEnv
   269  }
   270  
   271  func (c *detectTestUtilsBundle) DownloadFile(url, filename string, _ http.Header, _ []*http.Cookie) error {
   272  	if c.expectedError != nil {
   273  		return c.expectedError
   274  	}
   275  
   276  	if c.downloadedFiles == nil {
   277  		c.downloadedFiles = make(map[string]string)
   278  	}
   279  	c.downloadedFiles[url] = filename
   280  	return nil
   281  }
   282  
   283  func (w *detectTestUtilsBundle) CreateIssue(ghCreateIssueOptions *piperGithub.CreateIssueOptions) error {
   284  	return nil
   285  }
   286  
   287  func newDetectTestUtilsBundle(isPullRequest bool) *detectTestUtilsBundle {
   288  	utilsBundle := detectTestUtilsBundle{
   289  		ShellMockRunner: &mock.ShellMockRunner{},
   290  		FilesMock:       &mock.FilesMock{},
   291  		orchestrator:    &orchestratorConfigProviderMock{isPullRequest: isPullRequest},
   292  	}
   293  	return &utilsBundle
   294  }
   295  
   296  func TestRunDetect(t *testing.T) {
   297  	t.Parallel()
   298  	t.Run("success case", func(t *testing.T) {
   299  		t.Parallel()
   300  		ctx := context.Background()
   301  		utilsMock := newDetectTestUtilsBundle(false)
   302  		utilsMock.AddFile("detect.sh", []byte(""))
   303  		err := runDetect(ctx, detectExecuteScanOptions{}, utilsMock, &detectExecuteScanInflux{})
   304  
   305  		assert.Equal(t, utilsMock.downloadedFiles["https://detect.synopsys.com/detect8.sh"], "detect.sh")
   306  		assert.True(t, utilsMock.HasRemovedFile("detect.sh"))
   307  		assert.NoError(t, err)
   308  		assert.Equal(t, ".", utilsMock.Dir, "Wrong execution directory used")
   309  		assert.Equal(t, "/bin/bash", utilsMock.Shell[0], "Bash shell expected")
   310  		expectedScript := "./detect.sh --blackduck.url= --blackduck.api.token= \"--detect.project.name=\" \"--detect.project.version.name=\" \"--detect.code.location.name=\" \"--detect.force.success.on.skip=true\" --detect.source.path='.'"
   311  		assert.Equal(t, expectedScript, utilsMock.Calls[0])
   312  	})
   313  
   314  	t.Run("failure case", func(t *testing.T) {
   315  		t.Parallel()
   316  		ctx := context.Background()
   317  		utilsMock := newDetectTestUtilsBundle(false)
   318  		utilsMock.ShouldFailOnCommand = map[string]error{"./detect.sh --blackduck.url= --blackduck.api.token= \"--detect.project.name=\" \"--detect.project.version.name=\" \"--detect.code.location.name=\" \"--detect.force.success.on.skip=true\" --detect.source.path='.'": fmt.Errorf("")}
   319  		utilsMock.ExitCode = 3
   320  		utilsMock.AddFile("detect.sh", []byte(""))
   321  		err := runDetect(ctx, detectExecuteScanOptions{FailOnSevereVulnerabilities: true}, utilsMock, &detectExecuteScanInflux{})
   322  		assert.Equal(t, utilsMock.ExitCode, 3)
   323  		assert.Contains(t, err.Error(), "FAILURE_POLICY_VIOLATION => Detect found policy violations.")
   324  		assert.True(t, utilsMock.HasRemovedFile("detect.sh"))
   325  	})
   326  
   327  	t.Run("maven parameters", func(t *testing.T) {
   328  		t.Parallel()
   329  		ctx := context.Background()
   330  		utilsMock := newDetectTestUtilsBundle(false)
   331  		utilsMock.CurrentDir = "root_folder"
   332  		utilsMock.AddFile("detect.sh", []byte(""))
   333  		err := runDetect(ctx, detectExecuteScanOptions{
   334  			M2Path:              ".pipeline/local_repo",
   335  			ProjectSettingsFile: "project-settings.xml",
   336  			GlobalSettingsFile:  "global-settings.xml",
   337  		}, utilsMock, &detectExecuteScanInflux{})
   338  
   339  		assert.NoError(t, err)
   340  		assert.Equal(t, ".", utilsMock.Dir, "Wrong execution directory used")
   341  		assert.Equal(t, "/bin/bash", utilsMock.Shell[0], "Bash shell expected")
   342  		absoluteLocalPath := string(os.PathSeparator) + filepath.Join("root_folder", ".pipeline", "local_repo")
   343  
   344  		expectedParam := "\"--detect.maven.build.command=--global-settings global-settings.xml --settings project-settings.xml -Dmaven.repo.local=" + absoluteLocalPath + "\""
   345  		assert.Contains(t, utilsMock.Calls[0], expectedParam)
   346  	})
   347  }
   348  
   349  func TestAddDetectArgs(t *testing.T) {
   350  	t.Parallel()
   351  	testData := []struct {
   352  		args          []string
   353  		options       detectExecuteScanOptions
   354  		isPullRequest bool
   355  		expected      []string
   356  	}{
   357  		{
   358  			args: []string{"--testProp1=1"},
   359  			options: detectExecuteScanOptions{
   360  				BuildTool:           "mta",
   361  				ExcludedDirectories: []string{"dir1", "dir2"},
   362  				ScanProperties:      []string{"--scan1=1", "--scan2=2"},
   363  				ServerURL:           "https://server.url",
   364  				Token:               "apiToken",
   365  				ProjectName:         "testName",
   366  				Version:             "1.0",
   367  				VersioningModel:     "major-minor",
   368  				CodeLocation:        "",
   369  				Scanners:            []string{"signature"},
   370  				ScanPaths:           []string{"path1", "path2"},
   371  			},
   372  			expected: []string{
   373  				"--testProp1=1",
   374  				"--detect.detector.search.depth=100",
   375  				"--detect.detector.search.continue=true",
   376  				"--detect.excluded.directories=dir1,dir2",
   377  				"--scan1=1",
   378  				"--scan2=2",
   379  				"--blackduck.url=https://server.url",
   380  				"--blackduck.api.token=apiToken",
   381  				"\"--detect.project.name=testName\"",
   382  				"\"--detect.project.version.name=1.0\"",
   383  				"\"--detect.code.location.name=testName/1.0\"",
   384  				"\"--detect.force.success.on.skip=true\"",
   385  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   386  				"--detect.source.path='.'",
   387  			},
   388  		},
   389  		{
   390  			args: []string{"--testProp1=1"},
   391  			options: detectExecuteScanOptions{
   392  				ServerURL:       "https://server.url",
   393  				Token:           "apiToken",
   394  				ProjectName:     "testName",
   395  				Version:         "1.0",
   396  				VersioningModel: "major-minor",
   397  				CodeLocation:    "testLocation",
   398  				FailOn:          []string{"BLOCKER", "MAJOR"},
   399  				Scanners:        []string{"source"},
   400  				ScanPaths:       []string{"path1", "path2"},
   401  				Groups:          []string{"testGroup"},
   402  			},
   403  			expected: []string{
   404  				"--testProp1=1",
   405  				"--blackduck.url=https://server.url",
   406  				"--blackduck.api.token=apiToken",
   407  				"\"--detect.project.name=testName\"",
   408  				"\"--detect.project.version.name=1.0\"",
   409  				"\"--detect.project.user.groups=testGroup\"",
   410  				"--detect.policy.check.fail.on.severities=BLOCKER,MAJOR",
   411  				"\"--detect.code.location.name=testLocation\"",
   412  				"\"--detect.force.success.on.skip=true\"",
   413  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   414  				"--detect.source.path='.'",
   415  			},
   416  		},
   417  		{
   418  			args: []string{"--testProp1=1"},
   419  			options: detectExecuteScanOptions{
   420  				ServerURL:       "https://server.url",
   421  				Token:           "apiToken",
   422  				ProjectName:     "testName",
   423  				CodeLocation:    "testLocation",
   424  				FailOn:          []string{"BLOCKER", "MAJOR"},
   425  				Scanners:        []string{"source"},
   426  				ScanPaths:       []string{"path1", "path2"},
   427  				Groups:          []string{"testGroup", "testGroup2"},
   428  				Version:         "1.0",
   429  				VersioningModel: "major-minor",
   430  			},
   431  			expected: []string{
   432  				"--testProp1=1",
   433  				"--blackduck.url=https://server.url",
   434  				"--blackduck.api.token=apiToken",
   435  				"\"--detect.project.name=testName\"",
   436  				"\"--detect.project.version.name=1.0\"",
   437  				"\"--detect.project.user.groups=testGroup,testGroup2\"",
   438  				"--detect.policy.check.fail.on.severities=BLOCKER,MAJOR",
   439  				"\"--detect.code.location.name=testLocation\"",
   440  				"\"--detect.force.success.on.skip=true\"",
   441  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   442  				"--detect.source.path='.'",
   443  			},
   444  		},
   445  		{
   446  			args: []string{"--testProp1=1"},
   447  			options: detectExecuteScanOptions{
   448  				ServerURL:       "https://server.url",
   449  				Token:           "apiToken",
   450  				ProjectName:     "testName",
   451  				CodeLocation:    "testLocation",
   452  				FailOn:          []string{"BLOCKER", "MAJOR"},
   453  				Scanners:        []string{"source"},
   454  				ScanPaths:       []string{"path1", "path2"},
   455  				Groups:          []string{"testGroup", "testGroup2"},
   456  				Version:         "1.0",
   457  				VersioningModel: "major-minor",
   458  				DependencyPath:  "pathx",
   459  			},
   460  			expected: []string{
   461  				"--testProp1=1",
   462  				"--blackduck.url=https://server.url",
   463  				"--blackduck.api.token=apiToken",
   464  				"\"--detect.project.name=testName\"",
   465  				"\"--detect.project.version.name=1.0\"",
   466  				"\"--detect.project.user.groups=testGroup,testGroup2\"",
   467  				"--detect.policy.check.fail.on.severities=BLOCKER,MAJOR",
   468  				"\"--detect.code.location.name=testLocation\"",
   469  				"\"--detect.force.success.on.skip=true\"",
   470  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   471  				"--detect.source.path=pathx",
   472  			},
   473  		},
   474  		{
   475  			args: []string{"--testProp1=1"},
   476  			options: detectExecuteScanOptions{
   477  				ServerURL:       "https://server.url",
   478  				Token:           "apiToken",
   479  				ProjectName:     "testName",
   480  				CodeLocation:    "testLocation",
   481  				FailOn:          []string{"BLOCKER", "MAJOR"},
   482  				Scanners:        []string{"source"},
   483  				ScanPaths:       []string{"path1", "path2"},
   484  				Groups:          []string{"testGroup", "testGroup2"},
   485  				Version:         "1.0",
   486  				VersioningModel: "major-minor",
   487  				DependencyPath:  "pathx",
   488  				Unmap:           true,
   489  			},
   490  			expected: []string{
   491  				"--testProp1=1",
   492  				"--detect.project.codelocation.unmap=true",
   493  				"--blackduck.url=https://server.url",
   494  				"--blackduck.api.token=apiToken",
   495  				"\"--detect.project.name=testName\"",
   496  				"\"--detect.project.version.name=1.0\"",
   497  				"\"--detect.project.user.groups=testGroup,testGroup2\"",
   498  				"--detect.policy.check.fail.on.severities=BLOCKER,MAJOR",
   499  				"\"--detect.code.location.name=testLocation\"",
   500  				"\"--detect.force.success.on.skip=true\"",
   501  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   502  				"--detect.source.path=pathx",
   503  			},
   504  		},
   505  		{
   506  			args: []string{"--testProp1=1"},
   507  			options: detectExecuteScanOptions{
   508  				ServerURL:               "https://server.url",
   509  				Token:                   "apiToken",
   510  				ProjectName:             "testName",
   511  				CodeLocation:            "testLocation",
   512  				FailOn:                  []string{"BLOCKER", "MAJOR"},
   513  				Scanners:                []string{"source"},
   514  				ScanPaths:               []string{"path1", "path2"},
   515  				Groups:                  []string{"testGroup", "testGroup2"},
   516  				Version:                 "1.0",
   517  				VersioningModel:         "major-minor",
   518  				DependencyPath:          "pathx",
   519  				Unmap:                   true,
   520  				IncludedPackageManagers: []string{"maven", "GRADLE"},
   521  				ExcludedPackageManagers: []string{"npm", "NUGET"},
   522  				MavenExcludedScopes:     []string{"TEST", "compile"},
   523  				DetectTools:             []string{"DETECTOR"},
   524  			},
   525  			expected: []string{
   526  				"--testProp1=1",
   527  				"--detect.project.codelocation.unmap=true",
   528  				"--blackduck.url=https://server.url",
   529  				"--blackduck.api.token=apiToken",
   530  				"\"--detect.project.name=testName\"",
   531  				"\"--detect.project.version.name=1.0\"",
   532  				"\"--detect.project.user.groups=testGroup,testGroup2\"",
   533  				"--detect.policy.check.fail.on.severities=BLOCKER,MAJOR",
   534  				"\"--detect.code.location.name=testLocation\"",
   535  				"\"--detect.force.success.on.skip=true\"",
   536  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   537  				"--detect.source.path=pathx",
   538  				"--detect.included.detector.types=MAVEN,GRADLE",
   539  				"--detect.excluded.detector.types=NPM,NUGET",
   540  				"--detect.maven.excluded.scopes=test,compile",
   541  				"--detect.tools=DETECTOR",
   542  			},
   543  		},
   544  		{
   545  			args: []string{"--testProp1=1"},
   546  			options: detectExecuteScanOptions{
   547  				ServerURL:               "https://server.url",
   548  				Token:                   "apiToken",
   549  				ProjectName:             "testName",
   550  				CodeLocation:            "testLocation",
   551  				FailOn:                  []string{"BLOCKER", "MAJOR"},
   552  				Scanners:                []string{"source"},
   553  				ScanPaths:               []string{"path1", "path2"},
   554  				Groups:                  []string{"testGroup", "testGroup2"},
   555  				Version:                 "1.0",
   556  				VersioningModel:         "major-minor",
   557  				DependencyPath:          "pathx",
   558  				Unmap:                   true,
   559  				IncludedPackageManagers: []string{"maven", "GRADLE"},
   560  				ExcludedPackageManagers: []string{"npm", "NUGET"},
   561  				MavenExcludedScopes:     []string{"TEST", "compile"},
   562  				DetectTools:             []string{"DETECTOR"},
   563  			},
   564  			expected: []string{
   565  				"--testProp1=1",
   566  				"--detect.project.codelocation.unmap=true",
   567  				"--blackduck.url=https://server.url",
   568  				"--blackduck.api.token=apiToken",
   569  				"\"--detect.project.name=testName\"",
   570  				"\"--detect.project.version.name=1.0\"",
   571  				"\"--detect.project.user.groups=testGroup,testGroup2\"",
   572  				"--detect.policy.check.fail.on.severities=BLOCKER,MAJOR",
   573  				"\"--detect.code.location.name=testLocation\"",
   574  				"\"--detect.force.success.on.skip=true\"",
   575  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   576  				"--detect.source.path=pathx",
   577  				"--detect.included.detector.types=MAVEN,GRADLE",
   578  				"--detect.excluded.detector.types=NPM,NUGET",
   579  				"--detect.maven.excluded.scopes=test,compile",
   580  				"--detect.tools=DETECTOR",
   581  			},
   582  		},
   583  		{
   584  			args: []string{"--testProp1=1"},
   585  			options: detectExecuteScanOptions{
   586  				ServerURL:               "https://server.url",
   587  				Token:                   "apiToken",
   588  				ProjectName:             "testName",
   589  				CodeLocation:            "testLocation",
   590  				FailOn:                  []string{"BLOCKER", "MAJOR"},
   591  				Scanners:                []string{"source"},
   592  				ScanPaths:               []string{"path1", "path2"},
   593  				Groups:                  []string{"testGroup", "testGroup2"},
   594  				Version:                 "1.0",
   595  				VersioningModel:         "major-minor",
   596  				DependencyPath:          "pathx",
   597  				Unmap:                   true,
   598  				IncludedPackageManagers: []string{"maven", "GRADLE"},
   599  				ExcludedPackageManagers: []string{"npm", "NUGET"},
   600  				MavenExcludedScopes:     []string{"TEST", "compile"},
   601  				DetectTools:             []string{"DETECTOR"},
   602  			},
   603  			expected: []string{
   604  				"--testProp1=1",
   605  				"--detect.project.codelocation.unmap=true",
   606  				"--blackduck.url=https://server.url",
   607  				"--blackduck.api.token=apiToken",
   608  				"\"--detect.project.name=testName\"",
   609  				"\"--detect.project.version.name=1.0\"",
   610  				"\"--detect.project.user.groups=testGroup,testGroup2\"",
   611  				"--detect.policy.check.fail.on.severities=BLOCKER,MAJOR",
   612  				"\"--detect.code.location.name=testLocation\"",
   613  				"\"--detect.force.success.on.skip=true\"",
   614  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   615  				"--detect.source.path=pathx",
   616  				"--detect.included.detector.types=MAVEN,GRADLE",
   617  				"--detect.excluded.detector.types=NPM,NUGET",
   618  				"--detect.maven.excluded.scopes=test,compile",
   619  				"--detect.tools=DETECTOR",
   620  			},
   621  		},
   622  		{
   623  			args: []string{"--testProp1=1"},
   624  			options: detectExecuteScanOptions{
   625  				ScanProperties:          []string{"--scan=1", "--detect.project.codelocation.unmap=true"},
   626  				ServerURL:               "https://server.url",
   627  				Token:                   "apiToken",
   628  				ProjectName:             "testName",
   629  				CodeLocation:            "testLocation",
   630  				FailOn:                  []string{"BLOCKER", "MAJOR"},
   631  				Scanners:                []string{"source"},
   632  				ScanPaths:               []string{"path1", "path2"},
   633  				Groups:                  []string{"testGroup", "testGroup2"},
   634  				Version:                 "1.0",
   635  				VersioningModel:         "major-minor",
   636  				DependencyPath:          "pathx",
   637  				Unmap:                   true,
   638  				IncludedPackageManagers: []string{"maven", "GRADLE"},
   639  				ExcludedPackageManagers: []string{"npm", "NUGET"},
   640  				MavenExcludedScopes:     []string{"TEST", "compile"},
   641  				DetectTools:             []string{"DETECTOR"},
   642  			},
   643  			expected: []string{
   644  				"--testProp1=1",
   645  				"--scan=1",
   646  				"--detect.project.codelocation.unmap=true",
   647  				"--blackduck.url=https://server.url",
   648  				"--blackduck.api.token=apiToken",
   649  				"\"--detect.project.name=testName\"",
   650  				"\"--detect.project.version.name=1.0\"",
   651  				"\"--detect.project.user.groups=testGroup,testGroup2\"",
   652  				"--detect.policy.check.fail.on.severities=BLOCKER,MAJOR",
   653  				"\"--detect.code.location.name=testLocation\"",
   654  				"\"--detect.force.success.on.skip=true\"",
   655  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   656  				"--detect.source.path=pathx",
   657  				"--detect.included.detector.types=MAVEN,GRADLE",
   658  				"--detect.excluded.detector.types=NPM,NUGET",
   659  				"--detect.maven.excluded.scopes=test,compile",
   660  				"--detect.tools=DETECTOR",
   661  			},
   662  		},
   663  		{
   664  			args: []string{"--testProp1=1"},
   665  			options: detectExecuteScanOptions{
   666  				ServerURL:       "https://server.url",
   667  				Token:           "apiToken",
   668  				ProjectName:     "testName",
   669  				Version:         "1.0",
   670  				VersioningModel: "major-minor",
   671  				CodeLocation:    "",
   672  				ScanPaths:       []string{"path1", "path2"},
   673  				MinScanInterval: 4,
   674  			},
   675  			expected: []string{
   676  				"--testProp1=1",
   677  				"--detect.blackduck.signature.scanner.arguments='--min-scan-interval=4'",
   678  				"--blackduck.url=https://server.url",
   679  				"--blackduck.api.token=apiToken",
   680  				"\"--detect.project.name=testName\"",
   681  				"\"--detect.project.version.name=1.0\"",
   682  				"\"--detect.code.location.name=testName/1.0\"",
   683  				"\"--detect.force.success.on.skip=true\"",
   684  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   685  				"--detect.source.path='.'",
   686  			},
   687  		},
   688  		{
   689  			args: []string{"--testProp1=1"},
   690  			options: detectExecuteScanOptions{
   691  				ServerURL:         "https://server.url",
   692  				Token:             "apiToken",
   693  				ProjectName:       "Rapid_scan_on_PRs",
   694  				Version:           "1.0",
   695  				VersioningModel:   "major-minor",
   696  				CodeLocation:      "",
   697  				ScanPaths:         []string{"path1", "path2"},
   698  				MinScanInterval:   4,
   699  				CustomScanVersion: "1.0",
   700  			},
   701  			isPullRequest: true,
   702  			expected: []string{
   703  				"--testProp1=1",
   704  				"--detect.blackduck.signature.scanner.arguments='--min-scan-interval=4'",
   705  				"--blackduck.url=https://server.url",
   706  				"--blackduck.api.token=apiToken",
   707  				"\"--detect.project.name=Rapid_scan_on_PRs\"",
   708  				"\"--detect.project.version.name=1.0\"",
   709  				"\"--detect.code.location.name=Rapid_scan_on_PRs/1.0\"",
   710  				"\"--detect.force.success.on.skip=true\"",
   711  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   712  				"--detect.source.path='.'",
   713  				"--detect.blackduck.scan.mode='RAPID'",
   714  				"--detect.blackduck.rapid.compare.mode='BOM_COMPARE_STRICT'",
   715  				"--detect.cleanup=false",
   716  				"--detect.output.path='report'",
   717  			},
   718  		},
   719  		{
   720  			args: []string{"--testProp1=1"},
   721  			options: detectExecuteScanOptions{
   722  				ServerURL:       "https://server.url",
   723  				BuildTool:       "mta",
   724  				Token:           "apiToken",
   725  				ProjectName:     "Rapid_scan_on_PRs",
   726  				Version:         "2.0",
   727  				VersioningModel: "major-minor",
   728  				CodeLocation:    "",
   729  				ScanPaths:       []string{"path1", "path2"},
   730  				ScanProperties: []string{
   731  					"--detect.detector.search.depth=5",
   732  					"--detect.detector.search.continue=false",
   733  					"--detect.excluded.directories=dir1,dir2",
   734  				},
   735  				ExcludedDirectories: []string{"dir3,dir4"},
   736  				MinScanInterval:     4,
   737  				CustomScanVersion:   "2.0",
   738  			},
   739  			isPullRequest: true,
   740  			expected: []string{
   741  				"--testProp1=1",
   742  				"--detect.blackduck.signature.scanner.arguments='--min-scan-interval=4'",
   743  				"--detect.detector.search.depth=5",
   744  				"--detect.detector.search.continue=false",
   745  				"--detect.excluded.directories=dir1,dir2",
   746  				"--blackduck.url=https://server.url",
   747  				"--blackduck.api.token=apiToken",
   748  				"\"--detect.project.name=Rapid_scan_on_PRs\"",
   749  				"\"--detect.project.version.name=2.0\"",
   750  				"\"--detect.code.location.name=Rapid_scan_on_PRs/2.0\"",
   751  				"\"--detect.force.success.on.skip=true\"",
   752  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   753  				"--detect.source.path='.'",
   754  				"--detect.blackduck.scan.mode='RAPID'",
   755  				"--detect.cleanup=false",
   756  				"--detect.output.path='report'",
   757  			},
   758  		},
   759  		{
   760  			args: []string{"--testProp1=1"},
   761  			options: detectExecuteScanOptions{
   762  				ServerURL:          "https://server.url",
   763  				BuildTool:          "maven",
   764  				Token:              "apiToken",
   765  				ProjectName:        "Rapid_scan_on_PRs",
   766  				Version:            "2.0",
   767  				VersioningModel:    "major-minor",
   768  				CodeLocation:       "",
   769  				ScanPaths:          []string{"path1", "path2"},
   770  				M2Path:             "./m2",
   771  				GlobalSettingsFile: "pipeline/settings.xml",
   772  				ScanProperties: []string{
   773  					"--detect.maven.build.command= --settings .pipeline/settings.xml -DskipTests install",
   774  				},
   775  				MinScanInterval:   4,
   776  				CustomScanVersion: "2.0",
   777  			},
   778  			isPullRequest: true,
   779  			expected: []string{
   780  				"--testProp1=1",
   781  				"--detect.blackduck.signature.scanner.arguments='--min-scan-interval=4'",
   782  				"--detect.maven.build.command=",
   783  				"--settings",
   784  				".pipeline/settings.xml",
   785  				"-DskipTests",
   786  				"install",
   787  				"--blackduck.url=https://server.url",
   788  				"--blackduck.api.token=apiToken",
   789  				"\"--detect.project.name=Rapid_scan_on_PRs\"",
   790  				"\"--detect.project.version.name=2.0\"",
   791  				"\"--detect.code.location.name=Rapid_scan_on_PRs/2.0\"",
   792  				"\"--detect.force.success.on.skip=true\"",
   793  				"--detect.blackduck.signature.scanner.paths=path1,path2",
   794  				"--detect.source.path='.'",
   795  				"--detect.blackduck.scan.mode='RAPID'",
   796  				"--detect.cleanup=false",
   797  				"--detect.output.path='report'",
   798  			},
   799  		},
   800  	}
   801  
   802  	for k, v := range testData {
   803  		v := v
   804  		t.Run(fmt.Sprintf("run %v", k), func(t *testing.T) {
   805  			t.Parallel()
   806  
   807  			config := detectExecuteScanOptions{Token: "token", ServerURL: "https://my.blackduck.system", ProjectName: v.options.ProjectName, Version: v.options.Version, CustomScanVersion: v.options.CustomScanVersion}
   808  			sys := newBlackduckMockSystem(config)
   809  
   810  			got, err := addDetectArgs(v.args, v.options, newDetectTestUtilsBundle(v.isPullRequest), &sys)
   811  			assert.NoError(t, err)
   812  			assert.Equal(t, v.expected, got)
   813  		})
   814  	}
   815  }
   816  
   817  // Testing exit code mapping method
   818  func TestExitCodeMapping(t *testing.T) {
   819  	cases := []struct {
   820  		exitCode int
   821  		expected string
   822  	}{
   823  		{1, "FAILURE_BLACKDUCK_CONNECTIVITY"},
   824  		{-1, "Not known exit code key"},
   825  		{8, "Not known exit code key"},
   826  		{100, "FAILURE_UNKNOWN_ERROR"},
   827  	}
   828  
   829  	for _, c := range cases {
   830  		response := exitCodeMapping(c.exitCode)
   831  		assert.Contains(t, response, c.expected)
   832  	}
   833  }
   834  
   835  func TestPostScanChecksAndReporting(t *testing.T) {
   836  	t.Parallel()
   837  	t.Run("Reporting after scan", func(t *testing.T) {
   838  		ctx := context.Background()
   839  		config := detectExecuteScanOptions{Token: "token", ServerURL: "https://my.blackduck.system", ProjectName: "SHC-PiperTest", Version: "", CustomScanVersion: "1.0"}
   840  		utils := newDetectTestUtilsBundle(false)
   841  		sys := newBlackduckMockSystem(config)
   842  		err := postScanChecksAndReporting(ctx, config, &detectExecuteScanInflux{}, utils, &sys)
   843  
   844  		assert.EqualError(t, err, "License Policy Violations found")
   845  		content, err := utils.FileRead("blackduck-ip.json")
   846  		assert.NoError(t, err)
   847  		assert.Contains(t, string(content), `"policyViolations":2`)
   848  	})
   849  }
   850  
   851  func TestIsMajorVulnerability(t *testing.T) {
   852  	t.Parallel()
   853  	t.Run("Case True", func(t *testing.T) {
   854  		vr := bd.VulnerabilityWithRemediation{
   855  			OverallScore: 7.5,
   856  			Severity:     "HIGH",
   857  		}
   858  		v := bd.Vulnerability{
   859  			Name:                         "",
   860  			VulnerabilityWithRemediation: vr,
   861  			Ignored:                      false,
   862  		}
   863  		assert.True(t, isMajorVulnerability(v))
   864  	})
   865  	t.Run("Case Ignored Components", func(t *testing.T) {
   866  		vr := bd.VulnerabilityWithRemediation{
   867  			OverallScore: 7.5,
   868  			Severity:     "HIGH",
   869  		}
   870  		v := bd.Vulnerability{
   871  			Name:                         "",
   872  			VulnerabilityWithRemediation: vr,
   873  			Ignored:                      true,
   874  		}
   875  		assert.False(t, isMajorVulnerability(v))
   876  	})
   877  	t.Run("Case False", func(t *testing.T) {
   878  		vr := bd.VulnerabilityWithRemediation{
   879  			OverallScore: 7.5,
   880  			Severity:     "MEDIUM",
   881  		}
   882  		v := bd.Vulnerability{
   883  			Name:                         "",
   884  			VulnerabilityWithRemediation: vr,
   885  			Ignored:                      false,
   886  		}
   887  		assert.False(t, isMajorVulnerability(v))
   888  	})
   889  }
   890  
   891  func TestIsActiveVulnerability(t *testing.T) {
   892  	t.Parallel()
   893  	t.Run("Case true", func(t *testing.T) {
   894  		vr := bd.VulnerabilityWithRemediation{
   895  			OverallScore:      7.5,
   896  			Severity:          "HIGH",
   897  			RemediationStatus: "NEW",
   898  		}
   899  		v := bd.Vulnerability{
   900  			Name:                         "",
   901  			VulnerabilityWithRemediation: vr,
   902  		}
   903  		assert.True(t, isActiveVulnerability(v))
   904  	})
   905  	t.Run("Case False", func(t *testing.T) {
   906  		vr := bd.VulnerabilityWithRemediation{
   907  			OverallScore:      7.5,
   908  			Severity:          "HIGH",
   909  			RemediationStatus: "IGNORED",
   910  		}
   911  		v := bd.Vulnerability{
   912  			Name:                         "",
   913  			VulnerabilityWithRemediation: vr,
   914  		}
   915  		assert.False(t, isActiveVulnerability(v))
   916  	})
   917  }
   918  
   919  func TestIsActivePolicyViolation(t *testing.T) {
   920  	t.Parallel()
   921  	t.Run("Case true", func(t *testing.T) {
   922  		assert.True(t, isActivePolicyViolation("IN_VIOLATION"))
   923  	})
   924  	t.Run("Case False", func(t *testing.T) {
   925  		assert.False(t, isActivePolicyViolation("NOT_IN_VIOLATION"))
   926  	})
   927  }
   928  
   929  func TestGetActivePolicyViolations(t *testing.T) {
   930  	t.Parallel()
   931  	t.Run("Case true", func(t *testing.T) {
   932  		config := detectExecuteScanOptions{Token: "token", ServerURL: "https://my.blackduck.system", ProjectName: "SHC-PiperTest", Version: "", CustomScanVersion: "1.0"}
   933  		sys := newBlackduckMockSystem(config)
   934  
   935  		components, err := sys.Client.GetComponents("SHC-PiperTest", "1.0")
   936  		assert.NoError(t, err)
   937  		assert.Equal(t, 2, getActivePolicyViolations(components))
   938  	})
   939  }
   940  
   941  func TestGetVulnerabilitiesWithComponents(t *testing.T) {
   942  	t.Parallel()
   943  	t.Run("Case true", func(t *testing.T) {
   944  		config := detectExecuteScanOptions{Token: "token", ServerURL: "https://my.blackduck.system", ProjectName: "SHC-PiperTest", Version: "", CustomScanVersion: "1.0"}
   945  		sys := newBlackduckMockSystem(config)
   946  
   947  		vulns, err := getVulnerabilitiesWithComponents(config, &detectExecuteScanInflux{}, &sys)
   948  		assert.NoError(t, err)
   949  		vulnerabilitySpring := bd.Vulnerability{}
   950  		vulnerabilityLog4j1 := bd.Vulnerability{}
   951  		vulnerabilityLog4j2 := bd.Vulnerability{}
   952  		for _, v := range vulns.Items {
   953  			if v.VulnerabilityWithRemediation.VulnerabilityName == "BDSA-2019-2021" {
   954  				vulnerabilitySpring = v
   955  			}
   956  			if v.VulnerabilityWithRemediation.VulnerabilityName == "BDSA-2020-4711" {
   957  				vulnerabilityLog4j1 = v
   958  			}
   959  			if v.VulnerabilityWithRemediation.VulnerabilityName == "BDSA-2020-4712" {
   960  				vulnerabilityLog4j2 = v
   961  			}
   962  		}
   963  		vulnerableComponentSpring := &bd.Component{}
   964  		vulnerableComponentLog4j := &bd.Component{}
   965  		for i := 0; i < len(vulns.Items); i++ {
   966  			if vulns.Items[i].Component != nil && vulns.Items[i].Component.Name == "Spring Framework" {
   967  				vulnerableComponentSpring = vulns.Items[i].Component
   968  			}
   969  			if vulns.Items[i].Component != nil && vulns.Items[i].Component.Name == "Apache Log4j" {
   970  				vulnerableComponentLog4j = vulns.Items[i].Component
   971  			}
   972  		}
   973  		assert.Equal(t, vulnerableComponentSpring, vulnerabilitySpring.Component)
   974  		assert.Equal(t, vulnerableComponentLog4j, vulnerabilityLog4j1.Component)
   975  		assert.Equal(t, vulnerableComponentLog4j, vulnerabilityLog4j2.Component)
   976  	})
   977  }