Skip to content

Commit

Permalink
Aqua log and white-listing fixes (#1161)
Browse files Browse the repository at this point in the history
Updated the log for readability and fixed white-listing mechanism.

---------

Co-authored-by: brais <26645694+braisvq1996@users.noreply.github.com>
Co-authored-by: Josef <github@online.ms>
Co-authored-by: Clemens Utschig <40628552+clemensutschig@users.noreply.github.com>
Co-authored-by: Jorge Romero <jorge.romero.ext@boehringer-ingelheim.com>
Co-authored-by: Administrator EDP in a Box <admin@edpinabox.com>
Co-authored-by: brais <26645694+BraisVQ@users.noreply.github.com>
Co-authored-by: zxBCN Valeriu_Tuguran,Constantin (IT EDP) EXTERNAL <constantin.valeriu_tuguran.ext@boehringer-ingelheim.com>
  • Loading branch information
8 people committed Oct 23, 2024
1 parent c4e1532 commit b5d80c1
Show file tree
Hide file tree
Showing 14 changed files with 178 additions and 85 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# Changelog

## Unreleased
* Aqua log readability update and whitelisting mechanism fix ([#1161](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1161))
* Aqua remotely exploitable critical vulnerabilities improvements ([#1157](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1157))
* Fail builds when aqua scan detects remotely exploitable security vulnerabilities with solutions ([#1147](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1147))
* Fail the release manager pipeline and create security vulnerability issues or move them to TODO state if already present ([#1151](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1151))

### Added
* In the release manager pipeline, use the default integration branch for component ([#1144](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1144))
* In the release manager pipeline, use the default integration branch for component ([#1144](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1144))

### Changed
* Enhance SSDS Document Generation Performance using New Atlassian APIs ([#1084](https://github.com/opendevstack/ods-jenkins-shared-library/issues/1084))
Expand Down
10 changes: 9 additions & 1 deletion src/org/ods/component/Context.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,11 @@ class Context implements IContext {

logger.debug 'Retrieving Git information ...'
config.gitUrl = retrieveGitUrl()
logger.debug("Retrieved Git Url: ${config.gitUrl}")
config.gitBranch = retrieveGitBranch()
logger.debug("Retrieved Git Branch: ${config.gitBranch}")
config.gitCommit = retrieveGitCommit()
logger.debug("Retrieved Git Commit: ${config.gitCommit}")
config.gitCommitAuthor = retrieveGitCommitAuthor()
config.gitCommitMessage = retrieveGitCommitMessage()
config.gitCommitRawMessage = retrieveGitCommitRawMessage()
Expand Down Expand Up @@ -708,8 +711,13 @@ class Context implements IContext {
// in case code is already checked out, OpenShift build config can not be used for retrieving branch
branch = script.sh(
returnStdout: true,
script: 'git branch --show-current',
script: 'git rev-parse --abbrev-ref HEAD',
label: 'getting GIT branch to build').trim()
branch = script.sh(
returnStdout: true,
script: "git name-rev --name-only --exclude=tags/* ${branch} | cut -d ' ' -f2 |" +
" sed -e 's|remotes/origin/||g'",
label: 'resolving to real GIT branch to build').trim()
}
logger.debug "resolved branch ${branch}"
return branch
Expand Down
2 changes: 1 addition & 1 deletion src/org/ods/component/HelmDeploymentStrategy.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ class HelmDeploymentStrategy extends AbstractDeploymentStrategy {
'helmValuesFiles': options.helmValuesFiles,
'helmValues': options.helmValues,
'helmDefaultFlags': options.helmDefaultFlags,
'helmAdditionalFlags': options.helmAdditionalFlags
'helmAdditionalFlags': options.helmAdditionalFlags,
])
rolloutData["${resourceKind}/${resourceName}"] = podData
// TODO: Once the orchestration pipeline can deal with multiple replicas,
Expand Down
2 changes: 1 addition & 1 deletion src/org/ods/component/Pipeline.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ class Pipeline implements Serializable {
script.stage('odsPipeline error') {
logger.warnClocked("${context.componentId}",
"***** Finished ODS Pipeline for ${context.componentId} (with error) *****")
logger.warn "Error: ${err}"
logger.error "${err}"
updateBuildStatus('FAILURE')
setBitbucketBuildStatus('FAILED')
if (notifyNotGreen) {
Expand Down
79 changes: 55 additions & 24 deletions src/org/ods/component/ScanWithAquaStage.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class ScanWithAquaStage extends Stage {
private final OpenShiftService openShift
private final NexusService nexus
private final ScanWithAquaOptions options
private Map configurationAquaCluster
private Map configurationAquaProject
private final Map configurationAquaCluster
private final Map configurationAquaProject

@SuppressWarnings('ParameterCount')
@TypeChecked(TypeCheckingMode.SKIP)
Expand Down Expand Up @@ -113,7 +113,12 @@ class ScanWithAquaStage extends Stage {
try {
def resultInfo = steps.readJSON(text: steps.readFile(file: jsonFile) as String) as Map

actionableVulnerabilities = filterRemoteCriticalWithSolutionVulnerabilities(resultInfo);
List whitelistedRECVs = []
actionableVulnerabilities = filterRemoteCriticalWithSolutionVulnerabilities(resultInfo,
whitelistedRECVs)
if (whitelistedRECVs.size() > 0) {
logger.warn(buildWhiteListedRECVsMessage(whitelistedRECVs))
}

Map vulnerabilities = resultInfo.vulnerability_summary as Map
// returnCode is 0 --> Success or 4 --> Error policies
Expand All @@ -138,41 +143,54 @@ class ScanWithAquaStage extends Stage {
notifyAquaProblem(alertEmails, errorMessages)

if (actionableVulnerabilities?.size() > 0) { // We need to mark the pipeline and delete the image
addAquaVulnerabilityObjectsToContext(actionableVulnerabilities, nexusReportLink)
String response = openShift.deleteImage(context.getComponentId() + ":" + context.getShortGitCommit())
logger.info("Delete image response: " + response)
throw new AquaRemoteCriticalVulnerabilityWithSolutionException(
buildActionableMessageForAquaVulnerabilities(actionableVulnerabilities: actionableVulnerabilities,
nexusReportLink: nexusReportLink, gitUrl: context.getGitUrl(), gitBranch: context.getGitBranch(),
gitCommit: context.getGitCommit(), repoName: context.getRepoName()))
performActionsForRECVs(actionableVulnerabilities, nexusReportLink)
}

return
}

private void addAquaVulnerabilityObjectsToContext(List actionableVulnerabilities, String nexusReportLink) {
private void performActionsForRECVs(List actionableVulnerabilities, String nexusReportLink) {
def scannedBranch = computeScannedBranch()
addAquaVulnerabilityObjectsToContext(actionableVulnerabilities, nexusReportLink, scannedBranch)
String response = openShift.deleteImage(context.getComponentId() + ":" + context.getShortGitCommit())
logger.info("Delete image response: " + response)
throw new AquaRemoteCriticalVulnerabilityWithSolutionException(
buildActionableMessageForAquaVulnerabilities(actionableVulnerabilities: actionableVulnerabilities,
nexusReportLink: nexusReportLink, gitUrl: context.getGitUrl(), gitBranch: scannedBranch,
gitCommit: context.getGitCommit(), repoName: context.getRepoName()))
}

private void addAquaVulnerabilityObjectsToContext(List actionableVulnerabilities, String nexusReportLink,
String scannedBranch) {
context.addArtifactURI('aquaCriticalVulnerability', actionableVulnerabilities)
context.addArtifactURI('jiraComponentId', context.getComponentId())
context.addArtifactURI('gitUrl', context.getGitUrl())
context.addArtifactURI('gitBranch', context.getGitBranch())
context.addArtifactURI('gitBranch', scannedBranch)
context.addArtifactURI('repoName', context.getRepoName())
context.addArtifactURI('nexusReportLink', nexusReportLink)
}

private String buildWhiteListedRECVsMessage(List whiteListedRECVs) {
StringBuilder message = new StringBuilder("The Aqua scan detected the following remotely " +
"exploitable critical vulnerabilities which were whitelisted in Aqua: ")
message.append(whiteListedRECVs.join(", "))
return message.toString()
}

private String buildActionableMessageForAquaVulnerabilities(Map args) {
StringBuilder message = new StringBuilder();
StringBuilder message = new StringBuilder()
String gitBranchUrl = GitUtil.buildGitBranchUrl(args.gitUrl as String, context.getProjectId(),
args.repoName as String, args.gitBranch as String)
message.append("We detected remotely exploitable critical vulnerabilities in repository ${gitBranchUrl}. " +
"Due to their high severity, we must stop the delivery " +
"process until all vulnerabilities have been addressed. ")

message.append("\n\nThe following vulnerabilities were found:\n");
def count= 1;
message.append("\n\nThe following vulnerabilities were found:")
def count = 1
for (def vulnerability : args.actionableVulnerabilities) {
message.append("\n${count}. Vulnerability name: " + (vulnerability as Map).name as String)
message.append("\n${count}.1. Description: " + (vulnerability as Map).description as String)
message.append("\n${count}.2. Solution: " + (vulnerability as Map).solution as String)
message.append("\n\n${count}. Vulnerability name: " + (vulnerability as Map).name as String)
message.append("\n\n${count}.1. Description: " + (vulnerability as Map).description as String)
message.append("\n\n${count}.2. Solution: " + (vulnerability as Map).solution as String)
message.append("\n")
count++
}
Expand All @@ -181,8 +199,8 @@ class ScanWithAquaStage extends Stage {
message.append("\nThis commit exists in the following open pull requests: ")
def cnt = 1
for (def pr : openPRs) {
message.append("\n${cnt}. Pull request: " + (pr as Map).title as String)
message.append("\n${cnt}.1. Link: " + (pr as Map).link as String)
message.append("\n\n${cnt}. Pull request: " + (pr as Map).title as String)
message.append("\n\n${cnt}.1. Link: " + (pr as Map).link as String)
message.append("\n")
cnt++
}
Expand Down Expand Up @@ -214,7 +232,7 @@ class ScanWithAquaStage extends Stage {
}
response.add([
title: pr.title,
link: (((pr.links as Map).self as List)[0] as Map).href
link: (((pr.links as Map).self as List)[0] as Map).href,
])
}
response
Expand Down Expand Up @@ -298,7 +316,7 @@ class ScanWithAquaStage extends Stage {
}
((List) data.messages).add([
title: "Blocking",
value: "Yes"
value: "Yes",
])
}

Expand Down Expand Up @@ -388,18 +406,31 @@ class ScanWithAquaStage extends Stage {
}
}

private List filterRemoteCriticalWithSolutionVulnerabilities(Map aquaJsonMap) {
private List filterRemoteCriticalWithSolutionVulnerabilities(Map aquaJsonMap, List whitelistedRECVs) {
List result = []
aquaJsonMap.resources.each { it ->
(it as Map).vulnerabilities.each { vul ->
Map vulnerability = vul as Map
if ((vulnerability?.exploit_type as String)?.equalsIgnoreCase(REMOTE_EXPLOIT_TYPE)
&& (vulnerability?.aqua_severity as String)?.equalsIgnoreCase(CRITICAL_AQUA_SEVERITY)
&& !StringUtils.isEmpty((vulnerability?.solution as String).trim())) {
result.push(vulnerability)
if (Boolean.parseBoolean(vulnerability?.already_acknowledged as String)) {
whitelistedRECVs.add(vulnerability.name)
} else {
result.push(vulnerability)
}
}
}
}
return result
}

private String computeScannedBranch() {
def scannedBranch = context.getGitBranch()
if (scannedBranch.toLowerCase().startsWith("release/")) { // We scanned the default integration branch
scannedBranch = bitbucket.getDefaultBranch(context.getRepoName())
}
return scannedBranch
}

}
4 changes: 2 additions & 2 deletions src/org/ods/orchestration/BuildStage.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class BuildStage extends Stage {

def aquaCriticalVulnerabilityRepos = filterReposWithAquaCriticalVulnerability(repos)
if (aquaCriticalVulnerabilityRepos?.size() > 0) {
def securityVulnerabilityIssueKeys = project.jiraUseCase?.
Set securityVulnerabilityIssueKeys = project.jiraUseCase?.
createSecurityVulnerabilityIssues(aquaCriticalVulnerabilityRepos)
String aquaMessage = buildAquaSecurityVulnerabilityMessage(securityVulnerabilityIssueKeys)
logMessage += aquaMessage
Expand All @@ -119,7 +119,7 @@ class BuildStage extends Stage {
}
}

String buildAquaSecurityVulnerabilityMessage(List securityVulnerabilityIssueKeys) {
String buildAquaSecurityVulnerabilityMessage(Set securityVulnerabilityIssueKeys) {
if (securityVulnerabilityIssueKeys == null || securityVulnerabilityIssueKeys.size() == 0) {
// No issue created as Jira is not connected
return "\n\nRemotely exploitable critical vulnerabilities were detected (see above). " +
Expand Down
47 changes: 24 additions & 23 deletions src/org/ods/orchestration/service/JiraService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -227,33 +227,34 @@ class JiraService {
throw new IllegalArgumentException('Error: unable to create Jira issue. \'description\' is undefined.')
}

def request = [
fields: [
project: [
key: args.projectKey.toUpperCase()
],
summary: args.summary,
description: args.description,
fixVersions: [
[name: args.fixVersion]
],
issuetype: [
name: args.type
]
]
]

if (args.component) {
request.fields << [components: [[name: args.component]]]
}
if (args.priority) {
request.fields << [priority: [name: args.priority]]
}

def response = Unirest.post("${this.baseURL}/rest/api/2/issue")
.basicAuth(this.username, this.password)
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.body(JsonOutput.toJson(
[
fields: [
project: [
key: args.projectKey.toUpperCase()
],
summary: args.summary,
description: args.description,
components: [
[name: args.component]
],
priority: [
name: args.priority
],
fixVersions: [
[name: args.fixVersion]
],
issuetype: [
name: args.type
]
]
]
))
.body(JsonOutput.toJson(request))
.asString()

response.ifSuccess {
Expand Down
Loading

0 comments on commit b5d80c1

Please sign in to comment.