github.com/xgoffin/jenkins-library@v1.154.0/cmd/whitesourceExecuteScan_test.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "testing" 7 "time" 8 9 piperGithub "github.com/SAP/jenkins-library/pkg/github" 10 "github.com/SAP/jenkins-library/pkg/mock" 11 "github.com/SAP/jenkins-library/pkg/piperenv" 12 "github.com/SAP/jenkins-library/pkg/piperutils" 13 "github.com/SAP/jenkins-library/pkg/reporting" 14 "github.com/SAP/jenkins-library/pkg/versioning" 15 ws "github.com/SAP/jenkins-library/pkg/whitesource" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 type whitesourceUtilsMock struct { 20 *ws.ScanUtilsMock 21 coordinates versioning.Coordinates 22 usedBuildTool string 23 usedBuildDescriptorFile string 24 usedOptions versioning.Options 25 } 26 27 func (w *whitesourceUtilsMock) GetArtifactCoordinates(buildTool, buildDescriptorFile string, 28 options *versioning.Options) (versioning.Coordinates, error) { 29 w.usedBuildTool = buildTool 30 w.usedBuildDescriptorFile = buildDescriptorFile 31 w.usedOptions = *options 32 return w.coordinates, nil 33 } 34 35 func (w *whitesourceUtilsMock) CreateIssue(ghCreateIssueOptions *piperGithub.CreateIssueOptions) error { 36 return nil 37 } 38 39 const wsTimeNow = "2010-05-10 00:15:42" 40 41 func (w *whitesourceUtilsMock) Now() time.Time { 42 now, _ := time.Parse("2006-01-02 15:04:05", wsTimeNow) 43 return now 44 } 45 46 func newWhitesourceUtilsMock() *whitesourceUtilsMock { 47 return &whitesourceUtilsMock{ 48 ScanUtilsMock: &ws.ScanUtilsMock{ 49 FilesMock: &mock.FilesMock{}, 50 ExecMockRunner: &mock.ExecMockRunner{}, 51 }, 52 coordinates: versioning.Coordinates{ 53 GroupID: "mock-group-id", 54 ArtifactID: "mock-artifact-id", 55 Version: "1.0.42", 56 }, 57 } 58 } 59 60 func TestNewWhitesourceUtils(t *testing.T) { 61 t.Parallel() 62 config := ScanOptions{} 63 utils := newWhitesourceUtils(&config) 64 65 assert.NotNil(t, utils.Client) 66 assert.NotNil(t, utils.Command) 67 assert.NotNil(t, utils.Files) 68 } 69 70 func TestRunWhitesourceExecuteScan(t *testing.T) { 71 t.Parallel() 72 t.Run("fails for invalid configured project token", func(t *testing.T) { 73 // init 74 config := ScanOptions{ 75 BuildDescriptorFile: "my-mta.yml", 76 VersioningModel: "major", 77 ProductName: "mock-product", 78 ProjectToken: "no-such-project-token", 79 AgentDownloadURL: "https://whitesource.com/agent.jar", 80 AgentFileName: "ua.jar", 81 } 82 utilsMock := newWhitesourceUtilsMock() 83 utilsMock.AddFile("wss-generated-file.config", []byte("key=value")) 84 systemMock := ws.NewSystemMock("ignored") 85 scan := newWhitesourceScan(&config) 86 cpe := whitesourceExecuteScanCommonPipelineEnvironment{} 87 influx := whitesourceExecuteScanInflux{} 88 // test 89 err := runWhitesourceExecuteScan(&config, scan, utilsMock, systemMock, &cpe, &influx) 90 // assert 91 assert.EqualError(t, err, "failed to resolve and aggregate project name: failed to get project by token: no project with token 'no-such-project-token' found in Whitesource") 92 assert.Equal(t, "", config.ProjectName) 93 assert.Equal(t, "", scan.AggregateProjectName) 94 }) 95 t.Run("retrieves aggregate project name by configured token", func(t *testing.T) { 96 // init 97 config := ScanOptions{ 98 BuildDescriptorFile: "my-mta.yml", 99 VersioningModel: "major", 100 AgentDownloadURL: "https://whitesource.com/agent.jar", 101 VulnerabilityReportFormat: "pdf", 102 Reporting: true, 103 AgentFileName: "ua.jar", 104 ProductName: "mock-product", 105 ProjectToken: "mock-project-token", 106 } 107 utilsMock := newWhitesourceUtilsMock() 108 utilsMock.AddFile("wss-generated-file.config", []byte("key=value")) 109 lastUpdatedDate := time.Now().Format(ws.DateTimeLayout) 110 systemMock := ws.NewSystemMock(lastUpdatedDate) 111 systemMock.Alerts = []ws.Alert{} 112 scan := newWhitesourceScan(&config) 113 cpe := whitesourceExecuteScanCommonPipelineEnvironment{} 114 influx := whitesourceExecuteScanInflux{} 115 // test 116 err := runWhitesourceExecuteScan(&config, scan, utilsMock, systemMock, &cpe, &influx) 117 // assert 118 assert.NoError(t, err) 119 // Retrieved project name is stored in scan.AggregateProjectName, but not in config.ProjectName 120 // in order to differentiate between aggregate-project scanning and multi-project scanning. 121 assert.Equal(t, "", config.ProjectName) 122 assert.Equal(t, "mock-project", scan.AggregateProjectName) 123 if assert.Len(t, utilsMock.DownloadedFiles, 1) { 124 assert.Equal(t, ws.DownloadedFile{ 125 SourceURL: "https://whitesource.com/agent.jar", 126 FilePath: "ua.jar", 127 }, utilsMock.DownloadedFiles[0]) 128 } 129 if assert.Len(t, cpe.custom.whitesourceProjectNames, 1) { 130 assert.Equal(t, []string{"mock-project - 1"}, cpe.custom.whitesourceProjectNames) 131 } 132 assert.True(t, utilsMock.HasWrittenFile(filepath.Join(ws.ReportsDirectory, "mock-project - 1-vulnerability-report.pdf"))) 133 assert.True(t, utilsMock.HasWrittenFile(filepath.Join(ws.ReportsDirectory, "mock-project - 1-vulnerability-report.pdf"))) 134 }) 135 } 136 137 func TestCheckAndReportScanResults(t *testing.T) { 138 t.Parallel() 139 t.Run("no reports requested", func(t *testing.T) { 140 // init 141 config := &ScanOptions{ 142 ProductToken: "mock-product-token", 143 ProjectToken: "mock-project-token", 144 Version: "1", 145 } 146 scan := newWhitesourceScan(config) 147 utils := newWhitesourceUtilsMock() 148 system := ws.NewSystemMock(time.Now().Format(ws.DateTimeLayout)) 149 influx := whitesourceExecuteScanInflux{} 150 // test 151 _, err := checkAndReportScanResults(config, scan, utils, system, &influx) 152 // assert 153 assert.NoError(t, err) 154 vPath := filepath.Join(ws.ReportsDirectory, "mock-project-vulnerability-report.txt") 155 assert.False(t, utils.HasWrittenFile(vPath)) 156 rPath := filepath.Join(ws.ReportsDirectory, "mock-project-risk-report.pdf") 157 assert.False(t, utils.HasWrittenFile(rPath)) 158 }) 159 t.Run("check vulnerabilities - invalid limit", func(t *testing.T) { 160 // init 161 config := &ScanOptions{ 162 SecurityVulnerabilities: true, 163 CvssSeverityLimit: "invalid", 164 } 165 scan := newWhitesourceScan(config) 166 utils := newWhitesourceUtilsMock() 167 system := ws.NewSystemMock(time.Now().Format(ws.DateTimeLayout)) 168 influx := whitesourceExecuteScanInflux{} 169 // test 170 _, err := checkAndReportScanResults(config, scan, utils, system, &influx) 171 // assert 172 assert.EqualError(t, err, "failed to parse parameter cvssSeverityLimit (invalid) as floating point number: strconv.ParseFloat: parsing \"invalid\": invalid syntax") 173 }) 174 t.Run("check vulnerabilities - limit not hit", func(t *testing.T) { 175 // init 176 config := &ScanOptions{ 177 ProductToken: "mock-product-token", 178 ProjectToken: "mock-project-token", 179 Version: "1", 180 SecurityVulnerabilities: true, 181 CvssSeverityLimit: "6.0", 182 } 183 scan := newWhitesourceScan(config) 184 utils := newWhitesourceUtilsMock() 185 system := ws.NewSystemMock(time.Now().Format(ws.DateTimeLayout)) 186 influx := whitesourceExecuteScanInflux{} 187 // test 188 _, err := checkAndReportScanResults(config, scan, utils, system, &influx) 189 // assert 190 assert.NoError(t, err) 191 }) 192 t.Run("check vulnerabilities - limit exceeded", func(t *testing.T) { 193 // init 194 config := &ScanOptions{ 195 ProductToken: "mock-product-token", 196 ProjectName: "mock-project - 1", 197 ProjectToken: "mock-project-token", 198 Version: "1", 199 SecurityVulnerabilities: true, 200 CvssSeverityLimit: "4", 201 } 202 scan := newWhitesourceScan(config) 203 utils := newWhitesourceUtilsMock() 204 system := ws.NewSystemMock(time.Now().Format(ws.DateTimeLayout)) 205 influx := whitesourceExecuteScanInflux{} 206 // test 207 _, err := checkAndReportScanResults(config, scan, utils, system, &influx) 208 // assert 209 assert.EqualError(t, err, "1 Open Source Software Security vulnerabilities with CVSS score greater or equal to 4.0 detected in project mock-project - 1") 210 }) 211 } 212 213 func TestResolveProjectIdentifiers(t *testing.T) { 214 t.Parallel() 215 t.Run("success", func(t *testing.T) { 216 // init 217 config := ScanOptions{ 218 BuildTool: "mta", 219 BuildDescriptorFile: "my-mta.yml", 220 VersioningModel: "major", 221 ProductName: "mock-product", 222 M2Path: "m2/path", 223 ProjectSettingsFile: "project-settings.xml", 224 GlobalSettingsFile: "global-settings.xml", 225 } 226 utilsMock := newWhitesourceUtilsMock() 227 systemMock := ws.NewSystemMock("ignored") 228 scan := newWhitesourceScan(&config) 229 // test 230 err := resolveProjectIdentifiers(&config, scan, utilsMock, systemMock) 231 // assert 232 if assert.NoError(t, err) { 233 assert.Equal(t, "mock-group-id-mock-artifact-id", scan.AggregateProjectName) 234 assert.Equal(t, "1", config.Version) 235 assert.Equal(t, "mock-product-token", config.ProductToken) 236 assert.Equal(t, "mta", utilsMock.usedBuildTool) 237 assert.Equal(t, "my-mta.yml", utilsMock.usedBuildDescriptorFile) 238 assert.Equal(t, "project-settings.xml", utilsMock.usedOptions.ProjectSettingsFile) 239 assert.Equal(t, "global-settings.xml", utilsMock.usedOptions.GlobalSettingsFile) 240 assert.Equal(t, "m2/path", utilsMock.usedOptions.M2Path) 241 } 242 }) 243 t.Run("success - with version from default", func(t *testing.T) { 244 // init 245 config := ScanOptions{ 246 BuildTool: "mta", 247 BuildDescriptorFile: "my-mta.yml", 248 Version: "1.2.3-20200101", 249 VersioningModel: "major", 250 ProductName: "mock-product", 251 M2Path: "m2/path", 252 ProjectSettingsFile: "project-settings.xml", 253 GlobalSettingsFile: "global-settings.xml", 254 } 255 utilsMock := newWhitesourceUtilsMock() 256 systemMock := ws.NewSystemMock("ignored") 257 scan := newWhitesourceScan(&config) 258 // test 259 err := resolveProjectIdentifiers(&config, scan, utilsMock, systemMock) 260 // assert 261 if assert.NoError(t, err) { 262 assert.Equal(t, "mock-group-id-mock-artifact-id", scan.AggregateProjectName) 263 assert.Equal(t, "1", config.Version) 264 assert.Equal(t, "mock-product-token", config.ProductToken) 265 assert.Equal(t, "mta", utilsMock.usedBuildTool) 266 assert.Equal(t, "my-mta.yml", utilsMock.usedBuildDescriptorFile) 267 assert.Equal(t, "project-settings.xml", utilsMock.usedOptions.ProjectSettingsFile) 268 assert.Equal(t, "global-settings.xml", utilsMock.usedOptions.GlobalSettingsFile) 269 assert.Equal(t, "m2/path", utilsMock.usedOptions.M2Path) 270 } 271 }) 272 t.Run("success - with custom scan version", func(t *testing.T) { 273 // init 274 config := ScanOptions{ 275 BuildTool: "mta", 276 BuildDescriptorFile: "my-mta.yml", 277 CustomScanVersion: "2.3.4", 278 VersioningModel: "major", 279 ProductName: "mock-product", 280 M2Path: "m2/path", 281 ProjectSettingsFile: "project-settings.xml", 282 GlobalSettingsFile: "global-settings.xml", 283 } 284 utilsMock := newWhitesourceUtilsMock() 285 systemMock := ws.NewSystemMock("ignored") 286 scan := newWhitesourceScan(&config) 287 // test 288 err := resolveProjectIdentifiers(&config, scan, utilsMock, systemMock) 289 // assert 290 if assert.NoError(t, err) { 291 assert.Equal(t, "mock-group-id-mock-artifact-id", scan.AggregateProjectName) 292 assert.Equal(t, "2.3.4", config.Version) 293 assert.Equal(t, "mock-product-token", config.ProductToken) 294 assert.Equal(t, "mta", utilsMock.usedBuildTool) 295 assert.Equal(t, "my-mta.yml", utilsMock.usedBuildDescriptorFile) 296 assert.Equal(t, "project-settings.xml", utilsMock.usedOptions.ProjectSettingsFile) 297 assert.Equal(t, "global-settings.xml", utilsMock.usedOptions.GlobalSettingsFile) 298 assert.Equal(t, "m2/path", utilsMock.usedOptions.M2Path) 299 } 300 }) 301 t.Run("retrieves token for configured project name", func(t *testing.T) { 302 // init 303 config := ScanOptions{ 304 BuildTool: "mta", 305 BuildDescriptorFile: "my-mta.yml", 306 VersioningModel: "major", 307 ProductName: "mock-product", 308 ProjectName: "mock-project", 309 } 310 utilsMock := newWhitesourceUtilsMock() 311 systemMock := ws.NewSystemMock("ignored") 312 scan := newWhitesourceScan(&config) 313 // test 314 err := resolveProjectIdentifiers(&config, scan, utilsMock, systemMock) 315 // assert 316 if assert.NoError(t, err) { 317 assert.Equal(t, "mock-project", scan.AggregateProjectName) 318 assert.Equal(t, "1", config.Version) 319 assert.Equal(t, "mock-product-token", config.ProductToken) 320 assert.Equal(t, "mta", utilsMock.usedBuildTool) 321 assert.Equal(t, "my-mta.yml", utilsMock.usedBuildDescriptorFile) 322 assert.Equal(t, "mock-project-token", config.ProjectToken) 323 } 324 }) 325 t.Run("product not found", func(t *testing.T) { 326 // init 327 config := ScanOptions{ 328 BuildTool: "mta", 329 VersioningModel: "major", 330 ProductName: "does-not-exist", 331 } 332 utilsMock := newWhitesourceUtilsMock() 333 systemMock := ws.NewSystemMock("ignored") 334 scan := newWhitesourceScan(&config) 335 // test 336 err := resolveProjectIdentifiers(&config, scan, utilsMock, systemMock) 337 // assert 338 assert.EqualError(t, err, "error resolving product token: failed to get product by name: no product with name 'does-not-exist' found in Whitesource") 339 }) 340 t.Run("product not found, created from pipeline", func(t *testing.T) { 341 // init 342 config := ScanOptions{ 343 BuildTool: "mta", 344 CreateProductFromPipeline: true, 345 EmailAddressesOfInitialProductAdmins: []string{"user1@domain.org", "user2@domain.org"}, 346 VersioningModel: "major", 347 ProductName: "created-by-pipeline", 348 } 349 utilsMock := newWhitesourceUtilsMock() 350 systemMock := ws.NewSystemMock("ignored") 351 scan := newWhitesourceScan(&config) 352 // test 353 err := resolveProjectIdentifiers(&config, scan, utilsMock, systemMock) 354 // assert 355 assert.NoError(t, err) 356 assert.Len(t, systemMock.Products, 2) 357 assert.Equal(t, "created-by-pipeline", systemMock.Products[1].Name) 358 assert.Equal(t, "mock-product-token-1", config.ProductToken) 359 }) 360 } 361 362 func TestCheckPolicyViolations(t *testing.T) { 363 t.Parallel() 364 365 t.Run("success - no violations", func(t *testing.T) { 366 config := ScanOptions{ProductName: "mock-product", Version: "1"} 367 scan := newWhitesourceScan(&config) 368 scan.AppendScannedProject("testProject1") 369 systemMock := ws.NewSystemMock("ignored") 370 systemMock.Alerts = []ws.Alert{} 371 utilsMock := newWhitesourceUtilsMock() 372 reportPaths := []piperutils.Path{ 373 {Target: filepath.Join("whitesource", "report1.pdf")}, 374 {Target: filepath.Join("whitesource", "report2.pdf")}, 375 } 376 influx := whitesourceExecuteScanInflux{} 377 378 path, err := checkPolicyViolations(&config, scan, systemMock, utilsMock, reportPaths, &influx) 379 assert.NoError(t, err) 380 assert.Equal(t, filepath.Join(ws.ReportsDirectory, "whitesource-ip.json"), path.Target) 381 382 fileContent, _ := utilsMock.FileRead(path.Target) 383 content := string(fileContent) 384 assert.Contains(t, content, `"policyViolations":0`) 385 assert.Contains(t, content, `"reports":["report1.pdf","report2.pdf"]`) 386 387 exists, err := utilsMock.FileExists(filepath.Join(reporting.StepReportDirectory, "whitesourceExecuteScan_ip_2d3120020f3f46393a54575a7f6f5675ad536721.json")) 388 assert.True(t, exists) 389 390 }) 391 392 t.Run("success - no reports", func(t *testing.T) { 393 config := ScanOptions{} 394 scan := newWhitesourceScan(&config) 395 scan.AppendScannedProject("testProject1") 396 systemMock := ws.NewSystemMock("ignored") 397 systemMock.Alerts = []ws.Alert{} 398 utilsMock := newWhitesourceUtilsMock() 399 reportPaths := []piperutils.Path{} 400 influx := whitesourceExecuteScanInflux{} 401 402 path, err := checkPolicyViolations(&config, scan, systemMock, utilsMock, reportPaths, &influx) 403 assert.NoError(t, err) 404 405 fileContent, _ := utilsMock.FileRead(path.Target) 406 content := string(fileContent) 407 assert.Contains(t, content, `reports":[]`) 408 }) 409 410 t.Run("error - policy violations", func(t *testing.T) { 411 config := ScanOptions{} 412 scan := newWhitesourceScan(&config) 413 scan.AppendScannedProject("testProject1") 414 systemMock := ws.NewSystemMock("ignored") 415 systemMock.Alerts = []ws.Alert{ 416 {Vulnerability: ws.Vulnerability{Name: "policyVul1"}}, 417 {Vulnerability: ws.Vulnerability{Name: "policyVul2"}}, 418 } 419 utilsMock := newWhitesourceUtilsMock() 420 reportPaths := []piperutils.Path{ 421 {Target: "report1.pdf"}, 422 {Target: "report2.pdf"}, 423 } 424 influx := whitesourceExecuteScanInflux{} 425 426 path, err := checkPolicyViolations(&config, scan, systemMock, utilsMock, reportPaths, &influx) 427 assert.Contains(t, fmt.Sprint(err), "2 policy violation(s) found") 428 429 fileContent, _ := utilsMock.FileRead(path.Target) 430 content := string(fileContent) 431 assert.Contains(t, content, `"policyViolations":2`) 432 assert.Contains(t, content, `"reports":["report1.pdf","report2.pdf"]`) 433 }) 434 435 t.Run("error - get alerts", func(t *testing.T) { 436 config := ScanOptions{} 437 scan := newWhitesourceScan(&config) 438 scan.AppendScannedProject("testProject1") 439 systemMock := ws.NewSystemMock("ignored") 440 systemMock.AlertError = fmt.Errorf("failed to read alerts") 441 utilsMock := newWhitesourceUtilsMock() 442 reportPaths := []piperutils.Path{} 443 influx := whitesourceExecuteScanInflux{} 444 445 _, err := checkPolicyViolations(&config, scan, systemMock, utilsMock, reportPaths, &influx) 446 assert.Contains(t, fmt.Sprint(err), "failed to retrieve project policy alerts from WhiteSource") 447 }) 448 449 t.Run("error - write file", func(t *testing.T) { 450 config := ScanOptions{} 451 scan := newWhitesourceScan(&config) 452 scan.AppendScannedProject("testProject1") 453 systemMock := ws.NewSystemMock("ignored") 454 systemMock.Alerts = []ws.Alert{} 455 utilsMock := newWhitesourceUtilsMock() 456 utilsMock.FileWriteError = fmt.Errorf("failed to write file") 457 reportPaths := []piperutils.Path{} 458 influx := whitesourceExecuteScanInflux{} 459 460 _, err := checkPolicyViolations(&config, scan, systemMock, utilsMock, reportPaths, &influx) 461 assert.Contains(t, fmt.Sprint(err), "failed to write policy violation report:") 462 }) 463 464 t.Run("failed to write json report", func(t *testing.T) { 465 config := ScanOptions{ProductName: "mock-product", Version: "1"} 466 scan := newWhitesourceScan(&config) 467 scan.AppendScannedProject("testProject1") 468 systemMock := ws.NewSystemMock("ignored") 469 systemMock.Alerts = []ws.Alert{} 470 utilsMock := newWhitesourceUtilsMock() 471 utilsMock.FileWriteErrors = map[string]error{ 472 filepath.Join(reporting.StepReportDirectory, "whitesourceExecuteScan_ip_2d3120020f3f46393a54575a7f6f5675ad536721.json"): fmt.Errorf("write error"), 473 } 474 reportPaths := []piperutils.Path{} 475 influx := whitesourceExecuteScanInflux{} 476 477 _, err := checkPolicyViolations(&config, scan, systemMock, utilsMock, reportPaths, &influx) 478 assert.Contains(t, fmt.Sprint(err), "failed to write json report") 479 }) 480 } 481 482 func TestCheckSecurityViolations(t *testing.T) { 483 t.Parallel() 484 485 t.Run("success - non-aggregated", func(t *testing.T) { 486 config := ScanOptions{ 487 CvssSeverityLimit: "7", 488 } 489 scan := newWhitesourceScan(&config) 490 scan.AppendScannedProject("testProject1") 491 systemMock := ws.NewSystemMock("ignored") 492 systemMock.Alerts = []ws.Alert{ 493 {Vulnerability: ws.Vulnerability{Name: "vul1", CVSS3Score: 6.0}}, 494 } 495 utilsMock := newWhitesourceUtilsMock() 496 influx := whitesourceExecuteScanInflux{} 497 498 reportPaths, err := checkSecurityViolations(&config, scan, systemMock, utilsMock, &influx) 499 assert.NoError(t, err) 500 fileContent, err := utilsMock.FileRead(reportPaths[0].Target) 501 assert.NoError(t, err) 502 assert.True(t, len(fileContent) > 0) 503 }) 504 505 t.Run("success - aggregated", func(t *testing.T) { 506 config := ScanOptions{ 507 CvssSeverityLimit: "7", 508 ProjectToken: "theProjectToken", 509 } 510 scan := newWhitesourceScan(&config) 511 systemMock := ws.NewSystemMock("ignored") 512 systemMock.Alerts = []ws.Alert{ 513 {Vulnerability: ws.Vulnerability{Name: "vul1", CVSS3Score: 6.0}}, 514 } 515 utilsMock := newWhitesourceUtilsMock() 516 influx := whitesourceExecuteScanInflux{} 517 518 reportPaths, err := checkSecurityViolations(&config, scan, systemMock, utilsMock, &influx) 519 assert.NoError(t, err) 520 assert.Equal(t, 0, len(reportPaths)) 521 }) 522 523 t.Run("error - wrong limit", func(t *testing.T) { 524 config := ScanOptions{CvssSeverityLimit: "x"} 525 scan := newWhitesourceScan(&config) 526 systemMock := ws.NewSystemMock("ignored") 527 utilsMock := newWhitesourceUtilsMock() 528 influx := whitesourceExecuteScanInflux{} 529 530 _, err := checkSecurityViolations(&config, scan, systemMock, utilsMock, &influx) 531 assert.Contains(t, fmt.Sprint(err), "failed to parse parameter cvssSeverityLimit") 532 533 }) 534 535 t.Run("error - non-aggregated", func(t *testing.T) { 536 config := ScanOptions{ 537 CvssSeverityLimit: "5", 538 } 539 scan := newWhitesourceScan(&config) 540 scan.AppendScannedProject("testProject1") 541 systemMock := ws.NewSystemMock("ignored") 542 systemMock.Alerts = []ws.Alert{ 543 {Vulnerability: ws.Vulnerability{Name: "vul1", CVSS3Score: 6.0}}, 544 } 545 utilsMock := newWhitesourceUtilsMock() 546 influx := whitesourceExecuteScanInflux{} 547 548 reportPaths, err := checkSecurityViolations(&config, scan, systemMock, utilsMock, &influx) 549 assert.Contains(t, fmt.Sprint(err), "1 Open Source Software Security vulnerabilities") 550 fileContent, err := utilsMock.FileRead(reportPaths[0].Target) 551 assert.NoError(t, err) 552 assert.True(t, len(fileContent) > 0) 553 }) 554 555 t.Run("error - aggregated", func(t *testing.T) { 556 config := ScanOptions{ 557 CvssSeverityLimit: "5", 558 ProjectToken: "theProjectToken", 559 } 560 scan := newWhitesourceScan(&config) 561 systemMock := ws.NewSystemMock("ignored") 562 systemMock.Alerts = []ws.Alert{ 563 {Vulnerability: ws.Vulnerability{Name: "vul1", CVSS3Score: 6.0}}, 564 } 565 utilsMock := newWhitesourceUtilsMock() 566 influx := whitesourceExecuteScanInflux{} 567 568 reportPaths, err := checkSecurityViolations(&config, scan, systemMock, utilsMock, &influx) 569 assert.Contains(t, fmt.Sprint(err), "1 Open Source Software Security vulnerabilities") 570 assert.Equal(t, 0, len(reportPaths)) 571 }) 572 } 573 574 func TestCheckProjectSecurityViolations(t *testing.T) { 575 project := ws.Project{Name: "testProject - 1", Token: "testToken"} 576 577 t.Run("success - no alerts", func(t *testing.T) { 578 systemMock := ws.NewSystemMock("ignored") 579 systemMock.Alerts = []ws.Alert{} 580 influx := whitesourceExecuteScanInflux{} 581 582 severeVulnerabilities, alerts, err := checkProjectSecurityViolations(7.0, project, systemMock, &influx) 583 assert.NoError(t, err) 584 assert.Equal(t, 0, severeVulnerabilities) 585 assert.Equal(t, 0, len(alerts)) 586 }) 587 588 t.Run("error - some vulnerabilities", func(t *testing.T) { 589 systemMock := ws.NewSystemMock("ignored") 590 systemMock.Alerts = []ws.Alert{ 591 {Vulnerability: ws.Vulnerability{CVSS3Score: 7}}, 592 {Vulnerability: ws.Vulnerability{CVSS3Score: 6}}, 593 } 594 influx := whitesourceExecuteScanInflux{} 595 596 severeVulnerabilities, alerts, err := checkProjectSecurityViolations(7.0, project, systemMock, &influx) 597 assert.Contains(t, fmt.Sprint(err), "1 Open Source Software Security vulnerabilities") 598 assert.Equal(t, 1, severeVulnerabilities) 599 assert.Equal(t, 2, len(alerts)) 600 }) 601 602 t.Run("error - WhiteSource failure", func(t *testing.T) { 603 systemMock := ws.NewSystemMock("ignored") 604 systemMock.AlertError = fmt.Errorf("failed to read alerts") 605 influx := whitesourceExecuteScanInflux{} 606 607 _, _, err := checkProjectSecurityViolations(7.0, project, systemMock, &influx) 608 assert.Contains(t, fmt.Sprint(err), "failed to retrieve project alerts from WhiteSource") 609 }) 610 611 } 612 613 func TestAggregateVersionWideLibraries(t *testing.T) { 614 t.Parallel() 615 t.Run("happy path", func(t *testing.T) { 616 // init 617 config := &ScanOptions{ 618 ProductToken: "mock-product-token", 619 Version: "1", 620 } 621 utils := newWhitesourceUtilsMock() 622 system := ws.NewSystemMock("2010-05-30 00:15:00 +0100") 623 // test 624 err := aggregateVersionWideLibraries(config, utils, system) 625 // assert 626 resource := filepath.Join(ws.ReportsDirectory, "libraries-20100510-001542.csv") 627 if assert.NoError(t, err) && assert.True(t, utils.HasWrittenFile(resource)) { 628 contents, _ := utils.FileRead(resource) 629 asString := string(contents) 630 assert.Equal(t, "Library Name, Project Name\nmock-library, mock-project\n", asString) 631 assert.NotEmpty(t, piperenv.GetParameter("", "whitesourceExecuteScan_reports.json")) 632 } 633 }) 634 } 635 636 func TestAggregateVersionWideVulnerabilities(t *testing.T) { 637 t.Parallel() 638 t.Run("happy path", func(t *testing.T) { 639 // init 640 config := &ScanOptions{ 641 ProductToken: "mock-product-token", 642 Version: "1", 643 } 644 utils := newWhitesourceUtilsMock() 645 system := ws.NewSystemMock("2010-05-30 00:15:00 +0100") 646 // test 647 err := aggregateVersionWideVulnerabilities(config, utils, system) 648 // assert 649 resource := filepath.Join(ws.ReportsDirectory, "project-names-aggregated.txt") 650 assert.NoError(t, err) 651 if assert.True(t, utils.HasWrittenFile(resource)) { 652 contents, _ := utils.FileRead(resource) 653 asString := string(contents) 654 assert.Equal(t, "mock-project - 1\n", asString) 655 } 656 reportSheet := filepath.Join(ws.ReportsDirectory, "vulnerabilities-20100510-001542.xlsx") 657 sheetContents, err := utils.FileRead(reportSheet) 658 assert.NoError(t, err) 659 assert.NotEmpty(t, sheetContents) 660 assert.NotEmpty(t, piperenv.GetParameter("", "whitesourceExecuteScan_reports.json")) 661 }) 662 } 663 664 func TestPersistScannedProjects(t *testing.T) { 665 t.Parallel() 666 t.Run("write 1 scanned projects", func(t *testing.T) { 667 // init 668 cpe := whitesourceExecuteScanCommonPipelineEnvironment{} 669 config := &ScanOptions{Version: "1"} 670 scan := newWhitesourceScan(config) 671 _ = scan.AppendScannedProject("project") 672 // test 673 persistScannedProjects(config, scan, &cpe) 674 // assert 675 assert.Equal(t, []string{"project - 1"}, cpe.custom.whitesourceProjectNames) 676 }) 677 t.Run("write 2 scanned projects", func(t *testing.T) { 678 // init 679 cpe := whitesourceExecuteScanCommonPipelineEnvironment{} 680 config := &ScanOptions{Version: "1"} 681 scan := newWhitesourceScan(config) 682 _ = scan.AppendScannedProject("project-app") 683 _ = scan.AppendScannedProject("project-db") 684 // test 685 persistScannedProjects(config, scan, &cpe) 686 // assert 687 assert.Equal(t, []string{"project-app - 1", "project-db - 1"}, cpe.custom.whitesourceProjectNames) 688 }) 689 t.Run("write no projects", func(t *testing.T) { 690 // init 691 cpe := whitesourceExecuteScanCommonPipelineEnvironment{} 692 config := &ScanOptions{Version: "1"} 693 scan := newWhitesourceScan(config) 694 // test 695 persistScannedProjects(config, scan, &cpe) 696 // assert 697 assert.Equal(t, []string{}, cpe.custom.whitesourceProjectNames) 698 }) 699 t.Run("write aggregated project", func(t *testing.T) { 700 // init 701 cpe := whitesourceExecuteScanCommonPipelineEnvironment{} 702 config := &ScanOptions{ProjectName: "project", Version: "1"} 703 scan := newWhitesourceScan(config) 704 // test 705 persistScannedProjects(config, scan, &cpe) 706 // assert 707 assert.Equal(t, []string{"project - 1"}, cpe.custom.whitesourceProjectNames) 708 }) 709 }