1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/cmd/fortifyExecuteScan_test.go
Kevin Hudemann ceb3dd0a04
Refactor pkg/npm and npmExecuteScripts (#1684)
This change refactors the npm pkg and npmExecuteScripts implementations
to be reusable for future steps, e.g., npmExecuteLint.

In addition, it fixes few small bugs related to unit test execution on
Windows and the fileUtils mocking implementation.

Co-authored-by: Daniel Kurzynski <daniel.kurzynski@sap.com>
Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>
2020-06-18 17:30:17 +02:00

708 lines
30 KiB
Go

package cmd
import (
"context"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/google/go-github/v28/github"
"github.com/stretchr/testify/assert"
"github.com/piper-validation/fortify-client-go/models"
)
type fortifyMock struct {
Successive bool
}
func (f *fortifyMock) GetProjectByName(name string, autoCreate bool, projectVersion string) (*models.Project, error) {
return &models.Project{Name: &name}, nil
}
func (f *fortifyMock) GetProjectVersionDetailsByProjectIDAndVersionName(id int64, name string, autoCreate bool, projectName string) (*models.ProjectVersion, error) {
return &models.ProjectVersion{ID: id, Name: &name, Project: &models.Project{Name: &projectName}}, nil
}
func (f *fortifyMock) GetProjectVersionAttributesByProjectVersionID(id int64) ([]*models.Attribute, error) {
return []*models.Attribute{}, nil
}
func (f *fortifyMock) SetProjectVersionAttributesByProjectVersionID(id int64, attributes []*models.Attribute) ([]*models.Attribute, error) {
return attributes, nil
}
func (f *fortifyMock) CreateProjectVersionIfNotExist(projectName, projectVersionName, description string) (*models.ProjectVersion, error) {
return &models.ProjectVersion{ID: 4711, Name: &projectVersionName, Project: &models.Project{Name: &projectName}}, nil
}
func (f *fortifyMock) LookupOrCreateProjectVersionDetailsForPullRequest(projectID int64, masterProjectVersion *models.ProjectVersion, pullRequestName string) (*models.ProjectVersion, error) {
return &models.ProjectVersion{ID: 4712, Name: &pullRequestName, Project: masterProjectVersion.Project}, nil
}
func (f *fortifyMock) CreateProjectVersion(version *models.ProjectVersion) (*models.ProjectVersion, error) {
return version, nil
}
func (f *fortifyMock) ProjectVersionCopyFromPartial(sourceID, targetID int64) error {
return nil
}
func (f *fortifyMock) ProjectVersionCopyCurrentState(sourceID, targetID int64) error {
return nil
}
func (f *fortifyMock) ProjectVersionCopyPermissions(sourceID, targetID int64) error {
return nil
}
func (f *fortifyMock) CommitProjectVersion(id int64) (*models.ProjectVersion, error) {
name := "Committed"
return &models.ProjectVersion{ID: id, Name: &name}, nil
}
func (f *fortifyMock) MergeProjectVersionStateOfPRIntoMaster(downloadEndpoint, uploadEndpoint string, masterProjectID, masterProjectVersionID int64, pullRequestName string) error {
return nil
}
func (f *fortifyMock) GetArtifactsOfProjectVersion(id int64) ([]*models.Artifact, error) {
if id == 4711 {
return []*models.Artifact{{Status: "PROCESSED", UploadDate: models.Iso8601MilliDateTime(time.Now().UTC())}}, nil
}
if id == 4712 {
return []*models.Artifact{{Status: "ERROR_PROCESSING", UploadDate: models.Iso8601MilliDateTime(time.Now().UTC())}}, nil
}
if id == 4713 {
return []*models.Artifact{{Status: "REQUIRE_AUTH", UploadDate: models.Iso8601MilliDateTime(time.Now().UTC())}}, nil
}
if id == 4714 {
return []*models.Artifact{{Status: "PROCESSING", UploadDate: models.Iso8601MilliDateTime(time.Now().UTC())}}, nil
}
if id == 4715 {
return []*models.Artifact{{Status: "PROCESSED", Embed: &models.EmbeddedScans{[]*models.Scan{{BuildLabel: "/commit/test"}}}, UploadDate: models.Iso8601MilliDateTime(time.Now().UTC())}}, nil
}
return []*models.Artifact{}, nil
}
func (f *fortifyMock) GetFilterSetOfProjectVersionByTitle(id int64, title string) (*models.FilterSet, error) {
return &models.FilterSet{}, nil
}
func (f *fortifyMock) GetIssueFilterSelectorOfProjectVersionByName(id int64, names []string, options []string) (*models.IssueFilterSelectorSet, error) {
return &models.IssueFilterSelectorSet{}, nil
}
func (f *fortifyMock) GetFilterSetByDisplayName(issueFilterSelectorSet *models.IssueFilterSelectorSet, name string) *models.IssueFilterSelector {
if issueFilterSelectorSet.FilterBySet != nil {
for _, filter := range issueFilterSelectorSet.FilterBySet {
if filter.DisplayName == name {
return filter
}
}
}
return nil
}
func (f *fortifyMock) GetProjectIssuesByIDAndFilterSetGroupedBySelector(id int64, filter, filterSetGUID string, issueFilterSelectorSet *models.IssueFilterSelectorSet) ([]*models.ProjectVersionIssueGroup, error) {
if filter == "ET1:abcd" {
group := "HTTP Verb tampering"
total := int32(4)
audited := int32(3)
group2 := "Password in code"
total2 := int32(4)
audited2 := int32(4)
group3 := "Memory leak"
total3 := int32(5)
audited3 := int32(4)
return []*models.ProjectVersionIssueGroup{
{ID: &group, TotalCount: &total, AuditedCount: &audited},
{ID: &group2, TotalCount: &total2, AuditedCount: &audited2},
{ID: &group3, TotalCount: &total3, AuditedCount: &audited3},
}, nil
}
if issueFilterSelectorSet != nil && issueFilterSelectorSet.FilterBySet[0].GUID == "3" {
group := "3"
total := int32(4)
audited := int32(0)
group2 := "4"
total2 := int32(5)
audited2 := int32(0)
return []*models.ProjectVersionIssueGroup{
{ID: &group, TotalCount: &total, AuditedCount: &audited},
{ID: &group2, TotalCount: &total2, AuditedCount: &audited2},
}, nil
}
group := "Audit All"
total := int32(15)
audited := int32(12)
group2 := "Corporate Security Requirements"
total2 := int32(20)
audited2 := int32(11)
group3 := "Spot Checks of Each Category"
total3 := int32(5)
audited3 := int32(4)
return []*models.ProjectVersionIssueGroup{
{ID: &group, TotalCount: &total, AuditedCount: &audited},
{ID: &group2, TotalCount: &total2, AuditedCount: &audited2},
{ID: &group3, TotalCount: &total3, AuditedCount: &audited3},
}, nil
}
func (f *fortifyMock) ReduceIssueFilterSelectorSet(issueFilterSelectorSet *models.IssueFilterSelectorSet, names []string, options []string) *models.IssueFilterSelectorSet {
return issueFilterSelectorSet
}
func (f *fortifyMock) GetIssueStatisticsOfProjectVersion(id int64) ([]*models.IssueStatistics, error) {
suppressed := int32(6)
return []*models.IssueStatistics{{SuppressedCount: &suppressed}}, nil
}
func (f *fortifyMock) GenerateQGateReport(projectID, projectVersionID, reportTemplateID int64, projectName, projectVersionName, reportFormat string) (*models.SavedReport, error) {
if !f.Successive {
f.Successive = true
return &models.SavedReport{Status: "Processing"}, nil
}
f.Successive = false
return &models.SavedReport{Status: "Complete"}, nil
}
func (f *fortifyMock) GetReportDetails(id int64) (*models.SavedReport, error) {
return &models.SavedReport{Status: "Complete"}, nil
}
func (f *fortifyMock) UploadResultFile(endpoint, file string, projectVersionID int64) error {
return nil
}
func (f *fortifyMock) DownloadReportFile(endpoint string, projectVersionID int64) ([]byte, error) {
return []byte("abcd"), nil
}
func (f *fortifyMock) DownloadResultFile(endpoint string, projectVersionID int64) ([]byte, error) {
return []byte("defg"), nil
}
type pullRequestServiceMock struct{}
func (prService pullRequestServiceMock) ListPullRequestsWithCommit(ctx context.Context, owner, repo, sha string, opts *github.PullRequestListOptions) ([]*github.PullRequest, *github.Response, error) {
if owner == "A" {
result := 17
return []*github.PullRequest{{Number: &result}}, &github.Response{}, nil
} else if owner == "C" {
return []*github.PullRequest{}, &github.Response{}, errors.New("Test error")
}
return []*github.PullRequest{}, &github.Response{}, nil
}
type execRunnerMock struct {
numExecutions int
current *execution
executions []*execution
}
type execution struct {
dirValue string
envValue []string
outWriter io.Writer
errWriter io.Writer
executable string
parameters []string
}
func (er *execRunnerMock) newExecution() *execution {
newExecution := &execution{}
er.executions = append(er.executions, newExecution)
return newExecution
}
func (er *execRunnerMock) currentExecution() *execution {
if nil == er.current {
er.numExecutions = 0
er.current = er.newExecution()
}
return er.current
}
func (er *execRunnerMock) SetDir(d string) {
er.currentExecution().dirValue = d
}
func (er *execRunnerMock) SetEnv(e []string) {
er.currentExecution().envValue = e
}
func (er *execRunnerMock) Stdout(out io.Writer) {
er.currentExecution().outWriter = out
}
func (er *execRunnerMock) Stderr(err io.Writer) {
er.currentExecution().errWriter = err
}
func (er *execRunnerMock) RunExecutable(e string, p ...string) error {
er.numExecutions++
er.currentExecution().executable = e
er.currentExecution().parameters = p
classpathPip := "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib"
classpathMaven := "some.jar;someother.jar"
if e == "python2" {
er.currentExecution().outWriter.Write([]byte(classpathPip))
} else if e == "mvn" {
path := strings.ReplaceAll(p[2], "-Dmdep.outputFile=", "")
err := ioutil.WriteFile(path, []byte(classpathMaven), 0644)
if err != nil {
return err
}
}
er.current = er.newExecution()
return nil
}
func TestParametersAreValidated(t *testing.T) {
type parameterTestData struct {
nameOfRun string
config fortifyExecuteScanOptions
expectedError string
}
testData := []parameterTestData{
{
nameOfRun: "all parameters empty",
config: fortifyExecuteScanOptions{},
expectedError: "unable to get artifact from descriptor : build tool '' not supported",
},
}
for _, data := range testData {
t.Run(data.nameOfRun, func(t *testing.T) {
ff := fortifyMock{}
runner := execRunnerMock{}
influx := fortifyExecuteScanInflux{}
auditStatus := map[string]string{}
err := runFortifyScan(data.config, &ff, &runner, nil, &influx, auditStatus)
assert.EqualError(t, err, data.expectedError)
})
}
}
func TestAnalyseSuspiciousExploitable(t *testing.T) {
config := fortifyExecuteScanOptions{SpotCheckMinimum: 4, MustAuditIssueGroups: "Audit All, Corporate Security Requirements", SpotAuditIssueGroups: "Spot Checks of Each Category"}
ff := fortifyMock{}
influx := fortifyExecuteScanInflux{}
name := "test"
selectorGUID := "3"
selectorName := "Analysis"
selectorEntityType := "CUSTOMTAG"
projectVersion := models.ProjectVersion{ID: 4711, Name: &name}
auditStatus := map[string]string{}
selectorSet := models.IssueFilterSelectorSet{
FilterBySet: []*models.IssueFilterSelector{
{
GUID: selectorGUID,
DisplayName: selectorName,
EntityType: selectorEntityType,
},
},
GroupBySet: []*models.IssueSelector{
{
GUID: &selectorGUID,
DisplayName: &selectorName,
EntityType: &selectorEntityType,
},
},
}
issues := analyseSuspiciousExploitable(config, &ff, &projectVersion, &models.FilterSet{}, &selectorSet, &influx, auditStatus)
assert.Equal(t, 9, issues)
assert.Equal(t, "4", influx.fortify_data.fields.suspicious)
assert.Equal(t, "5", influx.fortify_data.fields.exploitable)
assert.Equal(t, "6", influx.fortify_data.fields.suppressed)
}
func TestAnalyseUnauditedIssues(t *testing.T) {
config := fortifyExecuteScanOptions{SpotCheckMinimum: 4, MustAuditIssueGroups: "Audit All, Corporate Security Requirements", SpotAuditIssueGroups: "Spot Checks of Each Category"}
ff := fortifyMock{}
influx := fortifyExecuteScanInflux{}
name := "test"
projectVersion := models.ProjectVersion{ID: 4711, Name: &name}
auditStatus := map[string]string{}
selectorSet := models.IssueFilterSelectorSet{
FilterBySet: []*models.IssueFilterSelector{
{
GUID: "1",
DisplayName: "Folder",
EntityType: "ET1",
SelectorOptions: []*models.SelectorOption{
{
Value: "abcd",
},
},
},
{
GUID: "2",
DisplayName: "Category",
EntityType: "ET2",
SelectorOptions: []*models.SelectorOption{
{
Value: "abcd",
},
},
},
{
GUID: "3",
DisplayName: "Analysis",
EntityType: "ET3",
SelectorOptions: []*models.SelectorOption{
{
Value: "abcd",
},
},
},
},
}
issues := analyseUnauditedIssues(config, &ff, &projectVersion, &models.FilterSet{}, &selectorSet, &influx, auditStatus)
assert.Equal(t, 13, issues)
assert.Equal(t, "15", influx.fortify_data.fields.auditAllTotal)
assert.Equal(t, "12", influx.fortify_data.fields.auditAllAudited)
assert.Equal(t, "20", influx.fortify_data.fields.corporateTotal)
assert.Equal(t, "11", influx.fortify_data.fields.corporateAudited)
assert.Equal(t, "13", influx.fortify_data.fields.spotChecksTotal)
assert.Equal(t, "11", influx.fortify_data.fields.spotChecksAudited)
assert.Equal(t, "1", influx.fortify_data.fields.spotChecksGap)
}
func TestTriggerFortifyScan(t *testing.T) {
t.Run("maven", func(t *testing.T) {
dir, err := ioutil.TempDir("", "test trigger fortify scan")
if err != nil {
t.Fatal("Failed to create temporary directory")
}
oldCWD, _ := os.Getwd()
_ = os.Chdir(dir)
// clean up tmp dir
defer func() {
_ = os.Chdir(oldCWD)
_ = os.RemoveAll(dir)
}()
runner := execRunnerMock{}
config := fortifyExecuteScanOptions{
BuildTool: "maven",
AutodetectClasspath: true,
BuildDescriptorFile: "./pom.xml",
Memory: "-Xmx4G -Xms2G",
Src: []string{"**/*.xml", "**/*.html", "**/*.jsp", "**/*.js", "src/main/resources/**/*", "src/main/java/**/*"}}
triggerFortifyScan(config, &runner, "test", "testLabel", "my.group-myartifact")
assert.Equal(t, 3, runner.numExecutions)
assert.Equal(t, "mvn", runner.executions[0].executable)
assert.Equal(t, []string{"--file", "./pom.xml", "-Dmdep.outputFile=fortify-execute-scan-cp.txt", "-DincludeScope=compile", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "dependency:build-classpath"}, runner.executions[0].parameters)
assert.Equal(t, "sourceanalyzer", runner.executions[1].executable)
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-Xmx4G", "-Xms2G", "-cp", "some.jar;someother.jar", "**/*.xml", "**/*.html", "**/*.jsp", "**/*.js", "src/main/resources/**/*", "src/main/java/**/*"}, runner.executions[1].parameters)
assert.Equal(t, "sourceanalyzer", runner.executions[2].executable)
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-scan", "-Xmx4G", "-Xms2G", "-build-label", "testLabel", "-build-project", "my.group-myartifact", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, runner.executions[2].parameters)
})
t.Run("pip", func(t *testing.T) {
dir, err := ioutil.TempDir("", "test trigger fortify scan")
if err != nil {
t.Fatal("Failed to create temporary directory")
}
oldCWD, _ := os.Getwd()
_ = os.Chdir(dir)
// clean up tmp dir
defer func() {
_ = os.Chdir(oldCWD)
_ = os.RemoveAll(dir)
}()
runner := execRunnerMock{}
config := fortifyExecuteScanOptions{BuildTool: "pip", PythonVersion: "python2", AutodetectClasspath: true, BuildDescriptorFile: "./setup.py", PythonRequirementsFile: "./requirements.txt", PythonInstallCommand: "pip2 install --user", Memory: "-Xmx4G -Xms2G"}
triggerFortifyScan(config, &runner, "test", "testLabel", "")
assert.Equal(t, 5, runner.numExecutions)
assert.Equal(t, "python2", runner.executions[0].executable)
separator := getSeparator()
template := fmt.Sprintf("import sys;p=sys.path;p.remove('');print('%v'.join(p))", separator)
assert.Equal(t, []string{"-c", template}, runner.executions[0].parameters)
assert.Equal(t, "pip2", runner.executions[1].executable)
assert.Equal(t, []string{"install", "--user", "-r", "./requirements.txt", ""}, runner.executions[1].parameters)
assert.Equal(t, "pip2", runner.executions[2].executable)
assert.Equal(t, []string{"install", "--user"}, runner.executions[2].parameters)
assert.Equal(t, "sourceanalyzer", runner.executions[3].executable)
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-Xmx4G", "-Xms2G", "-python-path", "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib", "-exclude", fmt.Sprintf("./**/tests/**/*%s./**/setup.py", separator), "./**/*"}, runner.executions[3].parameters)
assert.Equal(t, "sourceanalyzer", runner.executions[4].executable)
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-scan", "-Xmx4G", "-Xms2G", "-build-label", "testLabel", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, runner.executions[4].parameters)
})
}
func TestGenerateAndDownloadQGateReport(t *testing.T) {
ffMock := fortifyMock{Successive: false}
config := fortifyExecuteScanOptions{ReportTemplateID: 18, ReportType: "PDF"}
name := "test"
projectVersion := models.ProjectVersion{ID: 4711, Name: &name}
project := models.Project{ID: 815, Name: &name}
projectVersion.Project = &project
t.Run("success", func(t *testing.T) {
data, err := generateAndDownloadQGateReport(config, &ffMock, &project, &projectVersion)
assert.NoError(t, err)
assert.Equal(t, []byte("abcd"), data)
})
}
func TestVerifyScanResultsFinishedUploading(t *testing.T) {
ffMock := fortifyMock{Successive: false}
t.Run("error no recent upload detected", func(t *testing.T) {
config := fortifyExecuteScanOptions{DeltaMinutes: -1}
err := verifyScanResultsFinishedUploading(config, &ffMock, 4711, "", &models.FilterSet{}, 0)
assert.EqualError(t, err, "No recent upload detected on Project Version")
})
config := fortifyExecuteScanOptions{DeltaMinutes: 20}
t.Run("success", func(t *testing.T) {
err := verifyScanResultsFinishedUploading(config, &ffMock, 4711, "", &models.FilterSet{}, 0)
assert.NoError(t, err)
})
t.Run("error processing", func(t *testing.T) {
err := verifyScanResultsFinishedUploading(config, &ffMock, 4712, "", &models.FilterSet{}, 0)
assert.EqualError(t, err, "There are artifacts that failed processing for Project Version 4712\n/html/ssc/index.jsp#!/version/4712/artifacts?filterSet=")
})
t.Run("error required auth", func(t *testing.T) {
err := verifyScanResultsFinishedUploading(config, &ffMock, 4713, "", &models.FilterSet{}, 0)
assert.EqualError(t, err, "There are artifacts that require manual approval for Project Version 4713\n/html/ssc/index.jsp#!/version/4713/artifacts?filterSet=")
})
t.Run("error polling timeout", func(t *testing.T) {
err := verifyScanResultsFinishedUploading(config, &ffMock, 4714, "", &models.FilterSet{}, 1)
assert.EqualError(t, err, "Terminating after 0 minutes since artifact for Project Version 4714 is still in status PROCESSING")
})
t.Run("success build label", func(t *testing.T) {
err := verifyScanResultsFinishedUploading(config, &ffMock, 4715, "/commit/test", &models.FilterSet{}, 0)
assert.NoError(t, err)
})
t.Run("error no artifacts", func(t *testing.T) {
err := verifyScanResultsFinishedUploading(config, &ffMock, 4716, "", &models.FilterSet{}, 0)
assert.EqualError(t, err, "No uploaded artifacts for assessment detected for project version with ID 4716")
})
}
func TestCalculateTimeDifferenceToLastUpload(t *testing.T) {
diffSeconds := calculateTimeDifferenceToLastUpload(models.Iso8601MilliDateTime(time.Now().UTC()), 1234)
assert.Equal(t, true, diffSeconds < 1)
}
func TestExecuteTemplatedCommand(t *testing.T) {
runner := execRunnerMock{}
template := []string{"{{.Executable}}", "-c", "{{.Param}}"}
context := map[string]string{"Executable": "test.cmd", "Param": "abcd"}
executeTemplatedCommand(&runner, template, context)
assert.Equal(t, "test.cmd", runner.executions[0].executable)
assert.Equal(t, []string{"-c", "abcd"}, runner.executions[0].parameters)
}
func TestDeterminePullRequestMerge(t *testing.T) {
config := fortifyExecuteScanOptions{CommitMessage: "Merge pull request #2462 from branch f-test", PullRequestMessageRegex: `(?m).*Merge pull request #(\d+) from.*`, PullRequestMessageRegexGroup: 1}
t.Run("success", func(t *testing.T) {
match := determinePullRequestMerge(config)
assert.Equal(t, "2462", match, "Expected different result")
})
t.Run("no match", func(t *testing.T) {
config.CommitMessage = "Some test commit"
match := determinePullRequestMerge(config)
assert.Equal(t, "", match, "Expected different result")
})
}
func TestDeterminePullRequestMergeGithub(t *testing.T) {
prServiceMock := pullRequestServiceMock{}
t.Run("success", func(t *testing.T) {
match, err := determinePullRequestMergeGithub(nil, fortifyExecuteScanOptions{Owner: "A"}, prServiceMock)
assert.NoError(t, err)
assert.Equal(t, "17", match, "Expected different result")
})
t.Run("no match", func(t *testing.T) {
match, err := determinePullRequestMergeGithub(nil, fortifyExecuteScanOptions{Owner: "B"}, prServiceMock)
assert.NoError(t, err)
assert.Equal(t, "", match, "Expected different result")
})
t.Run("error", func(t *testing.T) {
match, err := determinePullRequestMergeGithub(nil, fortifyExecuteScanOptions{Owner: "C"}, prServiceMock)
assert.EqualError(t, err, "Test error")
assert.Equal(t, "", match, "Expected different result")
})
}
func TestTranslateProject(t *testing.T) {
t.Run("python", func(t *testing.T) {
execRunner := execRunnerMock{}
config := fortifyExecuteScanOptions{BuildTool: "pip", Memory: "-Xmx4G", Translate: `[{"pythonPath":"./some/path","src":"./**/*","exclude":"./tests/**/*"}]`}
translateProject(&config, &execRunner, "/commit/7267658798797", "")
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx4G", "-python-path", "./some/path", "-exclude", "./tests/**/*", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters")
})
t.Run("asp", func(t *testing.T) {
execRunner := execRunnerMock{}
config := fortifyExecuteScanOptions{BuildTool: "windows", Memory: "-Xmx6G", Translate: `[{"aspnetcore":"true","dotNetCoreVersion":"3.5","exclude":"./tests/**/*","libDirs":"tmp/","src":"./**/*"}]`}
translateProject(&config, &execRunner, "/commit/7267658798797", "")
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx6G", "-aspnetcore", "-dotnet-core-version", "3.5", "-libdirs", "tmp/", "-exclude", "./tests/**/*", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters")
})
t.Run("java", func(t *testing.T) {
execRunner := execRunnerMock{}
config := fortifyExecuteScanOptions{BuildTool: "maven", Memory: "-Xmx2G", Translate: `[{"classpath":"./classes/*.jar","extdirs":"tmp/","jdk":"1.8.0-21","source":"1.8","sourcepath":"src/ext/","src":"./**/*"}]`}
translateProject(&config, &execRunner, "/commit/7267658798797", "")
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx2G", "-cp", "./classes/*.jar", "-extdirs", "tmp/", "-source", "1.8", "-jdk", "1.8.0-21", "-sourcepath", "src/ext/", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters")
})
t.Run("auto classpath", func(t *testing.T) {
execRunner := execRunnerMock{}
config := fortifyExecuteScanOptions{BuildTool: "maven", Memory: "-Xmx2G", Translate: `[{"classpath":"./classes/*.jar", "extdirs":"tmp/","jdk":"1.8.0-21","source":"1.8","sourcepath":"src/ext/","src":"./**/*"}]`}
translateProject(&config, &execRunner, "/commit/7267658798797", "./WEB-INF/lib/*.jar")
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx2G", "-cp", "./WEB-INF/lib/*.jar", "-extdirs", "tmp/", "-source", "1.8", "-jdk", "1.8.0-21", "-sourcepath", "src/ext/", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters")
})
}
func TestScanProject(t *testing.T) {
config := fortifyExecuteScanOptions{Memory: "-Xmx4G"}
t.Run("normal", func(t *testing.T) {
execRunner := execRunnerMock{}
scanProject(&config, &execRunner, "/commit/7267658798797", "label", "my.group-myartifact")
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-scan", "-Xmx4G", "-build-label", "label", "-build-project", "my.group-myartifact", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, execRunner.executions[0].parameters, "Expected different parameters")
})
t.Run("quick", func(t *testing.T) {
execRunner := execRunnerMock{}
config.QuickScan = true
scanProject(&config, &execRunner, "/commit/7267658798797", "", "")
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-scan", "-Xmx4G", "-quick", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, execRunner.executions[0].parameters, "Expected different parameters")
})
}
func TestAutoresolveClasspath(t *testing.T) {
t.Run("success pip", func(t *testing.T) {
execRunner := execRunnerMock{}
dir, err := ioutil.TempDir("", "classpath")
assert.NoError(t, err, "Unexpected error detected")
defer os.RemoveAll(dir)
file := filepath.Join(dir, "cp.txt")
result := autoresolvePipClasspath("python2", []string{"-c", "import sys;p=sys.path;p.remove('');print(';'.join(p))"}, file, &execRunner)
assert.Equal(t, "python2", execRunner.executions[0].executable, "Expected different executable")
assert.Equal(t, []string{"-c", "import sys;p=sys.path;p.remove('');print(';'.join(p))"}, execRunner.executions[0].parameters, "Expected different parameters")
assert.Equal(t, "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib", result, "Expected different result")
})
t.Run("success maven", func(t *testing.T) {
execRunner := execRunnerMock{}
dir, err := ioutil.TempDir("", "classpath")
assert.NoError(t, err, "Unexpected error detected")
defer os.RemoveAll(dir)
file := filepath.Join(dir, "cp.txt")
result := autoresolveMavenClasspath(fortifyExecuteScanOptions{BuildDescriptorFile: "pom.xml"}, file, &execRunner)
assert.Equal(t, "mvn", execRunner.executions[0].executable, "Expected different executable")
assert.Equal(t, []string{"--file", "pom.xml", fmt.Sprintf("-Dmdep.outputFile=%v", file), "-DincludeScope=compile", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "dependency:build-classpath"}, execRunner.executions[0].parameters, "Expected different parameters")
assert.Equal(t, "some.jar;someother.jar", result, "Expected different result")
})
}
func TestPopulateMavenTranslate(t *testing.T) {
t.Run("src without translate", func(t *testing.T) {
config := fortifyExecuteScanOptions{Src: []string{"./**/*"}}
translate, err := populateMavenTranslate(&config, "")
assert.NoError(t, err)
assert.Equal(t, `[{"classpath":"","src":"./**/*"}]`, translate)
})
t.Run("exclude without translate", func(t *testing.T) {
config := fortifyExecuteScanOptions{Exclude: []string{"./**/*"}}
translate, err := populateMavenTranslate(&config, "")
assert.NoError(t, err)
assert.Equal(t, `[{"classpath":"","exclude":"./**/*","src":"**/*.xml:**/*.html:**/*.jsp:**/*.js:**/src/main/resources/**/*:**/src/main/java/**/*"}]`, translate)
})
t.Run("with translate", func(t *testing.T) {
config := fortifyExecuteScanOptions{Translate: `[{"classpath":""}]`, Src: []string{"./**/*"}, Exclude: []string{"./**/*"}}
translate, err := populateMavenTranslate(&config, "ignored/path")
assert.NoError(t, err)
assert.Equal(t, `[{"classpath":""}]`, translate)
})
}
func TestPopulatePipTranslate(t *testing.T) {
t.Run("PythonAdditionalPath without translate", func(t *testing.T) {
config := fortifyExecuteScanOptions{PythonAdditionalPath: []string{"./lib", "."}}
translate, err := populatePipTranslate(&config, "")
separator := getSeparator()
expected := fmt.Sprintf(`[{"exclude":"./**/tests/**/*%v./**/setup.py","pythonPath":"%v./lib%v.","src":"./**/*"}]`,
separator, separator, separator)
assert.NoError(t, err)
assert.Equal(t, expected, translate)
})
t.Run("Src without translate", func(t *testing.T) {
config := fortifyExecuteScanOptions{Src: []string{"./**/*.py"}}
translate, err := populatePipTranslate(&config, "")
separator := getSeparator()
expected := fmt.Sprintf(
`[{"exclude":"./**/tests/**/*%v./**/setup.py","pythonPath":"%v","src":"./**/*.py"}]`,
separator, separator)
assert.NoError(t, err)
assert.Equal(t, expected, translate)
})
t.Run("Exclude without translate", func(t *testing.T) {
config := fortifyExecuteScanOptions{Exclude: []string{"./**/tests/**/*"}}
translate, err := populatePipTranslate(&config, "")
separator := getSeparator()
expected := fmt.Sprintf(
`[{"exclude":"./**/tests/**/*","pythonPath":"%v","src":"./**/*"}]`,
separator)
assert.NoError(t, err)
assert.Equal(t, expected, translate)
})
t.Run("with translate", func(t *testing.T) {
config := fortifyExecuteScanOptions{
Translate: `[{"pythonPath":""}]`,
Src: []string{"./**/*"},
PythonAdditionalPath: []string{"./lib", "."}}
translate, err := populatePipTranslate(&config, "ignored/path")
assert.NoError(t, err)
assert.Equal(t, `[{"pythonPath":""}]`, translate, "Expected different parameters")
})
}
func TestRemoveDuplicates(t *testing.T) {
testData := []struct {
name string
input string
expected string
separator string
}{
{"empty", "", "", "x"},
{"no duplicates", ":a::b::", "a:b", ":"},
{"duplicates", "::a:b:a:b::a", "a:b", ":"},
{"long separator", "..a.b....ab..a.b", "a.b..ab", ".."},
{"no separator", "abc", "abc", ""},
}
for _, data := range testData {
t.Run(data.name, func(t *testing.T) {
assert.Equal(t, data.expected, removeDuplicates(data.input, data.separator))
})
}
}