Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ dependencies {
'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11.3',
'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.5',
'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.10.5',
'org.apache.logging.log4j:log4j-slf4j-impl:2.16.0',
'org.apache.logging.log4j:log4j-api:2.16.0',
'org.apache.logging.log4j:log4j-core:2.16.0'
'org.apache.logging.log4j:log4j-slf4j-impl:2.17.0',
'org.apache.logging.log4j:log4j-api:2.17.0',
'org.apache.logging.log4j:log4j-core:2.17.0'
constraints {
implementation('io.vertx:vertx-web:3.9.7') {
because 'previous versions have a bug impacting this application'
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
description = Provides automatic scan of code by Checkmarx server and shows results summary and trend in Jenkins interface.
group = com.checkmarx.jenkins
version = 2021.4.3
version = 2022.1.1

repositoryVersion=

Expand Down
70 changes: 69 additions & 1 deletion src/main/java/com/checkmarx/jenkins/CxScanBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@
import jenkins.model.Jenkins;
import jenkins.tasks.SimpleBuildStep;
import net.sf.json.JSONObject;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.kohsuke.stapler.*;
Expand Down Expand Up @@ -1320,7 +1322,15 @@ private CxScanConfig resolveConfiguration(Run<?, ?> run, DescriptorImpl descript
} else {
ret.setProxy(false);
}
teamPath = getTeamNameFromId(cxConnectionDetails, descriptor, groupId);

/*
* Pipeline script can provide grouoId or teamPath
* teamPath will take precedence if it is not empty.
* Freestyle job always send groupId, hence initializing teamPath using groupId
*/
if (!StringUtil.isNullOrEmpty(groupId) && StringUtil.isNullOrEmpty(teamPath)) {
teamPath = getTeamNameFromId(cxConnectionDetails, descriptor, groupId);
}
//project
ret.setProjectName(env.expand(projectName.trim()));
ret.setTeamPath(teamPath);
Expand Down Expand Up @@ -1534,6 +1544,20 @@ private AstScaConfig getScaConfig(Run<?, ?> run, EnvVars env, DependencyScanConf
result.setTenant(dsConfig.scaTenant);
result.setTeamPath(dsConfig.scaTeamPath);
result.setIncludeSources(dsConfig.isIncludeSources);

//add SCA Resolver code here
if (dsConfig.enableScaResolver != null
&& SCAScanType.SCA_RESOLVER.toString().equalsIgnoreCase(dsConfig.enableScaResolver.toString())) {
scaResolverPathExist(dsConfig.pathToScaResolver);
validateScaResolverParams(dsConfig.scaResolverAddParameters);
result.setEnableScaResolver(true);
}
else
result.setEnableScaResolver(false);

result.setPathToScaResolver(dsConfig.pathToScaResolver);
result.setScaResolverAddParameters(dsConfig.scaResolverAddParameters);

UsernamePasswordCredentials credentials = CxConnectionDetails.getCredentialsById(dsConfig.scaCredentialsId, run);
if (credentials != null) {
result.setUsername(credentials.getUsername());
Expand Down Expand Up @@ -1908,6 +1932,50 @@ private boolean isSkipScan(final Run<?, ?> run) {
}
return allowedCauses.isEmpty();
}

private boolean scaResolverPathExist(String pathToResolver) {
pathToResolver = pathToResolver + File.separator + "ScaResolver";
if(!SystemUtils.IS_OS_UNIX)
pathToResolver = pathToResolver + ".exe";

File file = new File(pathToResolver);
if(!file.exists())
{
throw new CxClientException("SCA Resolver path does not exist. Path="+file.getAbsolutePath());
}
return true;
}

private void validateScaResolverParams(String additionalParams) {

String[] arguments = additionalParams.split(" ");
Map<String, String> params = new HashMap<>();

for (int i = 0; i < arguments.length ; i++) {
if(arguments[i].startsWith("-") && (i+1 != arguments.length && !arguments[i+1].startsWith("-")))
params.put(arguments[i], arguments[i+1]);
else
params.put(arguments[i], "");
}

String dirPath = params.get("-s");
if(StringUtils.isEmpty(dirPath))
throw new CxClientException("Source code path (-s <source code path>) is not provided.");
fileExists(dirPath);

String projectName = params.get("-n");
if(StringUtils.isEmpty(projectName))
throw new CxClientException("Project name parameter (-n <project name>) must be provided to ScaResolver.");

}

private void fileExists(String file) {

File resultPath = new File(file);
if (!resultPath.exists()) {
throw new CxClientException("Path does not exist. Path= " + resultPath.getAbsolutePath());
}
}

/**
* Called when this plugin is initialized during Jenkins startup. Invoked by Jenkins using reflection.
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/com/checkmarx/jenkins/DependencyScanConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ public class DependencyScanConfig {

@DataBoundSetter
public boolean isIncludeSources;

@DataBoundSetter
public SCAScanType enableScaResolver;

@DataBoundSetter
public String pathToScaResolver;

@DataBoundSetter
public String scaResolverAddParameters;

@DataBoundSetter
public String fsaVariables;
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/checkmarx/jenkins/SCAScanType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.checkmarx.jenkins;

public enum SCAScanType {
SCA_RESOLVER,
MANIFEST
}
89 changes: 53 additions & 36 deletions src/main/resources/com/checkmarx/jenkins/CxScanBuilder/config.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -190,42 +190,59 @@
</f:entry>

<f:validateButton title="Test Connection" progress="Testing..." method="testScaConnection"
with="scaServerUrl,scaAccessControlUrl,scaCredentialsId,scaTenant,scaTimeout"/>

<f:entry title="Package Manager's Config File(s) Path" field="scaConfigFile">
<f:textarea value="${instance.dependencyScanConfig.scaConfigFile}" />
</f:entry>

<f:entry title="Private Registry Environment Variable" field="scaEnvVariables">
<f:textarea value="${instance.dependencyScanConfig.scaEnvVariables}" />
</f:entry>


<f:optionalBlock title="Include Sources" field="isIncludeSources"
inline="true" checked="${instance.dependencyScanConfig.isIncludeSources}"/>

<f:optionalBlock title="Enable Exploitable Path" field="isExploitablePath"
inline="true" checked="${instance.dependencyScanConfig.isExploitablePath}">

<f:optionalBlock title="Use global settings (${descriptor.credentialsDescription})" field="useJobLevelSastDetails"
inline="true" negative="true" checked="${!instance.dependencyScanConfig.useJobLevelSastDetails}">

<f:entry title="CxSAST Server Url" field="scaSastServerUrl">
<f:textbox default="${descriptor.dependencyScanConfig.serverUrl}" value="${instance.dependencyScanConfig.scaSastServerUrl}" />
</f:entry>
<f:entry title="CxSAST credentials" field="sastCredentialsId">
<c:select value="${instance.dependencyScanConfig.sastCredentialsId}" />
</f:entry>
<f:validateButton title="Test Connection" progress="Testing..." method="testScaSASTConnection"
with="scaSastServerUrl,password,username,timestamp,sastCredentialsId,isProxy" />
</f:optionalBlock>
<f:entry title="Project Full Path" field="scaSASTProjectFullPath">
<f:textbox value="${instance.dependencyScanConfig.scaSASTProjectFullPath}"/>
</f:entry>
<f:entry title="Project ID" field="scaSASTProjectID">
<f:textbox checkMethod="POST" value="${instance.dependencyScanConfig.scaSASTProjectID}"/>
</f:entry>
</f:optionalBlock>
with="scaServerUrl,scaAccessControlUrl,scaCredentialsId,scaTenant"/>

<f:radioBlock checked="${instance.dependencyScanConfig.enableScaResolver == null || instance.dependencyScanConfig.enableScaResolver == 'SCA_RESOLVER'}" inline="true"
name="enableScaResolver" title="Perform SCA scan using dependency resolution by SCA Resolver tool."
value="SCA_RESOLVER">
<!-- Sca Resolver Fields-->
<f:entry title="Path to SCA Resolver" field="pathToScaResolver">
<f:textbox value="${instance.dependencyScanConfig.pathToScaResolver}" />
</f:entry>

<f:entry title="SCA Resolver Additional Parameters" field="scaResolverAddParameters">
<f:textarea value="${instance.dependencyScanConfig.scaResolverAddParameters}" />
</f:entry>
</f:radioBlock>
<f:radioBlock checked="${instance.dependencyScanConfig.enableScaResolver == null || instance.dependencyScanConfig.enableScaResolver == 'MANIFEST'}" inline="true"
name="enableScaResolver" title="Perform SCA scan by uploading manifests file(s)/source to SCA Service."
value="MANIFEST">
<!-- Non-Sca Resolver Fields-->
<f:entry title="Package Manager's Config File(s) Path" field="scaConfigFile">
<f:textarea value="${instance.dependencyScanConfig.scaConfigFile}" />
</f:entry>

<f:entry title="Private Registry Environment Variable" field="scaEnvVariables">
<f:textarea value="${instance.dependencyScanConfig.scaEnvVariables}" />
</f:entry>

<f:optionalBlock title="Include Sources" field="isIncludeSources"
inline="true" checked="${instance.dependencyScanConfig.isIncludeSources}"/>

<f:optionalBlock title="Enable Exploitable Path" field="isExploitablePath"
inline="true" checked="${instance.dependencyScanConfig.isExploitablePath}">

<f:optionalBlock title="Use global settings (${descriptor.credentialsDescription})" field="useJobLevelSastDetails"
inline="true" negative="true" checked="${!instance.dependencyScanConfig.useJobLevelSastDetails}">

<f:entry title="CxSAST Server Url" field="scaSastServerUrl">
<f:textbox default="${descriptor.dependencyScanConfig.serverUrl}" value="${instance.dependencyScanConfig.scaSastServerUrl}" />
</f:entry>
<f:entry title="CxSAST credentials" field="sastCredentialsId">
<c:select value="${instance.dependencyScanConfig.sastCredentialsId}" />
</f:entry>
<f:validateButton title="Test Connection" progress="Testing..." method="testScaSASTConnection"
with="scaSastServerUrl,password,username,timestamp,sastCredentialsId,isProxy" />
</f:optionalBlock>

<f:entry title="Project Full Path" field="scaSASTProjectFullPath">
<f:textbox value="${instance.dependencyScanConfig.scaSASTProjectFullPath}"/>
</f:entry>
<f:entry title="Project ID" field="scaSASTProjectID">
<f:textbox checkMethod="POST" value="${instance.dependencyScanConfig.scaSASTProjectID}"/>
</f:entry>
</f:optionalBlock>
</f:radioBlock>
</f:nested>
</f:radioBlock>
</f:optionalBlock>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
When this flag is enabled, the plugin will use SCA Resolver utility to scan dependencies.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Folder path on the Jenkins node machine where ScaResolver is installed. For example: C:\Users\Installations\ScaResolver-win64 or /opt/ScaResolver-linux64.
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div>
Provide arguments to ScaResovler tool in the same format as supported by the ScaResolver tool. ScaResolver tool will be executed in offline mode.
<p>"-s", "-n" and "-r" are mandatory parameters. Example: -s C:\Users\SampleProject -n ProjectName -r c:\output, where </p>
<p> -s: Path to the source code</p>
<p> -n: name of the project</p>
<p> -r: local machine path where the evidence file must be stored</p>
</div>