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 }