2020-09-18 11:54:45 +02:00
package cmd
import (
2021-02-10 17:18:00 +02:00
"fmt"
2020-11-02 09:51:58 +02:00
"path/filepath"
"testing"
"time"
2020-09-18 11:54:45 +02:00
"github.com/SAP/jenkins-library/pkg/mock"
2021-02-10 17:18:00 +02:00
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/reporting"
2020-09-18 11:54:45 +02:00
"github.com/SAP/jenkins-library/pkg/versioning"
ws "github.com/SAP/jenkins-library/pkg/whitesource"
"github.com/stretchr/testify/assert"
)
type whitesourceUtilsMock struct {
2020-10-20 09:49:26 +02:00
* ws . ScanUtilsMock
2021-02-10 17:18:00 +02:00
coordinates versioning . Coordinates
2020-09-29 12:44:31 +02:00
usedBuildTool string
usedBuildDescriptorFile string
usedOptions versioning . Options
2020-09-18 11:54:45 +02:00
}
2020-09-29 12:44:31 +02:00
func ( w * whitesourceUtilsMock ) GetArtifactCoordinates ( buildTool , buildDescriptorFile string ,
options * versioning . Options ) ( versioning . Coordinates , error ) {
w . usedBuildTool = buildTool
w . usedBuildDescriptorFile = buildDescriptorFile
w . usedOptions = * options
2020-09-18 11:54:45 +02:00
return w . coordinates , nil
}
2020-09-29 12:44:31 +02:00
const wsTimeNow = "2010-05-10 00:15:42"
func ( w * whitesourceUtilsMock ) Now ( ) time . Time {
now , _ := time . Parse ( "2006-01-02 15:04:05" , wsTimeNow )
return now
}
2020-09-18 11:54:45 +02:00
func newWhitesourceUtilsMock ( ) * whitesourceUtilsMock {
return & whitesourceUtilsMock {
2020-10-20 09:49:26 +02:00
ScanUtilsMock : & ws . ScanUtilsMock {
FilesMock : & mock . FilesMock { } ,
ExecMockRunner : & mock . ExecMockRunner { } ,
} ,
2021-02-10 17:18:00 +02:00
coordinates : versioning . Coordinates {
2020-09-18 11:54:45 +02:00
GroupID : "mock-group-id" ,
ArtifactID : "mock-artifact-id" ,
Version : "1.0.42" ,
} ,
}
}
2021-02-10 17:18:00 +02:00
func TestNewWhitesourceUtils ( t * testing . T ) {
t . Parallel ( )
config := ScanOptions { }
utils := newWhitesourceUtils ( & config )
assert . NotNil ( t , utils . Client )
assert . NotNil ( t , utils . Command )
assert . NotNil ( t , utils . Files )
}
func TestRunWhitesourceExecuteScan ( t * testing . T ) {
t . Parallel ( )
t . Run ( "fails for invalid configured project token" , func ( t * testing . T ) {
// init
config := ScanOptions {
BuildDescriptorFile : "my-mta.yml" ,
VersioningModel : "major" ,
ProductName : "mock-product" ,
ProjectToken : "no-such-project-token" ,
AgentDownloadURL : "https://whitesource.com/agent.jar" ,
AgentFileName : "ua.jar" ,
}
utilsMock := newWhitesourceUtilsMock ( )
utilsMock . AddFile ( "wss-generated-file.config" , [ ] byte ( "key=value" ) )
systemMock := ws . NewSystemMock ( "ignored" )
scan := newWhitesourceScan ( & config )
cpe := whitesourceExecuteScanCommonPipelineEnvironment { }
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
// test
2021-03-10 17:00:53 +02:00
err := runWhitesourceExecuteScan ( & config , scan , utilsMock , systemMock , & cpe , & influx )
2021-02-10 17:18:00 +02:00
// assert
assert . EqualError ( t , err , "no project with token 'no-such-project-token' found in Whitesource" )
assert . Equal ( t , "" , config . ProjectName )
assert . Equal ( t , "" , scan . AggregateProjectName )
} )
t . Run ( "retrieves aggregate project name by configured token" , func ( t * testing . T ) {
// init
config := ScanOptions {
BuildDescriptorFile : "my-mta.yml" ,
VersioningModel : "major" ,
AgentDownloadURL : "https://whitesource.com/agent.jar" ,
VulnerabilityReportFormat : "pdf" ,
Reporting : true ,
AgentFileName : "ua.jar" ,
ProductName : "mock-product" ,
ProjectToken : "mock-project-token" ,
}
utilsMock := newWhitesourceUtilsMock ( )
utilsMock . AddFile ( "wss-generated-file.config" , [ ] byte ( "key=value" ) )
lastUpdatedDate := time . Now ( ) . Format ( ws . DateTimeLayout )
systemMock := ws . NewSystemMock ( lastUpdatedDate )
systemMock . Alerts = [ ] ws . Alert { }
scan := newWhitesourceScan ( & config )
cpe := whitesourceExecuteScanCommonPipelineEnvironment { }
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
// test
2021-03-10 17:00:53 +02:00
err := runWhitesourceExecuteScan ( & config , scan , utilsMock , systemMock , & cpe , & influx )
2021-02-10 17:18:00 +02:00
// assert
assert . NoError ( t , err )
// Retrieved project name is stored in scan.AggregateProjectName, but not in config.ProjectName
// in order to differentiate between aggregate-project scanning and multi-project scanning.
assert . Equal ( t , "" , config . ProjectName )
assert . Equal ( t , "mock-project" , scan . AggregateProjectName )
if assert . Len ( t , utilsMock . DownloadedFiles , 1 ) {
assert . Equal ( t , ws . DownloadedFile {
SourceURL : "https://whitesource.com/agent.jar" ,
FilePath : "ua.jar" ,
} , utilsMock . DownloadedFiles [ 0 ] )
}
if assert . Len ( t , cpe . custom . whitesourceProjectNames , 1 ) {
assert . Equal ( t , [ ] string { "mock-project - 1" } , cpe . custom . whitesourceProjectNames )
}
assert . True ( t , utilsMock . HasWrittenFile ( filepath . Join ( ws . ReportsDirectory , "mock-project - 1-vulnerability-report.pdf" ) ) )
assert . True ( t , utilsMock . HasWrittenFile ( filepath . Join ( ws . ReportsDirectory , "mock-project - 1-vulnerability-report.pdf" ) ) )
} )
}
func TestCheckAndReportScanResults ( t * testing . T ) {
t . Parallel ( )
t . Run ( "no reports requested" , func ( t * testing . T ) {
// init
config := & ScanOptions {
ProductToken : "mock-product-token" ,
ProjectToken : "mock-project-token" ,
Version : "1" ,
}
scan := newWhitesourceScan ( config )
utils := newWhitesourceUtilsMock ( )
system := ws . NewSystemMock ( time . Now ( ) . Format ( ws . DateTimeLayout ) )
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
// test
2021-03-10 17:00:53 +02:00
_ , err := checkAndReportScanResults ( config , scan , utils , system , & influx )
2021-02-10 17:18:00 +02:00
// assert
assert . NoError ( t , err )
vPath := filepath . Join ( ws . ReportsDirectory , "mock-project-vulnerability-report.txt" )
assert . False ( t , utils . HasWrittenFile ( vPath ) )
rPath := filepath . Join ( ws . ReportsDirectory , "mock-project-risk-report.pdf" )
assert . False ( t , utils . HasWrittenFile ( rPath ) )
} )
t . Run ( "check vulnerabilities - invalid limit" , func ( t * testing . T ) {
// init
config := & ScanOptions {
SecurityVulnerabilities : true ,
CvssSeverityLimit : "invalid" ,
}
scan := newWhitesourceScan ( config )
utils := newWhitesourceUtilsMock ( )
system := ws . NewSystemMock ( time . Now ( ) . Format ( ws . DateTimeLayout ) )
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
// test
2021-03-10 17:00:53 +02:00
_ , err := checkAndReportScanResults ( config , scan , utils , system , & influx )
2021-02-10 17:18:00 +02:00
// assert
assert . EqualError ( t , err , "failed to parse parameter cvssSeverityLimit (invalid) as floating point number: strconv.ParseFloat: parsing \"invalid\": invalid syntax" )
} )
t . Run ( "check vulnerabilities - limit not hit" , func ( t * testing . T ) {
// init
config := & ScanOptions {
ProductToken : "mock-product-token" ,
ProjectToken : "mock-project-token" ,
Version : "1" ,
SecurityVulnerabilities : true ,
CvssSeverityLimit : "6.0" ,
}
scan := newWhitesourceScan ( config )
utils := newWhitesourceUtilsMock ( )
system := ws . NewSystemMock ( time . Now ( ) . Format ( ws . DateTimeLayout ) )
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
// test
2021-03-10 17:00:53 +02:00
_ , err := checkAndReportScanResults ( config , scan , utils , system , & influx )
2021-02-10 17:18:00 +02:00
// assert
assert . NoError ( t , err )
} )
t . Run ( "check vulnerabilities - limit exceeded" , func ( t * testing . T ) {
// init
config := & ScanOptions {
ProductToken : "mock-product-token" ,
ProjectName : "mock-project - 1" ,
ProjectToken : "mock-project-token" ,
Version : "1" ,
SecurityVulnerabilities : true ,
CvssSeverityLimit : "4" ,
}
scan := newWhitesourceScan ( config )
utils := newWhitesourceUtilsMock ( )
system := ws . NewSystemMock ( time . Now ( ) . Format ( ws . DateTimeLayout ) )
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
// test
2021-03-10 17:00:53 +02:00
_ , err := checkAndReportScanResults ( config , scan , utils , system , & influx )
2021-02-10 17:18:00 +02:00
// assert
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" )
} )
}
2020-09-18 11:54:45 +02:00
func TestResolveProjectIdentifiers ( t * testing . T ) {
2020-09-29 12:44:31 +02:00
t . Parallel ( )
2021-02-10 17:18:00 +02:00
t . Run ( "success" , func ( t * testing . T ) {
// init
config := ScanOptions {
BuildTool : "mta" ,
BuildDescriptorFile : "my-mta.yml" ,
VersioningModel : "major" ,
ProductName : "mock-product" ,
M2Path : "m2/path" ,
ProjectSettingsFile : "project-settings.xml" ,
GlobalSettingsFile : "global-settings.xml" ,
}
utilsMock := newWhitesourceUtilsMock ( )
systemMock := ws . NewSystemMock ( "ignored" )
scan := newWhitesourceScan ( & config )
// test
err := resolveProjectIdentifiers ( & config , scan , utilsMock , systemMock )
// assert
if assert . NoError ( t , err ) {
assert . Equal ( t , "mock-group-id-mock-artifact-id" , scan . AggregateProjectName )
assert . Equal ( t , "1" , config . Version )
assert . Equal ( t , "mock-product-token" , config . ProductToken )
assert . Equal ( t , "mta" , utilsMock . usedBuildTool )
assert . Equal ( t , "my-mta.yml" , utilsMock . usedBuildDescriptorFile )
assert . Equal ( t , "project-settings.xml" , utilsMock . usedOptions . ProjectSettingsFile )
assert . Equal ( t , "global-settings.xml" , utilsMock . usedOptions . GlobalSettingsFile )
assert . Equal ( t , "m2/path" , utilsMock . usedOptions . M2Path )
}
} )
t . Run ( "success - with version from default" , func ( t * testing . T ) {
// init
config := ScanOptions {
BuildTool : "mta" ,
BuildDescriptorFile : "my-mta.yml" ,
Version : "1.2.3-20200101" ,
VersioningModel : "major" ,
ProductName : "mock-product" ,
M2Path : "m2/path" ,
ProjectSettingsFile : "project-settings.xml" ,
GlobalSettingsFile : "global-settings.xml" ,
}
utilsMock := newWhitesourceUtilsMock ( )
systemMock := ws . NewSystemMock ( "ignored" )
scan := newWhitesourceScan ( & config )
// test
err := resolveProjectIdentifiers ( & config , scan , utilsMock , systemMock )
// assert
if assert . NoError ( t , err ) {
assert . Equal ( t , "mock-group-id-mock-artifact-id" , scan . AggregateProjectName )
assert . Equal ( t , "1" , config . Version )
assert . Equal ( t , "mock-product-token" , config . ProductToken )
assert . Equal ( t , "mta" , utilsMock . usedBuildTool )
assert . Equal ( t , "my-mta.yml" , utilsMock . usedBuildDescriptorFile )
assert . Equal ( t , "project-settings.xml" , utilsMock . usedOptions . ProjectSettingsFile )
assert . Equal ( t , "global-settings.xml" , utilsMock . usedOptions . GlobalSettingsFile )
assert . Equal ( t , "m2/path" , utilsMock . usedOptions . M2Path )
}
} )
t . Run ( "success - with custom scan version" , func ( t * testing . T ) {
2020-09-18 11:54:45 +02:00
// init
config := ScanOptions {
2020-09-29 12:44:31 +02:00
BuildTool : "mta" ,
BuildDescriptorFile : "my-mta.yml" ,
2021-02-10 17:18:00 +02:00
CustomScanVersion : "2.3.4" ,
2020-09-29 12:44:31 +02:00
VersioningModel : "major" ,
ProductName : "mock-product" ,
M2Path : "m2/path" ,
ProjectSettingsFile : "project-settings.xml" ,
GlobalSettingsFile : "global-settings.xml" ,
2020-09-18 11:54:45 +02:00
}
utilsMock := newWhitesourceUtilsMock ( )
2020-10-20 09:49:26 +02:00
systemMock := ws . NewSystemMock ( "ignored" )
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( & config )
2020-09-18 11:54:45 +02:00
// test
2020-09-29 12:44:31 +02:00
err := resolveProjectIdentifiers ( & config , scan , utilsMock , systemMock )
2020-09-18 11:54:45 +02:00
// assert
if assert . NoError ( t , err ) {
2020-10-20 09:49:26 +02:00
assert . Equal ( t , "mock-group-id-mock-artifact-id" , scan . AggregateProjectName )
2021-02-10 17:18:00 +02:00
assert . Equal ( t , "2.3.4" , config . Version )
2020-09-18 11:54:45 +02:00
assert . Equal ( t , "mock-product-token" , config . ProductToken )
2020-09-29 12:44:31 +02:00
assert . Equal ( t , "mta" , utilsMock . usedBuildTool )
assert . Equal ( t , "my-mta.yml" , utilsMock . usedBuildDescriptorFile )
assert . Equal ( t , "project-settings.xml" , utilsMock . usedOptions . ProjectSettingsFile )
assert . Equal ( t , "global-settings.xml" , utilsMock . usedOptions . GlobalSettingsFile )
assert . Equal ( t , "m2/path" , utilsMock . usedOptions . M2Path )
}
} )
t . Run ( "retrieves token for configured project name" , func ( t * testing . T ) {
// init
config := ScanOptions {
BuildTool : "mta" ,
BuildDescriptorFile : "my-mta.yml" ,
VersioningModel : "major" ,
ProductName : "mock-product" ,
2020-10-20 09:49:26 +02:00
ProjectName : "mock-project" ,
2020-09-29 12:44:31 +02:00
}
utilsMock := newWhitesourceUtilsMock ( )
2020-10-20 09:49:26 +02:00
systemMock := ws . NewSystemMock ( "ignored" )
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( & config )
// test
err := resolveProjectIdentifiers ( & config , scan , utilsMock , systemMock )
// assert
if assert . NoError ( t , err ) {
2020-10-20 09:49:26 +02:00
assert . Equal ( t , "mock-project" , scan . AggregateProjectName )
2021-02-10 17:18:00 +02:00
assert . Equal ( t , "1" , config . Version )
2020-09-29 12:44:31 +02:00
assert . Equal ( t , "mock-product-token" , config . ProductToken )
assert . Equal ( t , "mta" , utilsMock . usedBuildTool )
assert . Equal ( t , "my-mta.yml" , utilsMock . usedBuildDescriptorFile )
assert . Equal ( t , "mock-project-token" , config . ProjectToken )
2020-09-18 11:54:45 +02:00
}
} )
t . Run ( "product not found" , func ( t * testing . T ) {
// init
config := ScanOptions {
2020-09-29 12:44:31 +02:00
BuildTool : "mta" ,
2020-09-18 11:54:45 +02:00
VersioningModel : "major" ,
ProductName : "does-not-exist" ,
}
utilsMock := newWhitesourceUtilsMock ( )
2020-10-20 09:49:26 +02:00
systemMock := ws . NewSystemMock ( "ignored" )
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( & config )
2020-09-18 11:54:45 +02:00
// test
2020-09-29 12:44:31 +02:00
err := resolveProjectIdentifiers ( & config , scan , utilsMock , systemMock )
2020-09-18 11:54:45 +02:00
// assert
assert . EqualError ( t , err , "no product with name 'does-not-exist' found in Whitesource" )
} )
2020-10-29 10:21:01 +02:00
t . Run ( "product not found, created from pipeline" , func ( t * testing . T ) {
// init
config := ScanOptions {
BuildTool : "mta" ,
CreateProductFromPipeline : true ,
EmailAddressesOfInitialProductAdmins : [ ] string { "user1@domain.org" , "user2@domain.org" } ,
VersioningModel : "major" ,
ProductName : "created-by-pipeline" ,
}
utilsMock := newWhitesourceUtilsMock ( )
systemMock := ws . NewSystemMock ( "ignored" )
scan := newWhitesourceScan ( & config )
// test
err := resolveProjectIdentifiers ( & config , scan , utilsMock , systemMock )
// assert
assert . NoError ( t , err )
assert . Len ( t , systemMock . Products , 2 )
assert . Equal ( t , "created-by-pipeline" , systemMock . Products [ 1 ] . Name )
assert . Equal ( t , "mock-product-token-1" , config . ProductToken )
} )
2020-09-18 11:54:45 +02:00
}
2021-02-10 17:18:00 +02:00
func TestCheckPolicyViolations ( t * testing . T ) {
2020-09-18 11:54:45 +02:00
t . Parallel ( )
2021-02-10 17:18:00 +02:00
t . Run ( "success - no violations" , func ( t * testing . T ) {
config := ScanOptions { }
scan := newWhitesourceScan ( & config )
scan . AppendScannedProject ( "testProject1" )
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . Alerts = [ ] ws . Alert { }
utilsMock := newWhitesourceUtilsMock ( )
reportPaths := [ ] piperutils . Path {
{ Target : filepath . Join ( "whitesource" , "report1.pdf" ) } ,
{ Target : filepath . Join ( "whitesource" , "report2.pdf" ) } ,
2020-09-18 11:54:45 +02:00
}
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
path , err := checkPolicyViolations ( & config , scan , systemMock , utilsMock , reportPaths , & influx )
2021-02-10 17:18:00 +02:00
assert . NoError ( t , err )
assert . Equal ( t , filepath . Join ( ws . ReportsDirectory , "whitesource-ip.json" ) , path . Target )
fileContent , _ := utilsMock . FileRead ( path . Target )
content := string ( fileContent )
assert . Contains ( t , content , ` "policyViolations":0 ` )
assert . Contains ( t , content , ` "reports":["report1.pdf","report2.pdf"] ` )
} )
t . Run ( "success - no reports" , func ( t * testing . T ) {
config := ScanOptions { }
scan := newWhitesourceScan ( & config )
scan . AppendScannedProject ( "testProject1" )
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . Alerts = [ ] ws . Alert { }
2020-11-10 10:09:51 +02:00
utilsMock := newWhitesourceUtilsMock ( )
2021-02-10 17:18:00 +02:00
reportPaths := [ ] piperutils . Path { }
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
path , err := checkPolicyViolations ( & config , scan , systemMock , utilsMock , reportPaths , & influx )
2021-02-10 17:18:00 +02:00
assert . NoError ( t , err )
fileContent , _ := utilsMock . FileRead ( path . Target )
content := string ( fileContent )
assert . Contains ( t , content , ` reports":[] ` )
} )
t . Run ( "error - policy violations" , func ( t * testing . T ) {
config := ScanOptions { }
scan := newWhitesourceScan ( & config )
scan . AppendScannedProject ( "testProject1" )
2020-11-10 10:09:51 +02:00
systemMock := ws . NewSystemMock ( "ignored" )
2021-02-10 17:18:00 +02:00
systemMock . Alerts = [ ] ws . Alert {
{ Vulnerability : ws . Vulnerability { Name : "policyVul1" } } ,
{ Vulnerability : ws . Vulnerability { Name : "policyVul2" } } ,
}
utilsMock := newWhitesourceUtilsMock ( )
reportPaths := [ ] piperutils . Path {
{ Target : "report1.pdf" } ,
{ Target : "report2.pdf" } ,
}
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
path , err := checkPolicyViolations ( & config , scan , systemMock , utilsMock , reportPaths , & influx )
2021-02-10 17:18:00 +02:00
assert . Contains ( t , fmt . Sprint ( err ) , "2 policy violation(s) found" )
fileContent , _ := utilsMock . FileRead ( path . Target )
content := string ( fileContent )
assert . Contains ( t , content , ` "policyViolations":2 ` )
assert . Contains ( t , content , ` "reports":["report1.pdf","report2.pdf"] ` )
} )
t . Run ( "error - get alerts" , func ( t * testing . T ) {
config := ScanOptions { }
2020-11-10 10:09:51 +02:00
scan := newWhitesourceScan ( & config )
2021-02-10 17:18:00 +02:00
scan . AppendScannedProject ( "testProject1" )
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . AlertError = fmt . Errorf ( "failed to read alerts" )
utilsMock := newWhitesourceUtilsMock ( )
reportPaths := [ ] piperutils . Path { }
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
_ , err := checkPolicyViolations ( & config , scan , systemMock , utilsMock , reportPaths , & influx )
2021-02-10 17:18:00 +02:00
assert . Contains ( t , fmt . Sprint ( err ) , "failed to retrieve project policy alerts from WhiteSource" )
2020-09-18 11:54:45 +02:00
} )
2021-02-10 17:18:00 +02:00
t . Run ( "error - write file" , func ( t * testing . T ) {
config := ScanOptions { }
scan := newWhitesourceScan ( & config )
scan . AppendScannedProject ( "testProject1" )
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . Alerts = [ ] ws . Alert { }
utilsMock := newWhitesourceUtilsMock ( )
utilsMock . FileWriteError = fmt . Errorf ( "failed to write file" )
reportPaths := [ ] piperutils . Path { }
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
_ , err := checkPolicyViolations ( & config , scan , systemMock , utilsMock , reportPaths , & influx )
2021-02-10 17:18:00 +02:00
assert . Contains ( t , fmt . Sprint ( err ) , "failed to write policy violation report:" )
} )
}
func TestCheckSecurityViolations ( t * testing . T ) {
t . Parallel ( )
t . Run ( "success - non-aggregated" , func ( t * testing . T ) {
2020-11-10 10:09:51 +02:00
config := ScanOptions {
2021-02-10 17:18:00 +02:00
CvssSeverityLimit : "7" ,
}
scan := newWhitesourceScan ( & config )
scan . AppendScannedProject ( "testProject1" )
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . Alerts = [ ] ws . Alert {
{ Vulnerability : ws . Vulnerability { Name : "vul1" , CVSS3Score : 6.0 } } ,
2020-09-18 11:54:45 +02:00
}
2020-11-10 10:09:51 +02:00
utilsMock := newWhitesourceUtilsMock ( )
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
reportPaths , err := checkSecurityViolations ( & config , scan , systemMock , utilsMock , & influx )
2021-02-10 17:18:00 +02:00
assert . NoError ( t , err )
fileContent , err := utilsMock . FileRead ( reportPaths [ 0 ] . Target )
assert . NoError ( t , err )
assert . True ( t , len ( fileContent ) > 0 )
} )
t . Run ( "success - aggregated" , func ( t * testing . T ) {
config := ScanOptions {
CvssSeverityLimit : "7" ,
ProjectToken : "theProjectToken" ,
}
2020-11-10 10:09:51 +02:00
scan := newWhitesourceScan ( & config )
2021-02-10 17:18:00 +02:00
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . Alerts = [ ] ws . Alert {
{ Vulnerability : ws . Vulnerability { Name : "vul1" , CVSS3Score : 6.0 } } ,
}
utilsMock := newWhitesourceUtilsMock ( )
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
reportPaths , err := checkSecurityViolations ( & config , scan , systemMock , utilsMock , & influx )
2020-11-10 10:09:51 +02:00
assert . NoError ( t , err )
2021-02-10 17:18:00 +02:00
assert . Equal ( t , 0 , len ( reportPaths ) )
} )
t . Run ( "error - wrong limit" , func ( t * testing . T ) {
config := ScanOptions { CvssSeverityLimit : "x" }
scan := newWhitesourceScan ( & config )
systemMock := ws . NewSystemMock ( "ignored" )
utilsMock := newWhitesourceUtilsMock ( )
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
_ , err := checkSecurityViolations ( & config , scan , systemMock , utilsMock , & influx )
2021-02-10 17:18:00 +02:00
assert . Contains ( t , fmt . Sprint ( err ) , "failed to parse parameter cvssSeverityLimit" )
} )
t . Run ( "error - non-aggregated" , func ( t * testing . T ) {
config := ScanOptions {
CvssSeverityLimit : "5" ,
2020-09-18 11:54:45 +02:00
}
2021-02-10 17:18:00 +02:00
scan := newWhitesourceScan ( & config )
scan . AppendScannedProject ( "testProject1" )
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . Alerts = [ ] ws . Alert {
{ Vulnerability : ws . Vulnerability { Name : "vul1" , CVSS3Score : 6.0 } } ,
2020-09-18 11:54:45 +02:00
}
2021-02-10 17:18:00 +02:00
utilsMock := newWhitesourceUtilsMock ( )
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
reportPaths , err := checkSecurityViolations ( & config , scan , systemMock , utilsMock , & influx )
2021-02-10 17:18:00 +02:00
assert . Contains ( t , fmt . Sprint ( err ) , "1 Open Source Software Security vulnerabilities" )
fileContent , err := utilsMock . FileRead ( reportPaths [ 0 ] . Target )
assert . NoError ( t , err )
assert . True ( t , len ( fileContent ) > 0 )
} )
t . Run ( "error - aggregated" , func ( t * testing . T ) {
config := ScanOptions {
CvssSeverityLimit : "5" ,
ProjectToken : "theProjectToken" ,
}
scan := newWhitesourceScan ( & config )
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . Alerts = [ ] ws . Alert {
{ Vulnerability : ws . Vulnerability { Name : "vul1" , CVSS3Score : 6.0 } } ,
}
utilsMock := newWhitesourceUtilsMock ( )
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
reportPaths , err := checkSecurityViolations ( & config , scan , systemMock , utilsMock , & influx )
2021-02-10 17:18:00 +02:00
assert . Contains ( t , fmt . Sprint ( err ) , "1 Open Source Software Security vulnerabilities" )
assert . Equal ( t , 0 , len ( reportPaths ) )
2020-09-18 11:54:45 +02:00
} )
}
2021-02-10 17:18:00 +02:00
func TestCheckProjectSecurityViolations ( t * testing . T ) {
project := ws . Project { Name : "testProject - 1" , Token : "testToken" }
t . Run ( "success - no alerts" , func ( t * testing . T ) {
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . Alerts = [ ] ws . Alert { }
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
severeVulnerabilities , alerts , err := checkProjectSecurityViolations ( 7.0 , project , systemMock , & influx )
2021-02-10 17:18:00 +02:00
assert . NoError ( t , err )
assert . Equal ( t , 0 , severeVulnerabilities )
assert . Equal ( t , 0 , len ( alerts ) )
} )
t . Run ( "error - some vulnerabilities" , func ( t * testing . T ) {
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . Alerts = [ ] ws . Alert {
{ Vulnerability : ws . Vulnerability { CVSS3Score : 7 } } ,
{ Vulnerability : ws . Vulnerability { CVSS3Score : 6 } } ,
}
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
2021-02-10 17:18:00 +02:00
2021-03-10 17:00:53 +02:00
severeVulnerabilities , alerts , err := checkProjectSecurityViolations ( 7.0 , project , systemMock , & influx )
2021-02-10 17:18:00 +02:00
assert . Contains ( t , fmt . Sprint ( err ) , "1 Open Source Software Security vulnerabilities" )
assert . Equal ( t , 1 , severeVulnerabilities )
assert . Equal ( t , 2 , len ( alerts ) )
} )
t . Run ( "error - WhiteSource failure" , func ( t * testing . T ) {
systemMock := ws . NewSystemMock ( "ignored" )
systemMock . AlertError = fmt . Errorf ( "failed to read alerts" )
2021-03-10 17:00:53 +02:00
influx := whitesourceExecuteScanInflux { }
_ , _ , err := checkProjectSecurityViolations ( 7.0 , project , systemMock , & influx )
2021-02-10 17:18:00 +02:00
assert . Contains ( t , fmt . Sprint ( err ) , "failed to retrieve project alerts from WhiteSource" )
} )
}
func TestCountSecurityVulnerabilities ( t * testing . T ) {
2020-09-29 12:44:31 +02:00
t . Parallel ( )
2021-02-10 17:18:00 +02:00
alerts := [ ] ws . Alert {
{ Vulnerability : ws . Vulnerability { CVSS3Score : 7.1 } } ,
{ Vulnerability : ws . Vulnerability { CVSS3Score : 7 } } ,
{ Vulnerability : ws . Vulnerability { CVSS3Score : 6 } } ,
}
severe , nonSevere := countSecurityVulnerabilities ( & alerts , 7.0 )
assert . Equal ( t , 2 , severe )
assert . Equal ( t , 1 , nonSevere )
}
func TestIsSevereVulnerability ( t * testing . T ) {
tt := [ ] struct {
alert ws . Alert
limit float64
expected bool
} {
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { CVSS3Score : 0 } } , limit : 0 , expected : true } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { CVSS3Score : 6.9 , Score : 6 } } , limit : 7.0 , expected : false } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { CVSS3Score : 7.0 , Score : 6 } } , limit : 7.0 , expected : true } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { CVSS3Score : 7.1 , Score : 6 } } , limit : 7.0 , expected : true } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { CVSS3Score : 6 , Score : 6.9 } } , limit : 7.0 , expected : false } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { CVSS3Score : 6 , Score : 7.0 } } , limit : 7.0 , expected : false } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { CVSS3Score : 6 , Score : 7.1 } } , limit : 7.0 , expected : false } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { Score : 6.9 } } , limit : 7.0 , expected : false } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { Score : 7.0 } } , limit : 7.0 , expected : true } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { Score : 7.1 } } , limit : 7.0 , expected : true } ,
}
for i , test := range tt {
assert . Equalf ( t , test . expected , isSevereVulnerability ( test . alert , test . limit ) , "run %v failed" , i )
}
}
func TestCreateCustomVulnerabilityReport ( t * testing . T ) {
t . Parallel ( )
t . Run ( "success case" , func ( t * testing . T ) {
config := & ScanOptions { }
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( config )
2021-02-10 17:18:00 +02:00
scan . AppendScannedProject ( "testProject" )
alerts := [ ] ws . Alert {
{ Library : ws . Library { Filename : "vul1" } , Vulnerability : ws . Vulnerability { CVSS3Score : 7.0 , Score : 6 } } ,
{ Library : ws . Library { Filename : "vul2" } , Vulnerability : ws . Vulnerability { CVSS3Score : 8.0 , TopFix : ws . Fix { Message : "this is the top fix" } } } ,
{ Library : ws . Library { Filename : "vul3" } , Vulnerability : ws . Vulnerability { Score : 6 } } ,
}
utilsMock := newWhitesourceUtilsMock ( )
scanReport := createCustomVulnerabilityReport ( config , scan , alerts , 7.0 , utilsMock )
assert . Equal ( t , "WhiteSource Security Vulnerability Report" , scanReport . Title )
assert . Equal ( t , 3 , len ( scanReport . DetailTable . Rows ) )
// assert that library info is filled and sorting has been executed
assert . Equal ( t , "vul2" , scanReport . DetailTable . Rows [ 0 ] . Columns [ 5 ] . Content )
assert . Equal ( t , "vul1" , scanReport . DetailTable . Rows [ 1 ] . Columns [ 5 ] . Content )
assert . Equal ( t , "vul3" , scanReport . DetailTable . Rows [ 2 ] . Columns [ 5 ] . Content )
// assert that CVSS version identification has been done
assert . Equal ( t , "v3" , scanReport . DetailTable . Rows [ 0 ] . Columns [ 3 ] . Content )
assert . Equal ( t , "v3" , scanReport . DetailTable . Rows [ 1 ] . Columns [ 3 ] . Content )
assert . Equal ( t , "v2" , scanReport . DetailTable . Rows [ 2 ] . Columns [ 3 ] . Content )
// assert proper rating and styling of high prio issues
assert . Equal ( t , "8" , scanReport . DetailTable . Rows [ 0 ] . Columns [ 2 ] . Content )
assert . Equal ( t , "7" , scanReport . DetailTable . Rows [ 1 ] . Columns [ 2 ] . Content )
assert . Equal ( t , "6" , scanReport . DetailTable . Rows [ 2 ] . Columns [ 2 ] . Content )
assert . Equal ( t , "red-cell" , scanReport . DetailTable . Rows [ 0 ] . Columns [ 2 ] . Style . String ( ) )
assert . Equal ( t , "red-cell" , scanReport . DetailTable . Rows [ 1 ] . Columns [ 2 ] . Style . String ( ) )
assert . Equal ( t , "yellow-cell" , scanReport . DetailTable . Rows [ 2 ] . Columns [ 2 ] . Style . String ( ) )
assert . Contains ( t , scanReport . DetailTable . Rows [ 0 ] . Columns [ 10 ] . Content , "this is the top fix" )
2020-09-29 12:44:31 +02:00
} )
2021-02-10 17:18:00 +02:00
}
func TestWriteCustomVulnerabilityReports ( t * testing . T ) {
t . Run ( "success" , func ( t * testing . T ) {
scanReport := reporting . ScanReport { }
utilsMock := newWhitesourceUtilsMock ( )
reportPaths , err := writeCustomVulnerabilityReports ( scanReport , utilsMock )
assert . NoError ( t , err )
assert . Equal ( t , 1 , len ( reportPaths ) )
exists , err := utilsMock . FileExists ( reportPaths [ 0 ] . Target )
assert . NoError ( t , err )
assert . True ( t , exists )
exists , err = utilsMock . FileExists ( filepath . Join ( reporting . MarkdownReportDirectory , "whitesourceExecuteScan_20100510001542.md" ) )
assert . NoError ( t , err )
assert . True ( t , exists )
2020-09-29 12:44:31 +02:00
} )
2021-02-10 17:18:00 +02:00
t . Run ( "failed to write HTML report" , func ( t * testing . T ) {
scanReport := reporting . ScanReport { }
utilsMock := newWhitesourceUtilsMock ( )
utilsMock . FileWriteErrors = map [ string ] error {
filepath . Join ( ws . ReportsDirectory , "piper_whitesource_vulnerability_report.html" ) : fmt . Errorf ( "write error" ) ,
}
_ , err := writeCustomVulnerabilityReports ( scanReport , utilsMock )
assert . Contains ( t , fmt . Sprint ( err ) , "failed to write html report" )
2020-09-29 12:44:31 +02:00
} )
2021-02-10 17:18:00 +02:00
t . Run ( "failed to write markdown report" , func ( t * testing . T ) {
scanReport := reporting . ScanReport { }
utilsMock := newWhitesourceUtilsMock ( )
utilsMock . FileWriteErrors = map [ string ] error {
filepath . Join ( reporting . MarkdownReportDirectory , "whitesourceExecuteScan_20100510001542.md" ) : fmt . Errorf ( "write error" ) ,
}
_ , err := writeCustomVulnerabilityReports ( scanReport , utilsMock )
assert . Contains ( t , fmt . Sprint ( err ) , "failed to write markdown report" )
2020-09-29 12:44:31 +02:00
} )
2021-02-10 17:18:00 +02:00
}
func TestVulnerabilityScore ( t * testing . T ) {
t . Parallel ( )
tt := [ ] struct {
alert ws . Alert
expected float64
} {
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { CVSS3Score : 7.0 , Score : 6 } } , expected : 7.0 } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { CVSS3Score : 7.0 } } , expected : 7.0 } ,
{ alert : ws . Alert { Vulnerability : ws . Vulnerability { Score : 6 } } , expected : 6 } ,
}
for i , test := range tt {
assert . Equalf ( t , test . expected , vulnerabilityScore ( test . alert ) , "run %v failed" , i )
}
2020-09-29 12:44:31 +02:00
}
func TestAggregateVersionWideLibraries ( t * testing . T ) {
t . Parallel ( )
t . Run ( "happy path" , func ( t * testing . T ) {
// init
config := & ScanOptions {
2021-02-10 17:18:00 +02:00
ProductToken : "mock-product-token" ,
Version : "1" ,
2020-09-29 12:44:31 +02:00
}
utils := newWhitesourceUtilsMock ( )
2020-10-20 09:49:26 +02:00
system := ws . NewSystemMock ( "2010-05-30 00:15:00 +0100" )
2020-09-29 12:44:31 +02:00
// test
err := aggregateVersionWideLibraries ( config , utils , system )
// assert
2021-02-10 17:18:00 +02:00
resource := filepath . Join ( ws . ReportsDirectory , "libraries-20100510-001542.csv" )
2020-09-29 12:44:31 +02:00
if assert . NoError ( t , err ) && assert . True ( t , utils . HasWrittenFile ( resource ) ) {
contents , _ := utils . FileRead ( resource )
asString := string ( contents )
assert . Equal ( t , "Library Name, Project Name\nmock-library, mock-project\n" , asString )
}
} )
}
func TestAggregateVersionWideVulnerabilities ( t * testing . T ) {
t . Parallel ( )
t . Run ( "happy path" , func ( t * testing . T ) {
// init
config := & ScanOptions {
2021-02-10 17:18:00 +02:00
ProductToken : "mock-product-token" ,
Version : "1" ,
2020-09-29 12:44:31 +02:00
}
utils := newWhitesourceUtilsMock ( )
2020-10-20 09:49:26 +02:00
system := ws . NewSystemMock ( "2010-05-30 00:15:00 +0100" )
2020-09-29 12:44:31 +02:00
// test
err := aggregateVersionWideVulnerabilities ( config , utils , system )
// assert
2021-02-10 17:18:00 +02:00
resource := filepath . Join ( ws . ReportsDirectory , "project-names-aggregated.txt" )
2020-09-29 12:44:31 +02:00
assert . NoError ( t , err )
if assert . True ( t , utils . HasWrittenFile ( resource ) ) {
contents , _ := utils . FileRead ( resource )
asString := string ( contents )
assert . Equal ( t , "mock-project - 1\n" , asString )
}
2021-02-10 17:18:00 +02:00
reportSheet := filepath . Join ( ws . ReportsDirectory , "vulnerabilities-20100510-001542.xlsx" )
2020-09-29 12:44:31 +02:00
sheetContents , err := utils . FileRead ( reportSheet )
assert . NoError ( t , err )
assert . NotEmpty ( t , sheetContents )
} )
}
2021-02-10 17:18:00 +02:00
func TestPersistScannedProjects ( t * testing . T ) {
2020-09-29 12:44:31 +02:00
t . Parallel ( )
2021-02-10 17:18:00 +02:00
t . Run ( "write 1 scanned projects" , func ( t * testing . T ) {
2020-09-29 12:44:31 +02:00
// init
2021-02-10 17:18:00 +02:00
cpe := whitesourceExecuteScanCommonPipelineEnvironment { }
config := & ScanOptions { Version : "1" }
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( config )
2021-02-10 17:18:00 +02:00
_ = scan . AppendScannedProject ( "project" )
2020-09-29 12:44:31 +02:00
// test
2021-02-10 17:18:00 +02:00
persistScannedProjects ( config , scan , & cpe )
2020-09-29 12:44:31 +02:00
// assert
2021-02-10 17:18:00 +02:00
assert . Equal ( t , [ ] string { "project - 1" } , cpe . custom . whitesourceProjectNames )
2020-09-29 12:44:31 +02:00
} )
2021-02-10 17:18:00 +02:00
t . Run ( "write 2 scanned projects" , func ( t * testing . T ) {
2020-09-29 12:44:31 +02:00
// init
2021-02-10 17:18:00 +02:00
cpe := whitesourceExecuteScanCommonPipelineEnvironment { }
config := & ScanOptions { Version : "1" }
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( config )
2021-02-10 17:18:00 +02:00
_ = scan . AppendScannedProject ( "project-app" )
_ = scan . AppendScannedProject ( "project-db" )
2020-09-29 12:44:31 +02:00
// test
2021-02-10 17:18:00 +02:00
persistScannedProjects ( config , scan , & cpe )
2020-09-29 12:44:31 +02:00
// assert
2021-02-10 17:18:00 +02:00
assert . Equal ( t , [ ] string { "project-app - 1" , "project-db - 1" } , cpe . custom . whitesourceProjectNames )
2020-09-29 12:44:31 +02:00
} )
2021-02-10 17:18:00 +02:00
t . Run ( "write no projects" , func ( t * testing . T ) {
2020-09-29 12:44:31 +02:00
// init
2021-02-10 17:18:00 +02:00
cpe := whitesourceExecuteScanCommonPipelineEnvironment { }
config := & ScanOptions { Version : "1" }
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( config )
// test
2021-02-10 17:18:00 +02:00
persistScannedProjects ( config , scan , & cpe )
2020-09-29 12:44:31 +02:00
// assert
2021-02-10 17:18:00 +02:00
assert . Equal ( t , [ ] string { } , cpe . custom . whitesourceProjectNames )
2020-09-29 12:44:31 +02:00
} )
2021-02-10 17:18:00 +02:00
t . Run ( "write aggregated project" , func ( t * testing . T ) {
2020-09-29 12:44:31 +02:00
// init
2021-02-10 17:18:00 +02:00
cpe := whitesourceExecuteScanCommonPipelineEnvironment { }
config := & ScanOptions { ProjectName : "project" , Version : "1" }
2020-09-29 12:44:31 +02:00
scan := newWhitesourceScan ( config )
// test
2021-02-10 17:18:00 +02:00
persistScannedProjects ( config , scan , & cpe )
2020-09-29 12:44:31 +02:00
// assert
2021-02-10 17:18:00 +02:00
assert . Equal ( t , [ ] string { "project - 1" } , cpe . custom . whitesourceProjectNames )
2020-09-29 12:44:31 +02:00
} )
2020-09-18 11:54:45 +02:00
}