-
Notifications
You must be signed in to change notification settings - Fork 184
Commit
Yocto project support CVE security vulnerabilities using cve-check in the specific image or target you are building, add the following setting to your configuration: INHERIT += "cve-check" status of each CVE: Patched, Unpatched or Ignored The scanner look only for Unpatched package and calculate the severity using the score_v2 or score_v3 Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package edu.hm.hafner.analysis.parser; | ||
|
||
import org.json.JSONArray; | ||
import org.json.JSONObject; | ||
|
||
import edu.hm.hafner.analysis.Issue; | ||
import edu.hm.hafner.analysis.IssueBuilder; | ||
import edu.hm.hafner.analysis.Report; | ||
import edu.hm.hafner.analysis.Severity; | ||
|
||
import static j2html.TagCreator.*; | ||
|
||
/** | ||
* Parser for Yocto Scanner CLI (scannercli) tool. | ||
* | ||
* @author Juri Duval | ||
*/ | ||
public class YoctoScannerParser extends JsonIssueParser { | ||
private static final String VALUE_NOT_SET = "-"; | ||
private static final long serialVersionUID = 1L; | ||
private static final Double INVALID_SCORE = -1.0; | ||
|
||
@Override | ||
protected void parseJsonObject(final Report report, final JSONObject jsonReport, final IssueBuilder issueBuilder) { | ||
JSONArray packages = jsonReport.optJSONArray("package"); | ||
if (packages != null) { | ||
parseResources(report, packages, issueBuilder); | ||
} | ||
} | ||
|
||
private void parseResources(final Report report, final JSONArray packages, final IssueBuilder issueBuilder) { | ||
for (int i = 0; i < packages.length(); i++) { | ||
final Object item = packages.get(i); | ||
if (item instanceof JSONObject) { | ||
final JSONObject resourceWrapper = (JSONObject) item; | ||
if (!resourceWrapper.isNull("issue")) { | ||
parseVulnerabilities(report, issueBuilder, resourceWrapper); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void parseVulnerabilities(final Report report, final IssueBuilder issueBuilder, | ||
final JSONObject resourceWrapper) { | ||
final JSONArray vulnerabilities = resourceWrapper.getJSONArray("issue"); | ||
for (Object vulnerability : vulnerabilities) { | ||
if (vulnerability instanceof JSONObject) { | ||
final JSONObject obj = (JSONObject) vulnerability; | ||
final String status = obj.getString("status"); | ||
if (status.equals("Unpatched")) { | ||
Check warning on line 50 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / Java Compilercheckstyle:check
Check warning on line 50 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / CheckStyleEqualsAvoidNullCheck
Raw output
|
||
report.add(convertToIssue(resourceWrapper, obj, issueBuilder)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private Issue convertToIssue(final JSONObject resource, final JSONObject vulnerability, | ||
final IssueBuilder issueBuilder) { | ||
final String packageName = resource.getString("name"); | ||
return issueBuilder | ||
.setPackageName(packageName) | ||
.setSeverity(mapSeverity(vulnerability)) | ||
.setMessage(vulnerability.optString("id", "UNKNOWN")) | ||
.setDescription(formatDescription(packageName, resource, vulnerability)) | ||
.buildAndClean(); | ||
} | ||
|
||
private Severity mapSeverity(final JSONObject vulnerability) { | ||
Check warning on line 68 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / PMDCyclomaticComplexity
Raw output
Check warning on line 68 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / PMDNPathComplexity
Raw output
|
||
Double score_v2 = INVALID_SCORE; | ||
Check warning on line 69 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / Java Compilercheckstyle:check
Check warning on line 69 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / CheckStyleLocalVariableNameCheck
Raw output
|
||
Double score_v3 = INVALID_SCORE; | ||
Check warning on line 70 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / Java Compilercheckstyle:check
Check warning on line 70 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / CheckStyleLocalVariableNameCheck
Raw output
|
||
Double score = INVALID_SCORE; | ||
|
||
if (vulnerability.has("scorev2")) { | ||
score_v2 = vulnerability.getDouble("scorev2"); | ||
} | ||
|
||
if (vulnerability.has("scorev3")) { | ||
score_v3 = vulnerability.getDouble("scorev3"); | ||
} | ||
|
||
if (score_v3 == 0.0) { | ||
Check warning on line 81 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / PMDAvoidLiteralsInIfCondition
Raw output
|
||
if (score_v2 != 0.0) { | ||
Check warning on line 82 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / Code CoveragePartially covered line
Check warning on line 82 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / PMDAvoidLiteralsInIfCondition
Raw output
|
||
score = score_v2; | ||
} | ||
} else { | ||
Check warning on line 85 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / Java Compilercheckstyle:check
Check warning on line 85 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / CheckStyleRightCurlyCheck
Raw output
|
||
score = score_v3; | ||
} | ||
|
||
if (score < 0) { | ||
return Severity.ERROR; | ||
} | ||
|
||
if (score == 0.0) { | ||
Check warning on line 93 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / Code CoveragePartially covered line
Check warning on line 93 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / PMDAvoidLiteralsInIfCondition
Raw output
|
||
return Severity.WARNING_LOW; | ||
} | ||
|
||
if (score < 4.0) { | ||
Check warning on line 97 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / PMDAvoidLiteralsInIfCondition
Raw output
|
||
return Severity.WARNING_LOW; | ||
} | ||
|
||
if (score >= 4.0 && score < 7.0) { | ||
return Severity.WARNING_NORMAL; | ||
} | ||
|
||
if (score >= 7 && score <= 10) | ||
Check warning on line 105 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / Code CoveragePartially covered line
Check warning on line 105 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / Java Compilercheckstyle:check
|
||
return Severity.WARNING_HIGH; | ||
Check warning on line 106 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / PMDControlStatementBraces
Raw output
|
||
|
||
return Severity.ERROR; | ||
} | ||
|
||
private String formatDescription(final String packageName, final JSONObject resource, final JSONObject vulnerability) { | ||
final String version = resource.optString("version", VALUE_NOT_SET); | ||
final String layer = resource.optString("layer", "UNKOWN"); | ||
final String vector = vulnerability.optString("vector", "UNKOWN"); | ||
final String link = vulnerability.optString("link", "UNKOWN"); | ||
final String description = vulnerability.optString("summary", ""); | ||
|
||
return join(div(b("Package: "), text(packageName)), | ||
div(b("Version: "), text(version)), | ||
div(b("Link: "), text(link)), | ||
div(b("Yocto Layer: "), text(layer)), | ||
div(b("Vector: "), text(vector)), | ||
p(text(description))).render(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package edu.hm.hafner.analysis.registry; | ||
|
||
import edu.hm.hafner.analysis.IssueParser; | ||
import edu.hm.hafner.analysis.parser.YoctoScannerParser; | ||
|
||
import static j2html.TagCreator.*; | ||
|
||
/** | ||
* A descriptor for Yocto Scanner. | ||
* | ||
* @author Juri Duval | ||
*/ | ||
class YoctoScannerDescriptor extends ParserDescriptor { | ||
private static final String ID = "Yocto cli"; | ||
private static final String NAME = "Yocto Scanner"; | ||
|
||
YoctoScannerDescriptor() { | ||
super(ID, NAME); | ||
} | ||
|
||
@Override | ||
public IssueParser createParser(final Option... options) { | ||
return new YoctoScannerParser(); | ||
} | ||
|
||
@Override | ||
public String getHelp() { | ||
return join(text("Use commandline"), | ||
code("bitbake <your product image>"), | ||
text(", add INHERIT += \"cve-check\" in your local.conf"), | ||
a("Yocto Scanner").withHref("https://docs.yoctoproject.org/dev/dev-manual/vulnerabilities.html"), | ||
text("for usage details.")).render(); | ||
} | ||
|
||
@Override | ||
public String getUrl() { | ||
return "https://docs.yoctoproject.org/dev/dev-manual/vulnerabilities.html"; | ||
} | ||
|
||
@Override | ||
public String getIconUrl() { | ||
return "https://www.yoctoproject.org/wp-content/uploads/sites/32/2023/09/YoctoProject_Logo_RGB_White_small.svg"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package edu.hm.hafner.analysis.parser; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import edu.hm.hafner.analysis.IssueParser; | ||
import edu.hm.hafner.analysis.ParsingException; | ||
import edu.hm.hafner.analysis.Report; | ||
import edu.hm.hafner.analysis.Severity; | ||
import edu.hm.hafner.analysis.assertions.SoftAssertions; | ||
import edu.hm.hafner.analysis.registry.AbstractParserTest; | ||
|
||
import static edu.hm.hafner.analysis.assertions.Assertions.*; | ||
|
||
/** | ||
* Tests the class {@link YoctoScannerParser}. | ||
*/ | ||
class YoctoScannerParserTest extends AbstractParserTest { | ||
Check warning on line 17 in src/test/java/edu/hm/hafner/analysis/parser/YoctoScannerParserTest.java ci.jenkins.io / Java Compilercheckstyle:check
Check warning on line 17 in src/test/java/edu/hm/hafner/analysis/parser/YoctoScannerParserTest.java ci.jenkins.io / CheckStyleRegexpMultilineCheck
Raw output
|
||
|
||
YoctoScannerParserTest() { | ||
super("yocto_scanner_result.json"); | ||
} | ||
|
||
@Override | ||
protected void assertThatIssuesArePresent(final Report report, final SoftAssertions softly) { | ||
softly.assertThat(report).hasSize(25); | ||
|
||
softly.assertThat(report.get(0)) | ||
.hasSeverity(Severity.WARNING_LOW) | ||
.hasPackageName("acl") | ||
.hasMessage("CVE-2009-4411"); | ||
softly.assertThat(report.get(3)) | ||
.hasSeverity(Severity.WARNING_NORMAL) | ||
.hasPackageName("automake-native") | ||
.hasMessage("CVE-2012-3386"); | ||
} | ||
|
||
@Test | ||
void shouldHandleEmptyResultsJenkins67296() { | ||
Report report = parse("issue67296.json"); | ||
|
||
assertThat(report).isEmpty(); | ||
} | ||
|
||
@Test | ||
void brokenInput() { | ||
assertThatThrownBy(() -> parse("eclipse.txt")).isInstanceOf(ParsingException.class); | ||
} | ||
|
||
@Override | ||
protected IssueParser createParser() { | ||
return new YoctoScannerParser(); | ||
} | ||
} |