-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pr add break build thresholds #440
Conversation
private boolean checkIfBreakBuild(ScanRequest request, ScanResults results){ | ||
boolean breakBuildResult = false; | ||
|
||
if(thresholdValidator.isThresholdsConfigurationExist(request)){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge the 2 if statements to 1 (like you do in the else if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or make thresholdValidator.thresholdsExceeded test for isThresholdsConfigurationExist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this is different case.
If thresholds not exist I want to go check the break build, but if exist and exceeded, shouldn't go to the 'else' flow
so 'exceeded' vs 'not exist' is a different result
@@ -335,6 +335,11 @@ private boolean requiresCxCustomFields(List<Field> fields) { | |||
} | |||
|
|||
public boolean filteredIssuesPresent(ScanResults results) { | |||
if(results.getAdditionalDetails()==null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try to a void 2 return statements.
ex.
return Optional.ofNullable(results.getAdditionalDetails())
.map(details -> details.get(Constants.SUMMARY_KEY))
.map(flow -> !flow.isEmpty())
.orElse(false);
if (!isMergeAllowed) { | ||
log.info("Merge is not allowed, because some thresholds were exceeded."); | ||
requestResult = new OperationResult(OperationStatus.FAILURE, MERGE_FAILURE_DESCRIPTION); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are not logging the flow of is merged is allowed here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added log
boolean sastThresholds; | ||
boolean scaThresholds = false; | ||
|
||
sastThresholds = scanRequest.getThresholds() != null || flowProperties.getThresholds() != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please inline this statement
} | ||
|
||
if (isAllowed && scaScanner.isEnabled()) { | ||
isAllowed = isAllowedSca(scanResults, pullRequestReport); | ||
isAllowed = isAllowedSca(scanResults, request); | ||
} | ||
|
||
return isAllowed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks more readable to me:
boolean isSastAllowed = isSast() ? isAllowedSast(scanResults, request) : true;
boolean isScaAllowed = scaScanner.isEnabled() ? isAllowedSca(scanResults, request) : true;
return isSastAllowed && isScaAllowed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The result would be different. we want that if one of the scanner is enabled and its thresholds were exceeded - to return false (not allowed)
in your case, if SAST not enabled (only SCA), and SCA thresholds not exceeded - still we will return notAllowed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if SAST not enabled -> isSast() == false -> boolean isSastAllowed = true
SCA thresholds not exceeded -> scaScanner.isEnabled() == true -> isAllowedSca(scanResults, request) -> true
return isSastAllowed && isScaAllowed -> true && true -> true
still we will return notAllowed <- no as you can see we will return true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right I changed that (and simplified per intelij suggestion)
@@ -507,6 +508,25 @@ private void processResults(ScanRequest request, ScanResults results) throws Exi | |||
} | |||
} | |||
|
|||
private boolean checkIfBreakBuild(ScanRequest request, ScanResults results){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd move this method into ThresholdValidator. E.g. ThresholdValidator.shouldInterruptBuild(...)
This way we won't need to expose the isThresholdsConfigurationExist method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the ThresholdValidator shouldn't be aware of 'build', 'merge' or 'pull request' terminology
This is why I added 'isThresholdsConfigurationExist' as a generic check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ThresholdValidator is already aware of 'merge' and 'pull request' - see ThresholdValidatorImpl#isMergeAllowed. isMergeAllowed is reused in several services. I don't see any problem with this.
Adding shouldInterruptBuild to ThresholdValidator will put 2 similar checks next to each other. This will make the code more consistent.
The real problem with ThresholdValidator is that it does 2 things at once: validates both SAST and SCA results. There are "parallel" methods for each of them, e.g.
failSastPrIfResultHasAnyFindings
failScaPrIfResultHasAnyFindings
getSastFindingCountPerSeverity
getScaFindingsCountsPerSeverity
isAllowedSast
isAllowedSca
isAnySastThresholdExceeded
isAnyScaThresholdsExceeded
This is not good code design. The SAST and SCA functionalities should be separated.
if(thresholdValidator.thresholdsExceeded(request, results)){ | ||
log.info("Fail build on Thresholds exceeded."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to log what were the actual results and what were the thresholds so the user will understand why we failed the build? (like we do on the --web flow).
Moreover, you can set both 'if' statements inline..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is logged inside the ThresholdValidator.
regarding 'if' statement see 1st Ofer comment
breakBuildResult = true; | ||
} | ||
} else if(flowProperties.isBreakBuild() && resultsService.filteredIssuesPresent(results)){ | ||
log.info("Fail build on issues presented after executing filters"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand this message...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If thresholds not exist, the logic is to fail the build if there were left vulnerabilities after the processing
https://github.com/checkmarx-ltd/cx-flow/wiki/Thresholds-and-policies#thresholds-vs-basic-filters
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe something like: "Build failed, because some issues were found"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed
log.info(isAllowedScanner ? "Merge is allowed, because no thresholds were exceeded." : | ||
"Merge is not allowed, because some of the thresholds were exceeded."); | ||
log.info(isAllowedScanner ? "No thresholds were exceeded." : | ||
"Thresholds were exceeded."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's wrong with the original detailed message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ThresholdValidator check the thresholds logic, and shouldn't be aware of 'build', 'merge' or 'pull request'.
Moreover in CLI flow, the original message is wrong
There are still places in ThresholdValidator with such references, but the refactoring was too dramatic for this stage
@@ -507,6 +508,25 @@ private void processResults(ScanRequest request, ScanResults results) throws Exi | |||
} | |||
} | |||
|
|||
private boolean checkIfBreakBuild(ScanRequest request, ScanResults results){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ThresholdValidator is already aware of 'merge' and 'pull request' - see ThresholdValidatorImpl#isMergeAllowed. isMergeAllowed is reused in several services. I don't see any problem with this.
Adding shouldInterruptBuild to ThresholdValidator will put 2 similar checks next to each other. This will make the code more consistent.
The real problem with ThresholdValidator is that it does 2 things at once: validates both SAST and SCA results. There are "parallel" methods for each of them, e.g.
failSastPrIfResultHasAnyFindings
failScaPrIfResultHasAnyFindings
getSastFindingCountPerSeverity
getScaFindingsCountsPerSeverity
isAllowedSast
isAllowedSca
isAnySastThresholdExceeded
isAnyScaThresholdsExceeded
This is not good code design. The SAST and SCA functionalities should be separated.
breakBuildResult = true; | ||
} | ||
} else if(flowProperties.isBreakBuild() && resultsService.filteredIssuesPresent(results)){ | ||
log.info("Fail build on issues presented after executing filters"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe something like: "Build failed, because some issues were found"?
// assuming SCA results only | ||
return false; | ||
} | ||
|
||
Map<String, Integer> flow = (Map<String, Integer>) results.getAdditionalDetails().get(Constants.SUMMARY_KEY); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 'flow' variable name is unclear. It should be called something like 'findingCountPerSeverity'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed
@@ -335,6 +335,11 @@ private boolean requiresCxCustomFields(List<Field> fields) { | |||
} | |||
|
|||
public boolean filteredIssuesPresent(ScanResults results) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we only count SAST issues here, then the method should be called filteredSastIssuesPresent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed
// assuming SCA results only | ||
return false; | ||
} | ||
|
||
Map<String, Integer> flow = (Map<String, Integer>) results.getAdditionalDetails().get(Constants.SUMMARY_KEY); | ||
return flow == null || !flow.isEmpty(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the case when the summary has 0 as a value? e.g. {high:0, medium:0}
In this case filteredIssuesPresent should return false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in this case !flow.isEmpty() will return false (not present)
testContext.setCxFlowExecutionException(exception); | ||
} | ||
|
||
@And("cxflow should exit with {}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sould be {int} and not {}
Kudos, SonarCloud Quality Gate passed! 0 Bugs 0.0% Coverage The version of Java (1.8.0_265) you have used to run this analysis is deprecated and we will stop accepting it from October 2020. Please update to at least Java 11. |
Map<String, Integer> flow = (Map<String, Integer>) results.getAdditionalDetails().get(Constants.SUMMARY_KEY); | ||
return flow == null || !flow.isEmpty(); | ||
Map<String, Integer> findingCountPerSeverity = (Map<String, Integer>) results.getAdditionalDetails().get(Constants.SUMMARY_KEY); | ||
return findingCountPerSeverity == null || !findingCountPerSeverity.isEmpty(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If e.g. findingCountPerSeverity has a single 'HIGH' key with the value 0, then findingCountPerSeverity.isEmpty() will return false. The result of filteredSastIssuesPresent() will then be 'true'. However, in fact no issues are present.
By submitting a PR to this repository, you agree to the terms within the Checkmarx Code of Conduct. Please see the contributing guidelines for how to create and submit a high-quality PR for this repo.
Description
Purpose of this PR is to add threshold logic for cxflow cli flows
Now user can configure thresholds to control break-build operations
References
Documentation guide: https://github.com/checkmarx-ltd/cx-flow/wiki/Thresholds-and-policies
Testing
Add automation voerage to cover cli flows in the following feature files:
Checklist