Skip to content

Commit

Permalink
Special characters and version (#112)
Browse files Browse the repository at this point in the history
•	Corrected config-as-code feature. Prior version failed to parse cx.config file.
•	‘overrideProjectSetting’ plugin parameter indicates whether preset, engineConfigurationId value will be saved on the SAST project.
•	HTTP link to OSA scan results that appear in the plugin logs are corrected
•	Enhanced default include/exclude pattern to exclude SCAResolver’s result files.
•	Introduced ‘ABORTED’ as new value for parameters jobStatusOnError, vulnerabilityThresholdResult  that will stop the pipeline immediately
•	Fixed issue that the build was not marked failed for SCA Policy violations.
•	Upgraded below libraries:
  • Loading branch information
umeshwaghode authored Dec 5, 2022
1 parent 68a5130 commit de6842b
Show file tree
Hide file tree
Showing 16 changed files with 159 additions and 38 deletions.
16 changes: 12 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,24 @@ dependencies {
exclude group: 'org.apache.logging.log4j', module: 'log4j-core'
}

compile 'com.checkmarx:cx-client-common:2022.3.16',
'com.fasterxml.jackson.core:jackson-core:2.11.3',
compile ('com.checkmarx:cx-client-common:2022.4.3') {
exclude group: 'org.apache.commons', module: 'commons-compress'
exclude group: 'org.yaml' , module: 'snakeyaml'
exclude group: 'com.google.code.gson', module: 'gson'
}

compile 'com.fasterxml.jackson.core:jackson-core:2.11.3',
'com.fasterxml.jackson.core:jackson-annotations:2.11.3',
'com.fasterxml.jackson.core:jackson-databind:2.11.3',
'com.fasterxml.jackson.core:jackson-databind:2.14.1',
'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.17.1',
'org.apache.logging.log4j:log4j-api:2.17.1',
'org.apache.logging.log4j:log4j-core:2.17.1'
'org.apache.logging.log4j:log4j-core:2.17.1',
'org.apache.commons:commons-compress:1.22',
'com.google.code.gson:gson:2.8.9',
'org.yaml:snakeyaml:1.33'
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 = 2022.3.3
version = 2022.4.3

repositoryVersion=

Expand Down
21 changes: 21 additions & 0 deletions sample/cx.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
project:
fullPath: "Testcac02"
origin: "jenkins"
sast:
engineConfiguration: "Korean"
excludeFolders: \"_cvs, .svn, .hg, .git, .bzr, bin, obj, backup, node_modules\"
includeExcludePattern: \"!**/.cxsca-results.json, !**/.cxsca-sast-results.json, !.checkmarx/cx.config,!**/*.DS_Store, !**/*.ipr, !**/*.iws, !**/*.TEST_SOMETHING, !**/*.bak, !**/*.tmp, !**/*.aac, !**/*.aif, !**/*.iff, !**/*.m3u, !**/*.mid, !**/*.mp3, !**/*.mpa, !**/*.ra, !**/*.wav, !**/*.wma, !**/*.3g2, !**/*.3gp, !**/*.asf, !**/*.asx, !**/*.avi, !**/*.flv, !**/*.mov, !**/*.mp4, !**/*.mpg, !**/*.rm, !**/*.swf, !**/*.vob, !**/*.wmv, !**/*.bmp, !**/*.gif, !**/*.jpg, !**/*.png, !**/*.psd, !**/*.tif, !**/*.jar, !**/*.zip, !**/*.rar, !**/*.exe, !**/*.dll, !**/*.pdb, !**/*.7z, !**/*.gz, !**/*.tar.gz, !**/*.tar, !**/*.ahtm, !**/*.ahtml, !**/*.fhtml, !**/*.hdm, !**/*.hdml, !**/*.hsql, !**/*.ht, !**/*.hta, !**/*.htc, !**/*.htd, !**/*.htmls, !**/*.ihtml, !**/*.mht, !**/*.mhtm, !**/*.mhtml, !**/*.ssi, !**/*.stm, !**/*.stml, !**/*.ttml, !**/*.txn, !**/*.class, !**/*.iml, !**/Checkmarx/Reports/*.*\"
high: 3
medium: 1
low: 2
incremental: false
preset: "All"
privateScan: false
overrideProjectSetting: false
sca:
fileInclude: \"*.dll\"
fileExclude: \"nothing*.jar\"
pathExclude: \"!**/*.DS_Store, !**/*.ipr, !**/*.iws, !**/*.TEST_SOMETHING, !**/*.bak, !**/*.tmp, !**/*.aac, !**/*.aif, !**/*.iff, !**/*.m3u, !**/*.mid, !**/*.mp3, !**/*.mpa, !**/*.ra, !**/*.wav, !**/*.wma, !**/*.3g2, !**/*.3gp, !**/*.asf, !**/*.asx, !**/*.avi, !**/*.flv, !**/*.mov, !**/*.mp4, !**/*.mpg, !**/*.rm, !**/*.swf, !**/*.vob, !**/*.wmv, !**/*.bmp, !**/*.gif, !**/*.jpg, !**/*.png, !**/*.psd, !**/*.tif, !**/*.jar, !**/*.zip, !**/*.rar, !**/*.exe, !**/*.dll, !**/*.pdb, !**/*.7z, !**/*.gz, !**/*.tar.gz, !**/*.tar, !**/*.ahtm, !**/*.ahtml, !**/*.fhtml, !**/*.hdm, !**/*.hdml, !**/*.hsql, !**/*.ht, !**/*.hta, !**/*.htc, !**/*.htd, !**/*.htmls, !**/*.ihtml, !**/*.mht, !**/*.mhtm, !**/*.mhtml, !**/*.ssi, !**/*.stm, !**/*.stml, !**/*.ttml, !**/*.txn, !**/*.class, !**/*.iml, !**/Checkmarx/Reports/*.*\"
high: 3
medium: 3
low: 3
12 changes: 6 additions & 6 deletions src/main/java/com/checkmarx/jenkins/CxConnectionDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public class CxConnectionDetails {
private String serverUrl;
private String username;
private String encryptedPassword;
private Boolean isProxy;
private Boolean isScaProxy;
private boolean isProxy;
private boolean isScaProxy;

public String getServerUrl() {
return serverUrl;
Expand All @@ -48,18 +48,18 @@ public void setPassword(String encryptedPassword) {
this.encryptedPassword = encryptedPassword;
}

public Boolean isProxy() {
public boolean isProxy() {
return isProxy;
}

public void setProxy(Boolean proxy) {
public void setProxy(boolean proxy) {
isProxy = proxy;
}
public Boolean isScaProxy() {
public boolean isScaProxy() {
return isScaProxy;
}

public void setScaProxy(Boolean scaProxy) {
public void setScaProxy(boolean scaProxy) {
isScaProxy = scaProxy;
}

Expand Down
85 changes: 66 additions & 19 deletions src/main/java/com/checkmarx/jenkins/CxScanBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.checkmarx.configprovider.dto.ResourceType;
import com.checkmarx.configprovider.dto.interfaces.ConfigReader;
import com.checkmarx.jenkins.configascode.ConfigAsCode;
import com.checkmarx.jenkins.configascode.ProjectConfig;
import com.checkmarx.jenkins.configascode.SastConfig;
import com.checkmarx.jenkins.configascode.ScaConfig;
import com.checkmarx.jenkins.exception.CxCredException;
Expand Down Expand Up @@ -99,6 +100,8 @@ public class CxScanBuilder extends Builder implements SimpleBuildStep {
// Persistent plugin configuration parameters
//////////////////////////////////////////////////////////////////////////////////////
private boolean useOwnServerCredentials;

private boolean overrideProjectSetting;

private boolean configAsCode;
@Nullable
Expand Down Expand Up @@ -318,8 +321,17 @@ public boolean isConfigAsCode() {
public void setConfigAsCode(boolean configAsCode) {
this.configAsCode = configAsCode;
}

public boolean isOverrideProjectSetting() {
return overrideProjectSetting;
}

@Nullable
@DataBoundSetter
public void setOverrideProjectSetting(boolean overrideProjectSetting) {
this.overrideProjectSetting = overrideProjectSetting;
}

@Nullable
public String getServerUrl() {
return serverUrl;
}
Expand Down Expand Up @@ -905,7 +917,7 @@ public void perform(@Nonnull Run<?, ?> run, @Nonnull FilePath workspace, @Nonnul
try {
overrideConfigAsCode(config, workspace);
} catch (ConfigurationException e) {
log.warn("couldn't load config file", e.getMessage());
log.warn("couldn't load config file: " + e.getMessage(), e);
}
}

Expand All @@ -916,7 +928,7 @@ public void perform(@Nonnull Run<?, ?> run, @Nonnull FilePath workspace, @Nonnul
//validate at least one scan type is enabled
if (!config.isSastEnabled() && !config.isAstScaEnabled() && !config.isOsaEnabled()) {
log.error("Both SAST and dependency scan are disabled. Exiting.");
run.setResult(Result.FAILURE);
run.setResult(Result.FAILURE);
return;
}

Expand Down Expand Up @@ -1030,8 +1042,7 @@ private ConfigAsCode getConfigAsCode(ConfigReader reader) throws ConfigurationEx

if (configProvider.hasConfiguration(CX_ORIGIN, "project"))
configAsCodeFromFile.setProject(
configProvider.getStringConfiguration(CX_ORIGIN, "project")
);
configProvider.getConfiguration(CX_ORIGIN, "project",ProjectConfig.class));

if (configProvider.hasConfiguration(CX_ORIGIN, "team"))
configAsCodeFromFile.setTeam(
Expand All @@ -1052,22 +1063,22 @@ private void overrideConfigAsCode(ConfigAsCode configAsCodeFromFile, CxScanConfi

//map global
Optional.ofNullable(configAsCodeFromFile).ifPresent(cac -> {
if (StringUtils.isNotEmpty(cac.getProject())) {
scanConfig.setProjectName(cac.getProject());
overridesResults.put("Project Name:", String.valueOf(cac.getProject()));
if (StringUtils.isNotEmpty(cac.getProject().getFullPath())) {
scanConfig.setProjectName(cac.getProject().getFullPath());
overridesResults.put("Project Name:", String.valueOf(cac.getProject().getFullPath()));
}

if (StringUtils.isNotEmpty(cac.getTeam())) {
scanConfig.setTeamPath(cac.getTeam());
overridesResults.put("Project Name:", String.valueOf(cac.getTeam()));
overridesResults.put("Team Name:", String.valueOf(cac.getTeam()));
}
});

mapSastConfiguration(Optional.ofNullable(configAsCodeFromFile.getSast()), scanConfig, overridesResults);
mapScaConfiguration(Optional.ofNullable(configAsCodeFromFile.getSca()), scanConfig, overridesResults);

if (!overridesResults.isEmpty()) {
log.info("the following fields was overrides using config as code file : ");
log.info("The following fields are overridden using config as code file : ");
overridesResults.keySet().forEach(key -> log.info(String.format("%s = %s", key, overridesResults.get(key))));
}
}
Expand Down Expand Up @@ -1156,6 +1167,12 @@ private void mapSastConfiguration(Optional<SastConfig> sast, CxScanConfig scanCo
scanConfig.setIncremental(pValue);
overridesResults.put("Is Incremental", String.valueOf(pValue));
});

sast.map(SastConfig::isOverrideProjectSetting)
.ifPresent(pValue -> {
scanConfig.setIsOverrideProjectSetting(pValue);
overridesResults.put("Is OverrideProjectSetting", String.valueOf(pValue));
});

sast.map(SastConfig::isPrivateScan)
.ifPresent(pValue -> {
Expand Down Expand Up @@ -1190,8 +1207,10 @@ private void mapSastConfiguration(Optional<SastConfig> sast, CxScanConfig scanCo
.filter(StringUtils::isNotBlank)
.ifPresent(pValue -> {
scanConfig.setPresetName(pValue);
scanConfig.setPresetId(null);
overridesResults.put("Preset", pValue);
});


sast.map(SastConfig::getExcludeFolders)
.filter(StringUtils::isNotBlank)
Expand Down Expand Up @@ -1313,6 +1332,8 @@ private Boolean verifyCustomCharacters(String inputString) {
}
private CxScanConfig resolveConfiguration(Run<?, ?> run, DescriptorImpl descriptor, EnvVars env, CxLoggerAdapter log) throws IOException {
CxScanConfig ret = new CxScanConfig();

ret.setIsOverrideProjectSetting(overrideProjectSetting);

if (isIncremental() && isForceScan()) {
throw new IOException("Force scan and incremental scan can not be configured in pair for SAST. Configure either Incremental or Force scan option");
Expand Down Expand Up @@ -1411,6 +1432,7 @@ private CxScanConfig resolveConfiguration(Run<?, ?> run, DescriptorImpl descript
ret.setSastEnabled(this.sastEnabled == null || sastEnabled); //for backward compatibility, assuming if sastEnabled is not set, then sast is enabled

if (ret.isSastEnabled()) {

int presetId = parseInt(preset, log, "Invalid presetId: [%s]. Using default preset.", 0);
ret.setPresetId(presetId);

Expand Down Expand Up @@ -1724,6 +1746,7 @@ private void printConfiguration(CxScanConfig config, CxLoggerAdapter log) {
log.info("post scan action: " + config.getPostScanActionId());
log.info("is force scan: " + config.getForceScan());
log.info("scan level custom fields: " + config.getCustomFields());
log.info("overrideProjectSetting value: " + overrideProjectSetting);

ScannerType scannerType = getDependencyScannerType(config);
String dependencyScannerType = scannerType != null ? scannerType.getDisplayName() : "NONE";
Expand Down Expand Up @@ -1855,23 +1878,35 @@ private void writeJsonObjectToFile(Object jsonObj, File to, String description)
}
}

private void failTheBuild(Run<?, ?> run, CxScanConfig config, ScanResults ret) {
private void failTheBuild(Run<?, ?> run, CxScanConfig config, ScanResults ret) throws AbortException {
//assert if expected exception is thrown OR when vulnerabilities under threshold OR when policy violated
ScanSummary scanSummary = new ScanSummary(config, ret.getSastResults(), ret.getOsaResults(), ret.getScaResults());
if (scanSummary.hasErrors() || ret.getGeneralException() != null ||
(ret.getSastResults() != null && ret.getSastResults().getException() != null) ||
(ret.getOsaResults() != null && ret.getOsaResults().getException() != null) ||
(ret.getScaResults() != null && ret.getScaResults().getException() != null)) {
printBuildFailure(scanSummary.toString(), ret, log);
if (resolvedVulnerabilityThresholdResult != null) {
run.setResult(resolvedVulnerabilityThresholdResult);
}

String statusToReturn = "";
String msgPrefix = "";
if (!scanSummary.getThresholdErrors().isEmpty() || (config.getSastNewResultsThresholdEnabled() && scanSummary.isSastThresholdForNewResultsExceeded() ) ) {
resolvedVulnerabilityThresholdResult = resolvedVulnerabilityThresholdResult == null?
Result.fromString(JobStatusOnError.FAILURE.toString()): resolvedVulnerabilityThresholdResult;
run.setResult(resolvedVulnerabilityThresholdResult);
statusToReturn = resolvedVulnerabilityThresholdResult.toString();
msgPrefix = "Threshold exceeded.";
}else {
msgPrefix = "Scan error occurred.";
statusToReturn = getReturnStatusOnError(getDescriptor());
run.setResult(Result.fromString(statusToReturn));
}

if(JobStatusOnError.ABORTED.toString().equalsIgnoreCase(statusToReturn)) {
String msg = msgPrefix + "Job is configured to return ABORTED and stop the build/pipeline.";
log.warn(msg);
throw new AbortException(msg);
}

if (useUnstableOnError(getDescriptor())) {
run.setResult(Result.UNSTABLE);
} else {
run.setResult(Result.FAILURE);
}
}
}

Expand Down Expand Up @@ -1971,6 +2006,18 @@ private boolean useUnstableOnError(final DescriptorImpl descriptor) {
|| (JobStatusOnError.GLOBAL.equals(getJobStatusOnError()) && JobGlobalStatusOnError.UNSTABLE.equals(descriptor
.getJobGlobalStatusOnError()));
}

private String getReturnStatusOnError(final DescriptorImpl descriptor) {

String status = JobStatusOnError.FAILURE.toString();

if (JobStatusOnError.GLOBAL.equals(getJobStatusOnError()))
status = descriptor.getJobGlobalStatusOnError().toString();
else
status = getJobStatusOnError().toString();

return status;
}

/**
* Checks if job should fail with <code>UNSTABLE</code> status instead of <code>FAILED</code>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

public enum JobGlobalStatusOnError {

FAILURE("Failure"), UNSTABLE("Unstable");
FAILURE("Failure"), UNSTABLE("Unstable"), ABORTED("ABORTED");

private final String displayName;

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/checkmarx/jenkins/JobStatusOnError.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.checkmarx.jenkins;

public enum JobStatusOnError {
GLOBAL("Use Global Settings"), FAILURE("Failure"), UNSTABLE("Unstable");
GLOBAL("Use Global Settings"), FAILURE("Failure"), UNSTABLE("Unstable"), ABORTED("ABORTED");

private final String displayName;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

public class ConfigAsCode {
@Optional
private String project;
private ProjectConfig project;
@Optional
private String team;
@Optional
Expand All @@ -31,11 +31,11 @@ public void setSast(SastConfig sast) {
this.sast = sast;
}

public String getProject() {
public ProjectConfig getProject() {
return project;
}

public void setProject(String project) {
public void setProject(ProjectConfig project) {
this.project = project;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.checkmarx.jenkins.configascode;

import com.typesafe.config.Optional;

public class ProjectConfig {
@Optional
private String fullPath;
@Optional
private String origin;

public ProjectConfig() {
}

public String getOrigin() {
return origin;
}

public void setOrigin(String origin) {
this.origin = origin;
}

public String getFullPath() {
return fullPath;
}

public void setFullPath(String fullPath) {
this.fullPath = fullPath;
}
}
11 changes: 10 additions & 1 deletion src/main/java/com/checkmarx/jenkins/configascode/SastConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public class SastConfig {
private int medium;
@Optional
private int high;

@Optional
private boolean overrideProjectSetting;

public SastConfig() {
}
Expand Down Expand Up @@ -97,4 +98,12 @@ public boolean isPrivateScan() {
public void setPrivateScan(boolean privateScan) {
this.privateScan = privateScan;
}

public boolean isOverrideProjectSetting() {
return overrideProjectSetting;
}

public void setOverrideProjectSetting(boolean isOverrideProjectSetting) {
this.overrideProjectSetting = isOverrideProjectSetting;
}
}
Loading

0 comments on commit de6842b

Please sign in to comment.