diff --git a/.gitignore b/.gitignore index 74e9a99..9e3253f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,11 @@ gradle-app.setting .gradletasknamecache # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 -# gradle/wrapper/gradle-wrapper.properties \ No newline at end of file +# gradle/wrapper/gradle-wrapper.properties + +# Vi +*~ +*.swp +*.swo +*.seq + diff --git a/jenkins/jobs/dsl/java_reference_application_jobs.groovy b/jenkins/jobs/dsl/java_reference_application_jobs.groovy index 9104c20..12c1b23 100644 --- a/jenkins/jobs/dsl/java_reference_application_jobs.groovy +++ b/jenkins/jobs/dsl/java_reference_application_jobs.groovy @@ -18,6 +18,7 @@ def regressionTestJob = freeStyleJob(projectFolderName + "/Reference_Application def performanceTestJob = freeStyleJob(projectFolderName + "/Reference_Application_Performance_Tests") def deployJobToProdA = freeStyleJob(projectFolderName + "/Reference_Application_Deploy_ProdA") def deployJobToProdB = freeStyleJob(projectFolderName + "/Reference_Application_Deploy_ProdB") +def owaspDepCheckJob = freeStyleJob(projectFolderName + "/OWASP_Dependency_Check") // Views def pipelineView = buildPipelineView(projectFolderName + "/Java_Reference_Application") @@ -145,7 +146,7 @@ codeAnalysisJob.with { } label("java8") steps { - copyArtifacts('Reference_Application_Unit_Tests') { + copyArtifacts('Reference_Application_Build') { buildSelector { buildNumber('${B}') } @@ -540,3 +541,72 @@ deployJobToProdB.with { ) } } + +owaspDepCheckJob.with { + description("This job uses the OWASP Dependency Check plugin to check for CVEs in the application dependencies.") + wrappers { + preBuildCleanup() + injectPasswords() + maskPasswords() + sshAgent("adop-jenkins-master") + } + scm { + git { + remote { + url(referenceAppGitUrl) + credentials("adop-jenkins-master") + } + branch("*/master") + } + } + environmentVariables { + env('WORKSPACE_NAME', workspaceFolderName) + env('PROJECT_NAME', projectFolderName) + } + label("java8") + + steps { + maven { + goals('clean install -DskipTests') + mavenInstallation("ADOP Maven") + } + } + + configure { project -> + project / 'builders' / 'org.jenkinsci.plugins.DependencyCheck.DependencyCheckBuilder'(plugin: 'dependency-check-jenkins-plugin@1.4.4') { + skipOnScmChange false + skipOnUpstreamChange false + scanpath '' + outdir '' + datadir '' + suppressionFile '' + zipExtensions '' + isAutoupdateDisabled false + isVerboseLoggingEnabled false + includeHtmlReports false + useMavenArtifactsScanPath false + } + } + + + publishers { + dependencyCheck('') { + thresholdLimit('low') + canRunOnFailed(false) + useStableBuildAsReference(false) + useDeltaValues(false) + computeNew(false) + shouldDetectModules(false) + thresholds( + unstableTotal: [all: '', high: '', normal: '', low: ''], + failedTotal: [all: '', high: 0, normal: '', low: ''], + unstableNew: [all: '', high: '', normal: '', low: ''], + failedNew: [all: '', high: '', normal: '', low: ''] + ) + } + } + +} + + + diff --git a/src/test/groovy/com/java/cartridge/CodeAnalysisReferenceApplicationJobSpec.groovy b/src/test/groovy/com/java/cartridge/CodeAnalysisReferenceApplicationJobSpec.groovy index 44dd5b9..fb8f7e3 100644 --- a/src/test/groovy/com/java/cartridge/CodeAnalysisReferenceApplicationJobSpec.groovy +++ b/src/test/groovy/com/java/cartridge/CodeAnalysisReferenceApplicationJobSpec.groovy @@ -192,7 +192,7 @@ class CodeAnalysisReferenceApplicationJobSpec extends Specification { } where: - jenkinsJobName = 'Reference_Application_Unit_Tests' + jenkinsJobName = 'Reference_Application_Build' } def 'step SonarQube configuration block exists'() { @@ -298,4 +298,4 @@ class CodeAnalysisReferenceApplicationJobSpec extends Specification { 'B' | '${B}' 'PARENT_BUILD' | '${PARENT_BUILD}' } -} \ No newline at end of file +} diff --git a/src/test/groovy/com/java/cartridge/OwaspDependencyCheckJobSpec.groovy b/src/test/groovy/com/java/cartridge/OwaspDependencyCheckJobSpec.groovy new file mode 100644 index 0000000..d7249fc --- /dev/null +++ b/src/test/groovy/com/java/cartridge/OwaspDependencyCheckJobSpec.groovy @@ -0,0 +1,193 @@ +package com.java.cartridge + +import spock.lang.Unroll +import spock.lang.Shared +import spock.lang.Specification + +/** + * Tests that JavaReferenceApplication/OwaspDependencyCheck job works as expected. + */ +class OwaspDependencyCheckJobSpec extends Specification { + + @Shared + def helper = new DslHelper('jenkins/jobs/dsl/java_reference_application_jobs.groovy') + + @Shared + def Node node = new XmlParser().parseText(helper.jm.savedConfigs["${helper.projectName}/OWASP_Dependency_Check"]) + + def 'OWASP_Dependency_Check job is exists'() { + expect: + helper.jm.savedConfigs[jobName] != null + + where: + jobName = "${helper.projectName}/OWASP_Dependency_Check" + } + + def 'job parameters not exists'() { + expect: + node.properties.size() == 1 + node.properties['hudson.model.ParametersDefinitionProperty'].size() == 0 + } + + def 'workspace_name and project_name env variables injected'() { + expect: + node.properties.EnvInjectJobProperty.size() == 1 + + with(node.properties.EnvInjectJobProperty) { + info.size() == 1 + + with(info) { + propertiesContent.size() == 1 + + with(propertiesContent) { + text() == "WORKSPACE_NAME=${workspaceName}\nPROJECT_NAME=${projectName}" + } + } + } + + where: + workspaceName = helper.workspaceName + projectName = helper.projectName + } + + def 'job assigned to java8 node'() { + expect: + node.assignedNode.size() == 1 + node.assignedNode.text() == 'java8' + } + + def 'wrappers exists'() { + expect: + node.buildWrappers.size() == 1 + } + + @Unroll + def 'wrappers "#name" exists'() { + expect: + node.buildWrappers[key].size() == 1 + + where: + name | key + 'preBuildCleanup' | 'hudson.plugins.ws__cleanup.PreBuildCleanup' + 'injectPasswords' | 'EnvInjectPasswordWrapper' + 'maskPasswords' | 'com.michelin.cio.hudson.plugins.maskpasswords.MaskPasswordsBuildWrapper' + 'sshAgent' | 'com.cloudbees.jenkins.plugins.sshagent.SSHAgentBuildWrapper' + } + + @Unroll + def 'wrappers sshAgent with "#sshCredentials" value chosen'() { + expect: + node.buildWrappers['com.cloudbees.jenkins.plugins.sshagent.SSHAgentBuildWrapper'].size() == 1 + + with(node.buildWrappers['com.cloudbees.jenkins.plugins.sshagent.SSHAgentBuildWrapper']) { + text() == sshCredentials + } + + where: + sshCredentials = "adop-jenkins-master" + } + + def 'steps with two Maven blocks exists'() { + expect: + node.builders.size() == 1 + + with(node.builders[0]) { + children().size() == 2 + + with(children()[0]) { + name() == 'hudson.tasks.Maven' + } + } + } + + @Unroll + def 'step Maven target goal is "#goal"'() { + expect: + with(node.builders['hudson.tasks.Maven']) { + targets.size() == 1 + targets.text() == goal + } + + where: + goal = "clean install -DskipTests" + } + + @Unroll + def 'step Maven installation is "#installation" chosen'() { + expect: + with(node.builders['hudson.tasks.Maven']) { + mavenName.size() == 1 + mavenName.text() == installation + } + + where: + installation = "ADOP Maven" + } + + def 'scm block with settings exists'() { + expect: + node.scm.size() == 1 + + with(node.scm) { + userRemoteConfigs.size() == 1 + + with(userRemoteConfigs[0]) { + children().size() == 1 + + with(children()[0]) { + name() == 'hudson.plugins.git.UserRemoteConfig' + } + } + } + } + + def 'scm remote name is not specified'() { + expect: + with(node.scm.userRemoteConfigs[0].children()[0]) { + name.size() == 0 + } + } + + @Unroll + def 'scm remote url is "#referenceAppGitUrl"'() { + expect: + with(node.scm.userRemoteConfigs[0].children()[0]) { + url.size() == 1 + + with(url) { + text() == referenceAppGitUrl + } + } + + where: + referenceAppGitUrl = "ssh://jenkins@gerrit:29418/${helper.projectName}/spring-petclinic" + } + + @Unroll + def 'scm credentials specified as "#gitCredentials"'() { + expect: + with(node.scm.userRemoteConfigs[0].children()[0]) { + credentialsId.size() == 1 + + with(credentialsId) { + text() == gitCredentials + } + } + + where: + gitCredentials = "adop-jenkins-master" + } + + @Unroll + def 'scm branch is "#branchName"'() { + expect: + with(node.scm) { + branches.size() == 1 + branches['hudson.plugins.git.BranchSpec'].text() == branchName + } + + where: + branchName = '*/master' + } + +}