-
-
Notifications
You must be signed in to change notification settings - Fork 758
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Support sarif as a report type - #3045 * Integrate sarif feedback from @lgolding * Test the whole sarif report instead of some json paths * Provide only the short description; we do not have access to the long one programmatically * Use the plain rule id as sarif rule name; the rule set id is encoded in the sarif rule id * Remove need for casting by using a when expression
- Loading branch information
1 parent
5c03562
commit 415ca77
Showing
10 changed files
with
321 additions
and
0 deletions.
There are no files selected for viewing
18 changes: 18 additions & 0 deletions
18
detekt-api/src/testFixtures/kotlin/io/gitlab/arturbosch/detekt/test/EmptySetupContext.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package io.gitlab.arturbosch.detekt.test | ||
|
||
import io.gitlab.arturbosch.detekt.api.Config | ||
import io.gitlab.arturbosch.detekt.api.SetupContext | ||
import io.gitlab.arturbosch.detekt.api.UnstableApi | ||
import java.net.URI | ||
|
||
@OptIn(UnstableApi::class) | ||
class EmptySetupContext : SetupContext { | ||
override val configUris: Collection<URI> = emptyList() | ||
override val config: Config = Config.empty | ||
override val outputChannel: Appendable = StringBuilder() | ||
override val errorChannel: Appendable = StringBuilder() | ||
override val properties: MutableMap<String, Any?> = HashMap() | ||
override fun register(key: String, value: Any) { | ||
properties[key] = value | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
repositories { | ||
mavenLocal() | ||
} | ||
|
||
dependencies { | ||
compileOnly(project(":detekt-api")) | ||
compileOnly(project(":detekt-tooling")) | ||
implementation("io.github.detekt.sarif4j:sarif4j:1.0.0") | ||
testImplementation(project(":detekt-tooling")) | ||
testImplementation(project(":detekt-test-utils")) | ||
testImplementation(testFixtures(project(":detekt-api"))) | ||
} | ||
|
||
tasks.withType<Jar>().configureEach { | ||
dependsOn(configurations.runtimeClasspath) | ||
from({ | ||
configurations.runtimeClasspath.get() | ||
.asSequence() | ||
.filterNot { "org.jetbrains" in it.toString() } | ||
.filterNot { "org.intellij" in it.toString() } | ||
.map { if (it.isDirectory) it else zipTree(it) } | ||
.toList() | ||
}) | ||
} |
43 changes: 43 additions & 0 deletions
43
detekt-report-sarif/src/main/kotlin/io/github/detekt/report/sarif/RuleDescriptors.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package io.github.detekt.report.sarif | ||
|
||
import io.github.detekt.sarif4j.MultiformatMessageString | ||
import io.github.detekt.sarif4j.ReportingDescriptor | ||
import io.gitlab.arturbosch.detekt.api.Config | ||
import io.gitlab.arturbosch.detekt.api.MultiRule | ||
import io.gitlab.arturbosch.detekt.api.Rule | ||
import io.gitlab.arturbosch.detekt.api.RuleSetId | ||
import io.gitlab.arturbosch.detekt.api.RuleSetProvider | ||
import java.net.URI | ||
import java.util.ServiceLoader | ||
|
||
fun ruleDescriptors(config: Config): HashMap<String, ReportingDescriptor> { | ||
val sets = ServiceLoader.load(RuleSetProvider::class.java) | ||
.map { it.instance(config.subConfig(it.ruleSetId)) } | ||
val descriptors = HashMap<String, ReportingDescriptor>() | ||
for (ruleSet in sets) { | ||
for (rule in ruleSet.rules) { | ||
when (rule) { | ||
is MultiRule -> { | ||
descriptors.putAll(rule.toDescriptors(ruleSet.id).associateBy { it.name }) | ||
} | ||
is Rule -> { | ||
val descriptor = rule.toDescriptor(ruleSet.id) | ||
descriptors[descriptor.name] = descriptor | ||
} | ||
} | ||
} | ||
} | ||
return descriptors | ||
} | ||
|
||
fun descriptor(init: ReportingDescriptor.() -> Unit) = ReportingDescriptor().apply(init) | ||
|
||
fun MultiRule.toDescriptors(ruleSetId: RuleSetId): List<ReportingDescriptor> = | ||
this.rules.map { it.toDescriptor(ruleSetId) } | ||
|
||
fun Rule.toDescriptor(ruleSetId: RuleSetId): ReportingDescriptor = descriptor { | ||
id = "detekt.$ruleSetId.$ruleId" | ||
name = ruleId | ||
shortDescription = MultiformatMessageString().apply { text = issue.description } | ||
helpUri = URI.create("https://detekt.github.io/detekt/${ruleSetId.toLowerCase()}.html#${ruleId.toLowerCase()}") | ||
} |
47 changes: 47 additions & 0 deletions
47
detekt-report-sarif/src/main/kotlin/io/github/detekt/report/sarif/SarifDsl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package io.github.detekt.report.sarif | ||
|
||
import io.github.detekt.sarif4j.Run | ||
import io.github.detekt.sarif4j.SarifSchema210 | ||
import io.github.detekt.sarif4j.Tool | ||
import io.github.detekt.sarif4j.ToolComponent | ||
import io.github.detekt.tooling.api.VersionProvider | ||
import io.gitlab.arturbosch.detekt.api.Config | ||
import java.net.URI | ||
|
||
const val SCHEMA_URL = "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json" | ||
|
||
fun sarif(init: SarifSchema210.() -> Unit): SarifSchema210 = SarifSchema210() | ||
.`with$schema`(URI.create(SCHEMA_URL)) | ||
.withVersion(SarifSchema210.Version._2_1_0) | ||
.withRuns(ArrayList()) | ||
.apply(init) | ||
|
||
typealias SarifIssue = io.github.detekt.sarif4j.Result | ||
|
||
fun result(init: SarifIssue.() -> Unit): SarifIssue = SarifIssue().withLocations(ArrayList()).apply(init) | ||
|
||
fun tool(init: Tool.() -> Unit): Tool = Tool().apply(init) | ||
|
||
fun component(init: ToolComponent.() -> Unit): ToolComponent = ToolComponent().apply(init) | ||
|
||
fun SarifSchema210.withDetektRun(config: Config, init: Run.() -> Unit) { | ||
runs.add( | ||
Run() | ||
.withResults(ArrayList()) | ||
.withTool(tool { | ||
driver = component { | ||
guid = "022ca8c2-f6a2-4c95-b107-bb72c43263f3" | ||
name = "detekt" | ||
fullName = name | ||
organization = name | ||
language = "en" | ||
version = VersionProvider.load().current() | ||
semanticVersion = version | ||
downloadUri = URI.create("https://github.com/detekt/detekt/releases/download/v$version/detekt") | ||
informationUri = URI.create("https://detekt.github.io/detekt") | ||
rules = ruleDescriptors(config).values.toSet() | ||
} | ||
}) | ||
.apply(init) | ||
) | ||
} |
64 changes: 64 additions & 0 deletions
64
detekt-report-sarif/src/main/kotlin/io/github/detekt/report/sarif/SarifOutputReport.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package io.github.detekt.report.sarif | ||
|
||
import io.github.detekt.sarif4j.ArtifactLocation | ||
import io.github.detekt.sarif4j.JacksonSarifWriter | ||
import io.github.detekt.sarif4j.Location | ||
import io.github.detekt.sarif4j.Message | ||
import io.github.detekt.sarif4j.PhysicalLocation | ||
import io.github.detekt.sarif4j.Region | ||
import io.github.detekt.sarif4j.Result | ||
import io.gitlab.arturbosch.detekt.api.Config | ||
import io.gitlab.arturbosch.detekt.api.Detektion | ||
import io.gitlab.arturbosch.detekt.api.Finding | ||
import io.gitlab.arturbosch.detekt.api.OutputReport | ||
import io.gitlab.arturbosch.detekt.api.RuleSetId | ||
import io.gitlab.arturbosch.detekt.api.SetupContext | ||
import io.gitlab.arturbosch.detekt.api.SingleAssign | ||
import io.gitlab.arturbosch.detekt.api.UnstableApi | ||
import java.net.URI | ||
|
||
class SarifOutputReport : OutputReport() { | ||
|
||
override val ending: String = "sarif" | ||
override val id: String = "sarif" | ||
override val name = "SARIF: a standard format for the output of static analysis tools" | ||
|
||
private var config: Config by SingleAssign() | ||
|
||
@OptIn(UnstableApi::class) | ||
override fun init(context: SetupContext) { | ||
this.config = context.config | ||
} | ||
|
||
override fun render(detektion: Detektion): String { | ||
val report = sarif { | ||
withDetektRun(config) { | ||
for ((ruleSetId, issues) in detektion.findings) { | ||
for (issue in issues) { | ||
results.add(issue.toIssue(ruleSetId)) | ||
} | ||
} | ||
} | ||
} | ||
return JacksonSarifWriter().toJson(report) | ||
} | ||
} | ||
|
||
fun Finding.toIssue(ruleSetId: RuleSetId): SarifIssue = result { | ||
ruleId = "detekt.$ruleSetId.$id" | ||
level = Result.Level.WARNING | ||
for (location in listOf(location) + references.map { it.location }) { | ||
locations.add(Location().apply { | ||
physicalLocation = PhysicalLocation().apply { | ||
region = Region().apply { | ||
startLine = location.source.line | ||
startColumn = location.source.column | ||
} | ||
artifactLocation = ArtifactLocation().apply { | ||
uri = URI.create(location.file).toString() | ||
} | ||
} | ||
}) | ||
} | ||
message = Message().apply { text = messageOrDescription() } | ||
} |
1 change: 1 addition & 0 deletions
1
...t-sarif/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.OutputReport
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
io.github.detekt.report.sarif.SarifOutputReport |
41 changes: 41 additions & 0 deletions
41
detekt-report-sarif/src/test/kotlin/io/github/detekt/report/sarif/SarifOutputReportSpec.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package io.github.detekt.report.sarif | ||
|
||
import io.github.detekt.test.utils.readResourceContent | ||
import io.github.detekt.tooling.api.VersionProvider | ||
import io.gitlab.arturbosch.detekt.test.EmptySetupContext | ||
import io.gitlab.arturbosch.detekt.test.TestDetektion | ||
import io.gitlab.arturbosch.detekt.test.createFinding | ||
import org.assertj.core.api.Assertions.assertThat | ||
import org.spekframework.spek2.Spek | ||
import org.spekframework.spek2.style.specification.describe | ||
|
||
class SarifOutputReportSpec : Spek({ | ||
|
||
describe("sarif output report") { | ||
|
||
val expectedReport by memoized { | ||
readResourceContent("expected.sarif.json").stripWhitespace() | ||
} | ||
|
||
it("renders multiple issues") { | ||
val result = TestDetektion( | ||
createFinding(ruleName = "TestSmellA"), | ||
createFinding(ruleName = "TestSmellB"), | ||
createFinding(ruleName = "TestSmellC") | ||
) | ||
|
||
val report = SarifOutputReport().apply { init(EmptySetupContext()) } | ||
.render(result) | ||
.stripWhitespace() | ||
|
||
assertThat(report).isEqualTo(expectedReport) | ||
} | ||
} | ||
}) | ||
|
||
internal fun String.stripWhitespace() = replace(Regex("\\s"), "") | ||
|
||
internal class TestVersionProvider : VersionProvider { | ||
|
||
override fun current(): String = "1.0.0" | ||
} |
1 change: 1 addition & 0 deletions
1
...t-sarif/src/test/resources/META-INF/services/io.github.detekt.tooling.api.VersionProvider
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
io.github.detekt.report.sarif.TestVersionProvider |
81 changes: 81 additions & 0 deletions
81
detekt-report-sarif/src/test/resources/expected.sarif.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
{ | ||
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", | ||
"version": "2.1.0", | ||
"runs": [ | ||
{ | ||
"tool": { | ||
"driver": { | ||
"guid": "022ca8c2-f6a2-4c95-b107-bb72c43263f3", | ||
"name": "detekt", | ||
"organization": "detekt", | ||
"fullName": "detekt", | ||
"version": "1.0.0", | ||
"semanticVersion": "1.0.0", | ||
"downloadUri": "https://github.com/detekt/detekt/releases/download/v1.0.0/detekt", | ||
"informationUri": "https://detekt.github.io/detekt", | ||
"rules": [], | ||
"language": "en" | ||
} | ||
}, | ||
"results": [ | ||
{ | ||
"ruleId": "detekt.TestSmellA.TestSmellA", | ||
"message": { | ||
"text": "TestMessage" | ||
}, | ||
"locations": [ | ||
{ | ||
"physicalLocation": { | ||
"artifactLocation": { | ||
"uri": "TestFile.kt" | ||
}, | ||
"region": { | ||
"startLine": 1, | ||
"startColumn": 1 | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
"ruleId": "detekt.TestSmellB.TestSmellB", | ||
"message": { | ||
"text": "TestMessage" | ||
}, | ||
"locations": [ | ||
{ | ||
"physicalLocation": { | ||
"artifactLocation": { | ||
"uri": "TestFile.kt" | ||
}, | ||
"region": { | ||
"startLine": 1, | ||
"startColumn": 1 | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
"ruleId": "detekt.TestSmellC.TestSmellC", | ||
"message": { | ||
"text": "TestMessage" | ||
}, | ||
"locations": [ | ||
{ | ||
"physicalLocation": { | ||
"artifactLocation": { | ||
"uri": "TestFile.kt" | ||
}, | ||
"region": { | ||
"startLine": 1, | ||
"startColumn": 1 | ||
} | ||
} | ||
} | ||
] | ||
} | ||
] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters