Skip to content

Commit

Permalink
feat: coverity parser (refs #186)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasbjerre committed Mar 24, 2024
1 parent 18593cc commit 9541b71
Show file tree
Hide file tree
Showing 9 changed files with 385 additions and 13 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ A number of **parsers** have been implemented. Some **parsers** can parse output
| [_CloudFormation Linter_](https://github.com/aws-cloudformation/cfn-lint) | `JUNIT` | `cfn-lint . -f junit --output-file report-junit.xml`
| [_CodeClimate_](https://codeclimate.com/) | `CODECLIMATE` |
| [_CodeNarc_](http://codenarc.sourceforge.net/) | `CODENARC` |
| [_Coverity_](https://scan.coverity.com/) | `COVERITY` |
| [_Dart_](https://dart.dev/) | `MACHINE` | With `dart analyze --format=machine`
| [_Dependency Check_](https://jeremylong.github.io/DependencyCheck/) | `SARIF` | Using `--format SARIF`
| [_Detekt_](https://github.com/arturbosch/detekt) | `CHECKSTYLE` | With `--output-format xml`.
Expand Down Expand Up @@ -89,7 +90,7 @@ A number of **parsers** have been implemented. Some **parsers** can parse output
| [_YAMLLint_](https://yamllint.readthedocs.io/en/stable/index.html) | `YAMLLINT` | With `-f parsable`
| [_ZPTLint_](https://pypi.python.org/pypi/zptlint) | `ZPTLINT` |

51 parsers and 78 reporters.
52 parsers and 79 reporters.

Missing a format? Open an issue [here](https://github.com/tomasbjerre/violations-lib/issues)!

Expand Down
37 changes: 26 additions & 11 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,36 @@ project.ext.buildConfig = [
updateReadme: true
],
staticCodeAnalysis: [
maxViolations: 6
maxViolations: 5
],
]
apply from: project.buildscript.classLoader.getResource('main.gradle').toURI()

apply plugin: 'jsonschema2pojo'

jsonSchema2Pojo {
source = files("${sourceSets.main.output.resourcesDir}/json")
targetDirectory = file("src/gen/java")
targetPackage = 'se.bjurr.violations.lib.model.generated.sarif'
generateBuilders = true
annotationStyle = 'none'
includeGeneratedAnnotation = false
removeOldOutput = true
[
[
removeOldOutput: true,
from: "${rootDir}/src/main/resources/json/sarif-schema.json",
to: "se.bjurr.violations.lib.model.generated.sarif"
],
[
removeOldOutput: false,
from: "${rootDir}/src/main/resources/json/coverity-schema.json",
to: "se.bjurr.violations.lib.model.generated.coverity"
]
].each { codeGen ->
logger.lifecycle("Generating ${codeGen.from} to ${codeGen.to}")

jsonSchema2Pojo {
source = files(codeGen.from)
targetDirectory = file("src/gen/java")
targetPackage = codeGen.to
generateBuilders = true
annotationStyle = 'none'
includeGeneratedAnnotation = false
removeOldOutput = codeGen.removeOldOutput
}
}

spotlessJava.dependsOn generateJsonSchema2Pojo
Expand All @@ -48,6 +63,6 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.assertj:assertj-core:3.25.3'
testImplementation 'uk.co.jemos.podam:podam:8.0.1.RELEASE'
testImplementation 'com.approvaltests:approvaltests:22.4.0'
testImplementation 'com.networknt:json-schema-validator:1.3.3'
testImplementation 'com.approvaltests:approvaltests:23.0.0'
testImplementation 'com.networknt:json-schema-validator:1.4.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

public class AnsibleLaterParser implements ViolationsParser {

public class AnsibleLaterEntry {
public static class AnsibleLaterEntry {
public String asctime;
public String levelname;
public String message;
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/se/bjurr/violations/lib/parsers/CoverityParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package se.bjurr.violations.lib.parsers;

import static se.bjurr.violations.lib.model.SEVERITY.ERROR;
import static se.bjurr.violations.lib.model.SEVERITY.WARN;
import static se.bjurr.violations.lib.model.Violation.violationBuilder;

import com.google.gson.Gson;
import java.util.Set;
import java.util.TreeSet;
import se.bjurr.violations.lib.ViolationsLogger;
import se.bjurr.violations.lib.model.SEVERITY;
import se.bjurr.violations.lib.model.Violation;
import se.bjurr.violations.lib.model.generated.coverity.CoveritySchema;
import se.bjurr.violations.lib.model.generated.coverity.Issue;
import se.bjurr.violations.lib.reports.Parser;

public class CoverityParser implements ViolationsParser {

@Override
public Set<Violation> parseReportOutput(
final String string, final ViolationsLogger violationsLogger) throws Exception {
final CoveritySchema coverityReport = new Gson().fromJson(string, CoveritySchema.class);

final Set<Violation> violations = new TreeSet<>();
for (final Issue issue : coverityReport.getIssues()) {

violations.add(
violationBuilder() //
.setFile(issue.getMainEventFilePathname()) //
.setMessage(
issue.getCheckerProperties().getSubcategoryLocalEffect()
+ "\n"
+ issue.getCheckerProperties().getSubcategoryLocalEffect()) //
.setParser(Parser.COVERITY) //
.setCategory(issue.getCheckerProperties().getCategory())
.setRule(issue.getType() + "/" + issue.getSubtype()) //
.setSeverity(this.toSeverity(issue.getCheckerProperties().getImpact())) //
.setStartLine(issue.getMainEventLineNumber()) //
.build());
}
return violations;
}

private SEVERITY toSeverity(final String from) {
if (from.equalsIgnoreCase("Medium")) {
return WARN;
}
return ERROR;
}
}
2 changes: 2 additions & 0 deletions src/main/java/se/bjurr/violations/lib/reports/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import se.bjurr.violations.lib.parsers.CheckStyleParser;
import se.bjurr.violations.lib.parsers.CodeClimateParser;
import se.bjurr.violations.lib.parsers.CodeNarcParser;
import se.bjurr.violations.lib.parsers.CoverityParser;
import se.bjurr.violations.lib.parsers.CppLintParser;
import se.bjurr.violations.lib.parsers.DocFXParser;
import se.bjurr.violations.lib.parsers.FindbugsParser;
Expand Down Expand Up @@ -64,6 +65,7 @@ public enum Parser {
CHECKSTYLE(new CheckStyleParser()), //
CODENARC(new CodeNarcParser()), //
CLANG(new CLangParser()), //
COVERITY(new CoverityParser()), //
CPD(new CPDParser()), //
CPPCHECK(new CPPCheckParser()), //
CPPLINT(new CppLintParser()), //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public enum Reporter {
"https://github.com/PyCQA/bandit",
"With `bandit -r examples/ -f custom -o bandit.out --msg-template \"{abspath}:{line}: {severity}: {test_id}: {msg}\"`"),
CLANG("CLang", Parser.CLANG, "https://clang-analyzer.llvm.org/", ""),
COVERITY("Coverity", Parser.COVERITY, "https://scan.coverity.com/", ""),
CFN(
"CloudFormation Linter",
Parser.JUNIT,
Expand Down
196 changes: 196 additions & 0 deletions src/main/resources/json/coverity-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"type": {
"type": "string"
},
"formatVersion": {
"type": "integer"
},
"suppressedIssueCount": {
"type": "integer"
},
"issues": {
"type": "array",
"items": {
"$ref": "#/definitions/issue"
}
},
"desktopAnalysisSettings": {
"type": "null"
},
"error": {
"type": "null"
},
"warnings": {
"type": "array",
"items": {}
}
},
"definitions": {
"issue": {
"type": "object",
"properties": {
"mergeKey": {
"type": "string"
},
"occurrenceCountForMK": {
"type": "integer"
},
"occurrenceNumberInMK": {
"type": "integer"
},
"referenceOccurrenceCountForMK": {
"type": "null"
},
"checkerName": {
"type": "string"
},
"subcategory": {
"type": "string"
},
"type": {
"type": "string"
},
"subtype": {
"type": "string"
},
"code-language": {
"type": "string"
},
"extra": {
"type": "string"
},
"domain": {
"type": "string"
},
"language": {
"type": "string"
},
"mainEventFilePathname": {
"type": "string"
},
"strippedMainEventFilePathname": {
"type": "string"
},
"mainEventLineNumber": {
"type": "integer"
},
"properties": {
"type": "object"
},
"functionDisplayName": {
"type": "string"
},
"functionMangledName": {
"type": "string"
},
"localStatus": {
"type": "null"
},
"ordered": {
"type": "boolean"
},
"stateOnServer": {
"type": "null"
},
"events": {
"type": "array",
"items": {
"$ref": "#/definitions/event"
}
},
"checkerProperties": {
"$ref": "#/definitions/checkerProperty"
}
}
},
"event": {
"type": "object",
"properties": {
"covLStrEventDescription": {
"type": "string"
},
"eventDescription": {
"type": "string"
},
"eventNumber": {
"type": "integer"
},
"eventTreePosition": {
"type": "string"
},
"eventSet": {
"type": "integer"
},
"eventTag": {
"type": "string"
},
"filePathname": {
"type": "string"
},
"strippedFilePathname": {
"type": "string"
},
"lineNumber": {
"type": "integer"
},
"main": {
"type": "boolean"
},
"moreInformationId": {
"type": "null"
},
"remediation": {
"type": "boolean"
},
"events": {
"type": "null"
}
}
},
"checkerProperty": {
"type": "object",
"properties": {
"category": {
"type": "string"
},
"categoryDescription": {
"type": "string"
},
"cweCategory": {
"type": "string"
},
"issueKinds": {
"type": "array",
"items": {
"$ref": "#/definitions/issueKind"
}
},
"eventSetCaptions": {
"type": "array",
"items": {}
},
"impact": {
"type": "string"
},
"impactDescription": {
"type": "string"
},
"subcategoryLocalEffect": {
"type": "string"
},
"subcategoryShortDescription": {
"type": "string"
},
"subcategoryLongDescription": {
"type": "string"
}
}
},
"issueKind": {
"type": "string"
}
}
}
45 changes: 45 additions & 0 deletions src/test/java/se/bjurr/violations/lib/CoverityTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package se.bjurr.violations.lib;

import static org.assertj.core.api.Assertions.assertThat;
import static se.bjurr.violations.lib.TestUtils.getRootFolder;
import static se.bjurr.violations.lib.ViolationsApi.violationsApi;
import static se.bjurr.violations.lib.model.SEVERITY.WARN;

import java.util.ArrayList;
import java.util.Set;
import org.junit.Test;
import se.bjurr.violations.lib.model.Violation;
import se.bjurr.violations.lib.reports.Parser;

public class CoverityTest {

@Test
public void testThatViolationsCanBeParsed() {
final String rootFolder = getRootFolder();

final Set<Violation> actual =
violationsApi() //
.withPattern(".*/coverity/example1\\.json$") //
.inFolder(rootFolder) //
.findAll(Parser.COVERITY) //
.violations();

assertThat(actual) //
.hasSize(1);

final Violation violation0 = new ArrayList<>(actual).get(0);
assertThat(violation0.getMessage()) //
.isEqualTo(
"The expression's value is always zero; construct may indicate an inadvertent logic error.\nThe expression's value is always zero; construct may indicate an inadvertent logic error.");
assertThat(violation0.getFile()) //
.isEqualTo("C:/Workspace/workspace/Build_jenkins_development/somefile.cs");
assertThat(violation0.getSeverity()) //
.isEqualTo(WARN);
assertThat(violation0.getCategory()) //
.isEqualTo("Integer handling issues");
assertThat(violation0.getRule()) //
.isEqualTo("constant_expression_result/bit_and_with_zero");
assertThat(violation0.getStartLine()) //
.isEqualTo(79);
}
}
Loading

0 comments on commit 9541b71

Please sign in to comment.