1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00
sap-jenkins-library/cmd/whitesourceExecuteScan_test.go
Stephan Aßmus eff38f6c9d
whitesourcExecuteScan-go: Additional fixes (#2315)
* Make sure the UA scan is known to the scan object. Fixes downloading reports later on.
* Move polling into pkg/whitesource, add test for e2e scan
* Remove conditions from stash config resource
* Don't use version stored in CPE. This will prevent the versioningModel from being applied.
2020-11-10 09:09:51 +01:00

387 lines
14 KiB
Go

package cmd
import (
"path/filepath"
"testing"
"time"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/SAP/jenkins-library/pkg/versioning"
ws "github.com/SAP/jenkins-library/pkg/whitesource"
"github.com/stretchr/testify/assert"
)
type whitesourceCoordinatesMock struct {
GroupID string
ArtifactID string
Version string
}
type whitesourceUtilsMock struct {
*ws.ScanUtilsMock
coordinates whitesourceCoordinatesMock
usedBuildTool string
usedBuildDescriptorFile string
usedOptions versioning.Options
}
func (w *whitesourceUtilsMock) GetArtifactCoordinates(buildTool, buildDescriptorFile string,
options *versioning.Options) (versioning.Coordinates, error) {
w.usedBuildTool = buildTool
w.usedBuildDescriptorFile = buildDescriptorFile
w.usedOptions = *options
return w.coordinates, nil
}
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
}
func newWhitesourceUtilsMock() *whitesourceUtilsMock {
return &whitesourceUtilsMock{
ScanUtilsMock: &ws.ScanUtilsMock{
FilesMock: &mock.FilesMock{},
ExecMockRunner: &mock.ExecMockRunner{},
},
coordinates: whitesourceCoordinatesMock{
GroupID: "mock-group-id",
ArtifactID: "mock-artifact-id",
Version: "1.0.42",
},
}
}
func TestResolveProjectIdentifiers(t *testing.T) {
t.Parallel()
t.Run("happy path", 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.ProductVersion)
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("retrieves token for configured project name", func(t *testing.T) {
// init
config := ScanOptions{
BuildTool: "mta",
BuildDescriptorFile: "my-mta.yml",
VersioningModel: "major",
ProductName: "mock-product",
ProjectName: "mock-project",
}
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-project", scan.AggregateProjectName)
assert.Equal(t, "1", config.ProductVersion)
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)
}
})
t.Run("product not found", func(t *testing.T) {
// init
config := ScanOptions{
BuildTool: "mta",
VersioningModel: "major",
ProductName: "does-not-exist",
}
utilsMock := newWhitesourceUtilsMock()
systemMock := ws.NewSystemMock("ignored")
scan := newWhitesourceScan(&config)
// test
err := resolveProjectIdentifiers(&config, scan, utilsMock, systemMock)
// assert
assert.EqualError(t, err, "no product with name 'does-not-exist' found in Whitesource")
})
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)
})
}
func TestRunWhitesourceExecuteScan(t *testing.T) {
t.Parallel()
t.Run("fails for invalid configured project token", func(t *testing.T) {
// init
config := ScanOptions{
ScanType: "unified-agent",
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{}
// test
err := runWhitesourceExecuteScan(&config, scan, utilsMock, systemMock, &cpe)
// 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",
ReportDirectoryName: "ws-reports",
VulnerabilityReportFormat: "pdf",
Reporting: true,
AgentFileName: "ua.jar",
ProductName: "mock-product",
ProjectToken: "mock-project-token",
ScanType: "unified-agent",
}
utilsMock := newWhitesourceUtilsMock()
utilsMock.AddFile("wss-generated-file.config", []byte("key=value"))
lastUpdatedDate := time.Now().Format(ws.DateTimeLayout)
systemMock := ws.NewSystemMock(lastUpdatedDate)
scan := newWhitesourceScan(&config)
cpe := whitesourceExecuteScanCommonPipelineEnvironment{}
// test
err := runWhitesourceExecuteScan(&config, scan, utilsMock, systemMock, &cpe)
// 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("ws-reports/mock-project - 1-vulnerability-report.pdf"))
assert.True(t, utilsMock.HasWrittenFile("ws-reports/mock-project - 1-risk-report.pdf"))
})
}
func TestPersistScannedProjects(t *testing.T) {
t.Parallel()
t.Run("write 1 scanned projects", func(t *testing.T) {
// init
cpe := whitesourceExecuteScanCommonPipelineEnvironment{}
config := &ScanOptions{ProductVersion: "1"}
scan := newWhitesourceScan(config)
_ = scan.AppendScannedProject("project")
// test
persistScannedProjects(config, scan, &cpe)
// assert
assert.Equal(t, []string{"project - 1"}, cpe.custom.whitesourceProjectNames)
})
t.Run("write 2 scanned projects", func(t *testing.T) {
// init
cpe := whitesourceExecuteScanCommonPipelineEnvironment{}
config := &ScanOptions{ProductVersion: "1"}
scan := newWhitesourceScan(config)
_ = scan.AppendScannedProject("project-app")
_ = scan.AppendScannedProject("project-db")
// test
persistScannedProjects(config, scan, &cpe)
// assert
assert.Equal(t, []string{"project-app - 1", "project-db - 1"}, cpe.custom.whitesourceProjectNames)
})
t.Run("write no projects", func(t *testing.T) {
// init
cpe := whitesourceExecuteScanCommonPipelineEnvironment{}
config := &ScanOptions{ProductVersion: "1"}
scan := newWhitesourceScan(config)
// test
persistScannedProjects(config, scan, &cpe)
// assert
assert.Equal(t, []string{}, cpe.custom.whitesourceProjectNames)
})
t.Run("write aggregated project", func(t *testing.T) {
// init
cpe := whitesourceExecuteScanCommonPipelineEnvironment{}
config := &ScanOptions{ProjectName: "project", ProductVersion: "1"}
scan := newWhitesourceScan(config)
// test
persistScannedProjects(config, scan, &cpe)
// assert
assert.Equal(t, []string{"project - 1"}, cpe.custom.whitesourceProjectNames)
})
}
func TestAggregateVersionWideLibraries(t *testing.T) {
t.Parallel()
t.Run("happy path", func(t *testing.T) {
// init
config := &ScanOptions{
ProductToken: "mock-product-token",
ProductVersion: "1",
ReportDirectoryName: "mock-reports",
}
utils := newWhitesourceUtilsMock()
system := ws.NewSystemMock("2010-05-30 00:15:00 +0100")
// test
err := aggregateVersionWideLibraries(config, utils, system)
// assert
resource := filepath.Join("mock-reports", "libraries-20100510-001542.csv")
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{
ProductToken: "mock-product-token",
ProductVersion: "1",
ReportDirectoryName: "mock-reports",
}
utils := newWhitesourceUtilsMock()
system := ws.NewSystemMock("2010-05-30 00:15:00 +0100")
// test
err := aggregateVersionWideVulnerabilities(config, utils, system)
// assert
resource := filepath.Join("mock-reports", "project-names-aggregated.txt")
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)
}
reportSheet := filepath.Join("mock-reports", "vulnerabilities-20100510-001542.xlsx")
sheetContents, err := utils.FileRead(reportSheet)
assert.NoError(t, err)
assert.NotEmpty(t, sheetContents)
})
}
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",
ProductVersion: "1",
ReportDirectoryName: "mock-reports",
}
scan := newWhitesourceScan(config)
utils := newWhitesourceUtilsMock()
system := ws.NewSystemMock(time.Now().Format(ws.DateTimeLayout))
// test
err := checkAndReportScanResults(config, scan, utils, system)
// assert
assert.NoError(t, err)
vPath := filepath.Join("mock-reports", "mock-project-vulnerability-report.txt")
assert.False(t, utils.HasWrittenFile(vPath))
rPath := filepath.Join("mock-reports", "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))
// test
err := checkAndReportScanResults(config, scan, utils, system)
// 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",
ProductVersion: "1",
ReportDirectoryName: "mock-reports",
SecurityVulnerabilities: true,
CvssSeverityLimit: "6.0",
}
scan := newWhitesourceScan(config)
utils := newWhitesourceUtilsMock()
system := ws.NewSystemMock(time.Now().Format(ws.DateTimeLayout))
// test
err := checkAndReportScanResults(config, scan, utils, system)
// 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",
ProductVersion: "1",
ReportDirectoryName: "mock-reports",
SecurityVulnerabilities: true,
CvssSeverityLimit: "4",
}
scan := newWhitesourceScan(config)
utils := newWhitesourceUtilsMock()
system := ws.NewSystemMock(time.Now().Format(ws.DateTimeLayout))
// test
err := checkAndReportScanResults(config, scan, utils, system)
// 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")
})
}