Skip to content
Open
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
13 changes: 8 additions & 5 deletions src/main/java/org/jenkinsci/plugins/zap/ZAPBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import hudson.model.BuildListener;
import hudson.model.Computer;
import hudson.model.Node;
import hudson.model.Result;
import hudson.remoting.VirtualChannel;
import hudson.slaves.SlaveComputer;
import hudson.tasks.BuildStepDescriptor;
Expand All @@ -61,7 +62,8 @@

/**
* The main class of the plugin. This class adds a build step in a Jenkins job that allows you to launch the ZAP security tool and generate reports based on the alerts.
*
*
* @author Lenaic Tchokogoue
* @author Goran Sarenkapa
* @author Mostafa AbdelMoez
* @author Tanguy de Lignières
Expand Down Expand Up @@ -282,14 +284,15 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
return false;
}

boolean res;
Result res;
try {
if (startZAPFirst){
Utils.lineBreak(listener);
Utils.loggerMessage(listener, 0, "[{0}] SELENIUM SCRIPTS COMPLETED", Utils.ZAP);
}

res = build.getWorkspace().act(new ZAPDriverCallable(listener, this.zaproxy));
build.setResult(res);
proc.joinWithTimeout(60L, TimeUnit.MINUTES, listener);
Utils.lineBreak(listener);
Utils.lineBreak(listener);
Expand Down Expand Up @@ -334,7 +337,7 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
listener.error(ExceptionUtils.getStackTrace(e));
return false;
}
return res;
return res.completeBuild;
}

/**
Expand Down Expand Up @@ -433,7 +436,7 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc
/**
* Used to execute ZAP remotely.
*/
private static class ZAPDriverCallable implements FileCallable<Boolean> {
private static class ZAPDriverCallable implements FileCallable<Result> {

private static final long serialVersionUID = 1L;
private BuildListener listener;
Expand All @@ -445,7 +448,7 @@ public ZAPDriverCallable(BuildListener listener, ZAPDriver zaproxy) {
}

@Override
public Boolean invoke(File f, VirtualChannel channel) { return zaproxy.executeZAP(listener, new FilePath(f)); }
public Result invoke(File f, VirtualChannel channel) { return zaproxy.executeZAP(listener, new FilePath(f)); }

@Override
public void checkRoles(RoleChecker checker) throws SecurityException { /* N/A */ }
Expand Down
173 changes: 171 additions & 2 deletions src/main/java/org/jenkinsci/plugins/zap/ZAPDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
import hudson.model.EnvironmentSpecific;
import hudson.model.JDK;
import hudson.model.Node;
import hudson.model.Result;
import hudson.remoting.VirtualChannel;
import hudson.slaves.NodeSpecific;
import hudson.slaves.SlaveComputer;
Expand Down Expand Up @@ -178,6 +179,7 @@ public ZAPDriver(boolean autoInstall, String toolUsed, String zapHome, String jd
boolean exportreportAlertHigh, boolean exportreportAlertMedium, boolean exportreportAlertLow, boolean exportreportAlertInformational,
boolean exportreportCWEID, boolean exportreportWASCID, boolean exportreportDescription, boolean exportreportOtherInfo, boolean exportreportSolution, boolean exportreportReference, boolean exportreportRequestHeader, boolean exportreportResponseHeader, boolean exportreportRequestBody, boolean exportreportResponseBody,
boolean jiraCreate, String jiraProjectKey, String jiraAssignee, boolean jiraAlertHigh, boolean jiraAlertMedium, boolean jiraAlertLow, boolean jiraFilterIssuesByResourceType,
boolean buildThresholds, int hThresholdValue, int hSoftValue, int mThresholdValue, int mSoftValue, int lThresholdValue, int lSoftValue, int iThresholdValue, int iSoftValue, int cumulValue,
List<ZAPCmdLine> cmdLinesZAP) {

/* Startup */
Expand Down Expand Up @@ -283,6 +285,18 @@ public ZAPDriver(boolean autoInstall, String toolUsed, String zapHome, String jd
this.jiraAlertMedium = jiraAlertMedium;
this.jiraAlertLow = jiraAlertLow;
this.jiraFilterIssuesByResourceType = jiraFilterIssuesByResourceType;

/* Post Build Step*/
this.buildThresholds=buildThresholds;
this.hThresholdValue= hThresholdValue;
this.hSoftValue = hSoftValue;
this.mThresholdValue = mThresholdValue;
this.mSoftValue = mSoftValue;
this.lThresholdValue = lThresholdValue;
this.lSoftValue = lSoftValue;
this.iThresholdValue = iThresholdValue;
this.iSoftValue = iSoftValue;
this.cumulValue = cumulValue;
/* Other */
this.cmdLinesZAP = cmdLinesZAP != null ? new ArrayList<ZAPCmdLine>(cmdLinesZAP) : new ArrayList<ZAPCmdLine>();

Expand Down Expand Up @@ -411,6 +425,19 @@ public String toString() {
s += "jiraAlertMedium [" + jiraAlertMedium + "]\n";
s += "jiraAlertLow [" + jiraAlertLow + "]\n";
s += "jiraFilterIssuesByResourceType[" + jiraFilterIssuesByResourceType + "]\n";
s += "\n";
s += " Post build \n";
s += "-------------------------------------------------------\n";
s += "buildThresholds [" + buildThresholds + "]\n";
s += "hThresholdValue [" + hThresholdValue + "]\n";
s += "hSoftValue [" + hSoftValue + "]\n";
s += "mThresholdValue [" + mThresholdValue + "]\n";
s += "mSoftValue [" + mSoftValue + "]\n";
s += "lThresholdValue [" + lThresholdValue + "]\n";
s += "lSoftValue [" + lSoftValue + "]\n";
s += "iThresholdValue [" + iThresholdValue + "]\n";
s += "iSoftValue [" + iSoftValue + "]\n";
s += "cumulValue [" + cumulValue + "]\n";
return s;
}

Expand Down Expand Up @@ -1084,8 +1111,9 @@ private boolean deleteExternalSites (BuildListener listener, ClientApi clientApi
* of type FilePath: a {@link FilePath} representing the build's workspace.
* @return of type: boolean DESC: true if no exception is caught, false otherwise.
*/
public boolean executeZAP(BuildListener listener, FilePath workspace) {
public Result executeZAP(BuildListener listener, FilePath workspace) {
boolean buildSuccess = true;
Result buildStatus=Result.SUCCESS;

/* Check to make sure that plugin's are installed with ZAP if they are selected in the UI. */
if (((this.generateReports) && this.selectedReportMethod.equals(EXPORT_REPORT)) || (this.jiraCreate)) {
Expand Down Expand Up @@ -1229,11 +1257,18 @@ else if (this.selectedReportMethod.equals(EXPORT_REPORT)) {
Utils.loggerMessage(listener, 1, "ALERTS COUNT [ {1} ]", Utils.ZAP, numberOfAlerts);
String numberOfMessages = ((ApiResponseElement) clientApi.core.numberOfMessages("")).getValue();
Utils.loggerMessage(listener, 1, "MESSAGES COUNT [ {1} ]", Utils.ZAP, numberOfMessages);

/* POST BUILD STEP */
Utils.lineBreak(listener);
Utils.loggerMessage(listener, 0, "[{0}] MANAGE POST-BUILD THRESHOLD(S) ENABLED [ {1} ]", Utils.ZAP, String.valueOf(this.buildThresholds).toUpperCase());
if(this.buildThresholds) buildStatus = ManageThreshold(listener, clientApi, this.hThresholdValue, this.hSoftValue, this.mThresholdValue, this.mSoftValue, this.lThresholdValue, this.lSoftValue, this.iThresholdValue, this.iSoftValue, this.cumulValue);

}
}
catch (Exception e) {
listener.error(ExceptionUtils.getStackTrace(e));
buildSuccess = false;
buildStatus = Result.ABORTED;
}
finally {
try {
Expand All @@ -1242,10 +1277,11 @@ else if (this.selectedReportMethod.equals(EXPORT_REPORT)) {
catch (ClientApiException e) {
listener.error(ExceptionUtils.getStackTrace(e));
buildSuccess = false;
buildStatus = Result.ABORTED;
}
}
Utils.lineBreak(listener);
return buildSuccess;
return buildStatus;
}

/**
Expand Down Expand Up @@ -2103,6 +2139,107 @@ else if (authMode) {
else Utils.loggerMessage(listener, 1, "SKIP ACTIVE SCAN FOR THE SITE [ {0} ]", targetURL);
}

/**
* ManageThreshold define build value failed, pass , unstable.
*
* @param listener
* of type BuildListener: the display log listener during the Jenkins job execution.
* @param clientApi
* of type ClientApi: the ZAP client API to call method.
* @param hThresholdValue
* of type int: the Weight of the alert severity high.
* @param hSoftValue
* of type int: the threshold of the alert severity high.
* @param mThresholdValue
* of type int: the Weight of the alert severity meduim.
* @param mSoftValue
* of type int: the threshold of the alert severity meduim.
* @param lThresholdValue
* of type int: the Weight of the alert severity low.
* @param lSoftValue
* of type int: the threshold of the alert severity low.
* @param iThresholdValue
* of type int: the Weight of the alert severity informational.
* @param iSoftValue
* of type int: the threshold of the alert severity informational.
* @param cumulValue
* of type int: the cumulative threshold of the alerts.
*
*/

private Result ManageThreshold(BuildListener listener,ClientApi clientApi, int hThresholdValue, int hSoftValue, int mThresholdValue, int mSoftValue, int lThresholdValue, int lSoftValue, int iThresholdValue, int iSoftValue, int cumulValue) throws ClientApiException, IOException {

Utils.lineBreak(listener);
Utils.loggerMessage(listener, 0, "START : COMPUTE THRESHOLD", Utils.ZAP);
Result buildStatus = Result.SUCCESS;

Utils.lineBreak(listener);
int nbAlertHigh = countAlertbySeverity(clientApi, "High");
Utils.loggerMessage(listener, 1, "ALERTS High COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertHigh));

int nbAlertMedium = countAlertbySeverity(clientApi, "Medium");
Utils.loggerMessage(listener, 1, "ALERTS Medium COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertMedium));

int nbAlertLow = countAlertbySeverity(clientApi, "Low");
Utils.loggerMessage(listener, 1, "ALERTS Low COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertLow));

int nbAlertInfo =countAlertbySeverity(clientApi, "Informational");
Utils.loggerMessage(listener, 1, "ALERTS Informational COUNT [ {1} ]", Utils.ZAP, Integer.toString(nbAlertInfo));

int hScale = computeProduct(hThresholdValue,nbAlertHigh);
int mScale = computeProduct(mThresholdValue,nbAlertMedium);
int lScale = computeProduct(lThresholdValue,nbAlertLow);
int iScale = computeProduct(iThresholdValue,nbAlertInfo);

if((mScale > mSoftValue) || (lScale > lSoftValue ) || (iScale > iSoftValue)){buildStatus = Result.UNSTABLE;}

if((hScale > hSoftValue) || ((hScale+mScale+lScale+iScale)> cumulValue)){buildStatus = Result.FAILURE;}

Utils.loggerMessage(listener, 0, "END : COMPUTING THRESHOLD", Utils.ZAP);

return buildStatus;

}

/**
* computeProduct do the product of two Integer.
*
* @param a
* of type Integer.
* @param b
* of type Integer.
*/
public int computeProduct(int a, int b){
int res;
res = a * b;
return res;
}

/**
* countAlertbySeverity count the number of alert by severity.
*
* @param clientApi
* of type ClientApi: the ZAP client API to call method.
* @param risk
* of type string : it's the alert severity.
*/
public int countAlertbySeverity(ClientApi clientApi,String risk)throws ClientApiException{
int nbAlert = 0;
List<String> tempid = new ArrayList<String>();
tempid.add("begin");

List allAlerts1 = ((ApiResponseList) clientApi.core.alerts("","","")).getItems();
for(int i=0;i<allAlerts1.size();i++) {
ApiResponseSet temp = ((ApiResponseSet) allAlerts1.get(i));
if (!tempid.contains(temp.getValue("alert").toString())) {
if (risk.equals(temp.getValue("risk").toString())) {nbAlert++;}
}
tempid.add(temp.getValue("alert").toString());
}

return nbAlert;
}

/**
* Stop ZAP if it has been previously started.
*
Expand Down Expand Up @@ -3176,5 +3313,37 @@ private void getAvailableFormats(ZAPDriverDescriptorImpl zapDriver) {
private final boolean jiraFilterIssuesByResourceType; /* Filter issues by resource type. */

public boolean getFiraFilterIssuesByResourceType() { return jiraFilterIssuesByResourceType; }

/* Post Build Step >> Manage Threshold */

private final boolean buildThresholds;
public boolean isbuildThresholds() {return buildThresholds;}

private final int hThresholdValue;
public int gethThresholdValue() {return hThresholdValue;}

private final int hSoftValue;
public int gethSoftValue() {return hSoftValue;}

private final int mThresholdValue;
public int getmThresholdValue() {return mThresholdValue;}

private final int mSoftValue;
public int getmSoftValue() {return mSoftValue;}

private final int lThresholdValue;
public int getlThresholdValue() {return lThresholdValue;}

private final int lSoftValue;
public int getlSoftValue() {return lSoftValue;}

private final int iThresholdValue;
public int getiThresholdValue() {return iThresholdValue;}

private final int iSoftValue;
public int getiSoftValue() {return iSoftValue;}

private final int cumulValue;
public int getcumulValue() {return cumulValue;}
/*****************************/
}
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,43 @@ SOFTWARE.
</f:entry>
</f:optionalBlock>
</f:section>
<f:section title="${%Post Build}">
<f:optionalBlock title="${%Define Build Management Threshold }" field="buildThresholds" inline="true">
<f:entry>
<table width="100%">
<tr>
<th></th>
<th>${%Threshold Value}</th>
<th>${%Soft Threshold }</th>
</tr>
<tr>
<td>High</td>
<td><f:textbox field="hThresholdValue"/></td>
<td><f:textbox field="hSoftValue"/></td>
</tr>
<tr>
<td>Medium</td>
<td><f:textbox field="mThresholdValue"/></td>
<td><f:textbox field="mSoftValue"/></td>
</tr>
<tr>
<td>Low</td>
<td><f:textbox field="lThresholdValue"/></td>
<td><f:textbox field="lSoftValue"/></td>
</tr>
<tr>
<td>Info</td>
<td><f:textbox field="iThresholdValue"/></td>
<td><f:textbox field="iSoftValue"/></td>
</tr>
</table>
<table width="100%">
<tr>
<td>Cumulative Threshold</td>
<td><f:textbox field="cumulValue"/></td>
</tr>
</table>
</f:entry>
</f:optionalBlock>
</f:section>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Post Build Management Threshold, allows zap to define if a build is flagged as passed, failed or unstable.</br></br>
<b>Threshold value</b> stand for the weight of each alert severity</br></br>
<b>Soft value</b> is threshold of each alert severity</br></br>
<b>Cumulative value</b> is the threshold of the build</br></br>
The build goes <b>unstable</b> when we are under the soft or cumulative value</br></br>
The build goes <b>failed</b> when we are under the soft and cumulative value</br></br><hr/></br>