Skip to content

Commit

Permalink
Merge pull request #41 from jenkinsci/feature/AST-8453-handle-cancel-…
Browse files Browse the repository at this point in the history
…scan

Feature/ast 8453 handle cancel scan
  • Loading branch information
AndreGCX committed Apr 11, 2022
2 parents 562cfa1 + 2aa587a commit fd1ae11
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 40 deletions.
128 changes: 102 additions & 26 deletions src/main/java/com/checkmarx/jenkins/CheckmarxScanBuilder.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.checkmarx.jenkins;

import com.checkmarx.ast.scan.Scan;
import com.checkmarx.ast.wrapper.CxConfig;
import com.checkmarx.ast.wrapper.CxException;
import com.checkmarx.jenkins.credentials.CheckmarxApiToken;
import com.checkmarx.jenkins.model.ScanConfig;
Expand All @@ -20,6 +18,7 @@
import hudson.tasks.ArtifactArchiver;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import hudson.util.ArgumentListBuilder;
import hudson.util.DescribableList;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
Expand All @@ -36,12 +35,10 @@
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
import java.util.UUID;
import java.io.OutputStream;
import java.util.*;

import static com.cloudbees.plugins.credentials.CredentialsMatchers.anyOf;
import static com.cloudbees.plugins.credentials.CredentialsMatchers.withId;
Expand Down Expand Up @@ -262,31 +259,110 @@ public void perform(@NonNull Run<?, ?> run, @NonNull FilePath workspace, EnvVars
return;
}

final List<String> argumentsForCommand = PluginUtils.submitScanDetailsToWrapper(scanConfig, checkmarxCliExecutable, this.log);
ArgumentListBuilder arguments = new ArgumentListBuilder();
FileOutputStream fos = new FileOutputStream("./output.log");
arguments.add(argumentsForCommand);

try {
int exitCode = launcher.launch().cmds(arguments).envs(envVars).stdout(
// Writing stdout to file
new OutputStream() {
@Override
public void write(int b) throws IOException {
fos.write(b);
listener.getLogger().write(b);
}

@Override
public void flush() throws IOException {
super.flush();
fos.flush();
listener.getLogger().flush();
}

@Override
public void close() throws IOException {
super.close();
fos.close();
listener.getLogger().close();
}
}).join();

if(exitCode != 0) {
log.error(String.format("Exit code from AST-CLI: %s", exitCode));
run.setResult(Result.FAILURE);
return;
}
} catch (InterruptedException interruptedException) {
String scanId = PluginUtils.getScanIdFromLogFile("./output.log", log);
if(!scanId.isEmpty()) {
log.info("Cancelling scan with id: {}", scanId);
launcher.launch().cmds(PluginUtils.scanCancel(UUID.fromString(scanId), scanConfig, checkmarxCliExecutable, this.log)).envs(envVars).stdout(listener.getLogger()).join();
log.info("Successfully canceled scan with id: {}", scanId);
}
run.setResult(Result.ABORTED);
return;
} catch (Exception e) {
log.info(e.getMessage());
run.setResult(Result.FAILURE);
return;
}

String scanId = PluginUtils.getScanIdFromLogFile("./output.log", log);

FilePath tempDir = workspace.createTempDir("cx", "");

ArgumentListBuilder htmlArguments = new ArgumentListBuilder();
ArgumentListBuilder jsonArguments = new ArgumentListBuilder();

try {
final Scan scan = PluginUtils.submitScanDetailsToWrapper(scanConfig, checkmarxCliExecutable, this.log);
PluginUtils.generateHTMLReport(workspace, UUID.fromString(scan.getId()), scanConfig, checkmarxCliExecutable, log);
PluginUtils.generateJsonReport(workspace, UUID.fromString(scan.getId()), scanConfig, checkmarxCliExecutable, log);
final List<String> htmlReportCommand = PluginUtils.generateHTMLReport(UUID.fromString(scanId), scanConfig, checkmarxCliExecutable, log);

ArtifactArchiver artifactArchiverHtml = new ArtifactArchiver(workspace.getName() + "_" + PluginUtils.CHECKMARX_AST_RESULTS_HTML);
String fileName = Long.toString(System.nanoTime());

htmlArguments.add(htmlReportCommand);
//Adding temp directory path name to command arguments
htmlArguments.add("--output-path");
htmlArguments.add(tempDir.getRemote());
//Adding output file name to command arguments
htmlArguments.add("--output-name");
htmlArguments.add(fileName);

launcher.launch().cmds(htmlArguments).envs(envVars).stdout(listener.getLogger()).join();

final List<String> jsonReportCommand = PluginUtils.generateJsonReport(UUID.fromString(scanId), scanConfig, checkmarxCliExecutable, log);

jsonArguments.add(jsonReportCommand);
//Adding temp directory path name to command arguments
jsonArguments.add("--output-path");
jsonArguments.add(tempDir.getRemote());
//Adding output file name to command arguments
jsonArguments.add("--output-name");
jsonArguments.add(fileName);

launcher.launch().cmds(jsonArguments).envs(envVars).stdout(listener.getLogger()).join();

//Getting created report files path
FilePath htmlReportFilePath = tempDir.child(fileName + ".html" );
FilePath jsonReportFilePath = tempDir.child(fileName + ".json" );

ArtifactArchiver artifactArchiverHtml = new ArtifactArchiver(workspace.toURI().relativize(htmlReportFilePath.toURI()).toString());
artifactArchiverHtml.perform(run, workspace, envVars, launcher, listener);

ArtifactArchiver artifactArchiverJson = new ArtifactArchiver(workspace.getName() + "_" + PluginUtils.CHECKMARX_AST_RESULTS_JSON);
ArtifactArchiver artifactArchiverJson = new ArtifactArchiver(workspace.toURI().relativize(jsonReportFilePath.toURI()).toString());
artifactArchiverJson.perform(run, workspace, envVars, launcher, listener);

if (run.getActions(CheckmarxScanResultsAction.class).isEmpty()) {
run.addAction(new CheckmarxScanResultsAction());
}
run.setResult(Result.SUCCESS);
} catch (IOException | InterruptedException | URISyntaxException e) {
run.setResult(Result.FAILURE);
} catch (CxConfig.InvalidCLIConfigException e) {
log.error(e.getMessage());
run.setResult(Result.FAILURE);
} catch (CxException e) {
log.error(String.format("Exit code from AST-CLI: %s", e.getExitCode()));
log.error(e.getMessage());
run.setResult(Result.FAILURE);
} finally {
//Deleting temporary directory to clean up the workspace env
tempDir.deleteContents();
tempDir.delete();
}

if (run.getActions(CheckmarxScanResultsAction.class).isEmpty()) {
run.addAction(new CheckmarxScanResultsAction());
}
run.setResult(Result.SUCCESS);
}

/**
Expand Down Expand Up @@ -560,7 +636,7 @@ public FormValidation doTestConnection(@QueryParameter final String serverUrl,

String cxInstallationPath = getCheckmarxInstallationPath(checkmarxInstallation);
CheckmarxApiToken checkmarxApiToken = getCheckmarxApiToken(credentialsId);

DescribableList<NodeProperty<?>, NodePropertyDescriptor> globalNodeProperties = Jenkins.get().getGlobalNodeProperties();
EnvironmentVariablesNodeProperty environmentVariablesNodeProperty = globalNodeProperties.get(hudson.slaves.EnvironmentVariablesNodeProperty.class);

Expand Down
58 changes: 44 additions & 14 deletions src/main/java/com/checkmarx/jenkins/PluginUtils.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
package com.checkmarx.jenkins;

import com.checkmarx.ast.results.ReportFormat;
import com.checkmarx.ast.scan.Scan;
import com.checkmarx.ast.wrapper.CxConfig;
import com.checkmarx.ast.wrapper.CxConstants;
import com.checkmarx.ast.wrapper.CxException;
import com.checkmarx.ast.wrapper.CxWrapper;
import com.checkmarx.jenkins.model.ScanConfig;
import com.checkmarx.jenkins.tools.CheckmarxInstallation;
import hudson.FilePath;
import jenkins.model.Jenkins;

import java.io.IOException;
import java.io.*;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import static java.nio.charset.StandardCharsets.UTF_8;


public class PluginUtils {

public static final String CHECKMARX_AST_RESULTS_HTML = "checkmarx-ast-results.html";
public static final String CHECKMARX_AST_RESULTS_JSON = "checkmarx-ast-results.json";
public static final String REGEX_SCAN_ID_FROM_LOGS = "(ID)\":\"((\\\\\"|[^\"])*)";
private static final String JENKINS = "Jenkins";

public static CheckmarxInstallation findCheckmarxInstallation(final String checkmarxInstallation) {
Expand All @@ -33,7 +33,7 @@ public static CheckmarxInstallation findCheckmarxInstallation(final String check
.findFirst().orElse(null);
}

public static Scan submitScanDetailsToWrapper(final ScanConfig scanConfig, final String checkmarxCliExecutable, final CxLoggerAdapter log) throws IOException, InterruptedException, URISyntaxException, CxConfig.InvalidCLIConfigException, CxException {
public static List<String> submitScanDetailsToWrapper(final ScanConfig scanConfig, final String checkmarxCliExecutable, final CxLoggerAdapter log) throws IOException, InterruptedException, URISyntaxException, CxConfig.InvalidCLIConfigException, CxException {
log.info("Submitting the scan details to the CLI wrapper.");

final CxConfig cxConfig = initiateWrapperObject(scanConfig, checkmarxCliExecutable);
Expand All @@ -46,23 +46,28 @@ public static Scan submitScanDetailsToWrapper(final ScanConfig scanConfig, final
params.put(CxConstants.BRANCH, scanConfig.getBranchName());

final CxWrapper cxWrapper = new CxWrapper(cxConfig, log);
return cxWrapper.scanCreate(params, scanConfig.getAdditionalOptions());
return cxWrapper.buildScanCreateArguments(params, scanConfig.getAdditionalOptions());
}

public static void generateHTMLReport(FilePath workspace, UUID scanId, final ScanConfig scanConfig, final String checkmarxCliExecutable, final CxLoggerAdapter log) throws IOException, InterruptedException, CxException, URISyntaxException, CxConfig.InvalidCLIConfigException {
public static List<String> scanCancel(UUID scanId, final ScanConfig scanConfig, final String checkmarxCliExecutable, final CxLoggerAdapter log) throws IOException, InterruptedException, CxConfig.InvalidCLIConfigException {
final CxConfig cxConfig = initiateWrapperObject(scanConfig, checkmarxCliExecutable);

final CxWrapper cxWrapper = new CxWrapper(cxConfig, log);
final String summaryHtml = cxWrapper.results(scanId, ReportFormat.summaryHTML);
workspace.child(workspace.getName() + "_" + CHECKMARX_AST_RESULTS_HTML).write(summaryHtml, UTF_8.name());
return cxWrapper.buildScanCancelArguments(scanId);
}

public static void generateJsonReport(FilePath workspace, UUID scanId, final ScanConfig scanConfig, final String checkmarxCliExecutable, final CxLoggerAdapter log) throws IOException, InterruptedException, CxException, URISyntaxException, CxConfig.InvalidCLIConfigException {
public static List<String> generateHTMLReport(UUID scanId, final ScanConfig scanConfig, final String checkmarxCliExecutable, final CxLoggerAdapter log) throws IOException, InterruptedException, CxConfig.InvalidCLIConfigException {
final CxConfig cxConfig = initiateWrapperObject(scanConfig, checkmarxCliExecutable);

final CxWrapper cxWrapper = new CxWrapper(cxConfig, log);
final String summaryJson = cxWrapper.results(scanId, ReportFormat.summaryJSON);
workspace.child(workspace.getName() + "_" + CHECKMARX_AST_RESULTS_JSON).write(summaryJson, UTF_8.name());
return cxWrapper.buildResultsArguments(scanId, ReportFormat.summaryHTML);
}

public static List<String> generateJsonReport(UUID scanId, final ScanConfig scanConfig, final String checkmarxCliExecutable, final CxLoggerAdapter log) throws IOException, InterruptedException, CxException, URISyntaxException, CxConfig.InvalidCLIConfigException {
final CxConfig cxConfig = initiateWrapperObject(scanConfig, checkmarxCliExecutable);

final CxWrapper cxWrapper = new CxWrapper(cxConfig, log);
return cxWrapper.buildResultsArguments(scanId, ReportFormat.summaryJSON);
}

public static String authValidate(final ScanConfig scanConfig, final String checkmarxCliExecutable) throws IOException, InterruptedException, CxConfig.InvalidCLIConfigException, URISyntaxException, CxException {
Expand All @@ -83,4 +88,29 @@ private static CxConfig initiateWrapperObject(final ScanConfig scanConfig, final
.pathToExecutable(checkmarxCliExecutable)
.build();
}

public static String getScanIdFromLogFile(String filename, final CxLoggerAdapter log) {
try {
// regex to find scanId from logs
final String regex = REGEX_SCAN_ID_FROM_LOGS;
final Pattern pattern = Pattern.compile(regex);
Matcher matcher;

File logFile = new File(filename);
Scanner logFileReader = new Scanner(logFile, UTF_8.name());
while (logFileReader.hasNextLine()) {
String logs = logFileReader.nextLine();
matcher = pattern.matcher(logs);

if (matcher.find()) {
return matcher.group(2);
}
}
logFileReader.close();
} catch (FileNotFoundException err) {
log.error("An error occurred while finding scanId in logs", err);
}
return "";
}

}

0 comments on commit fd1ae11

Please sign in to comment.