Skip to content
Snippets Groups Projects
Verified Commit 836971dc authored by Jan-Niclas Strüwer's avatar Jan-Niclas Strüwer
Browse files

updated db structure to enable a query to get the latest results for all tools...

updated db structure to enable a query to get the latest results for all tools for a certain repository
parent f5cc847f
No related branches found
No related tags found
No related merge requests found
Showing
with 163 additions and 51 deletions
...@@ -14,7 +14,11 @@ class Repository { ...@@ -14,7 +14,11 @@ class Repository {
var id: UUID? = null var id: UUID? = null
@OrderBy("time_stamp DESC") @OrderBy("time_stamp DESC")
@OneToMany(mappedBy = "repository", cascade = [CascadeType.ALL], orphanRemoval = true) @OneToMany(
mappedBy = "repository",
cascade = [CascadeType.MERGE, CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.DETACH],
orphanRemoval = true
)
var toolRuns: MutableList<ToolRun> = mutableListOf() var toolRuns: MutableList<ToolRun> = mutableListOf()
@Column(name = "name") @Column(name = "name")
......
...@@ -21,7 +21,6 @@ fun de.fraunhofer.iem.dataprovider.sarif.Rule.asDbObject(): Rule { ...@@ -21,7 +21,6 @@ fun de.fraunhofer.iem.dataprovider.sarif.Rule.asDbObject(): Rule {
fun de.fraunhofer.iem.dataprovider.sarif.Tool.asDbObject(): Tool { fun de.fraunhofer.iem.dataprovider.sarif.Tool.asDbObject(): Tool {
val tool = Tool() val tool = Tool()
tool.addRules(this.driver.rules.map { it.asDbObject() })
tool.fullName = this.driver.fullName tool.fullName = this.driver.fullName
tool.name = this.driver.name tool.name = this.driver.name
tool.version = this.driver.version tool.version = this.driver.version
...@@ -38,7 +37,7 @@ fun Location.asDbObject(): ResultLocation { ...@@ -38,7 +37,7 @@ fun Location.asDbObject(): ResultLocation {
return resultLocation return resultLocation
} }
fun Result.asDbObject(rules: Collection<Rule>): ToolResult { fun Result.asDbObject(): ToolResult {
val toolResult = ToolResult() val toolResult = ToolResult()
when (this.level.uppercase(Locale.getDefault())) { when (this.level.uppercase(Locale.getDefault())) {
...@@ -48,26 +47,19 @@ fun Result.asDbObject(rules: Collection<Rule>): ToolResult { ...@@ -48,26 +47,19 @@ fun Result.asDbObject(rules: Collection<Rule>): ToolResult {
else -> toolResult.level = Level.None else -> toolResult.level = Level.None
} }
rules
.filter { it.sarifRuleId == this.ruleId }
.forEach { it.addResultLocation(toolResult) }
toolResult.message = this.message.text toolResult.message = this.message.text
toolResult.addLocations(this.locations.map { it.asDbObject() }) toolResult.addLocations(this.locations.map { it.asDbObject() })
return toolResult return toolResult
} }
fun Sarif.asDbObject(): List<ToolRun> { fun Run.asDbObject(): ToolRun {
return this.runs.map { run -> val tr = ToolRun()
val tr = ToolRun() tr.timeStamp = Timestamp.from(Instant.now())
tr.tool = run.tool.asDbObject() return tr
tr.addToolResults(run.results.map { it.asDbObject(tr.tool!!.rules) })
tr.timeStamp = Timestamp.from(Instant.now())
tr
}
} }
fun getSarifFromFilePath(resultPath: Path): Sarif { fun getSarifFromFilePath(resultPath: Path): Sarif {
val resFile = resultPath.toFile() val resFile = resultPath.toFile()
if (resFile.exists()) { if (resFile.exists()) {
......
...@@ -5,7 +5,7 @@ import de.fraunhofer.iem.dataprovider.gitlab.RepositoryRepository ...@@ -5,7 +5,7 @@ import de.fraunhofer.iem.dataprovider.gitlab.RepositoryRepository
import de.fraunhofer.iem.dataprovider.logger.getLogger import de.fraunhofer.iem.dataprovider.logger.getLogger
import de.fraunhofer.iem.dataprovider.sarif.Sarif import de.fraunhofer.iem.dataprovider.sarif.Sarif
import de.fraunhofer.iem.dataprovider.taskManager.tasks.* import de.fraunhofer.iem.dataprovider.taskManager.tasks.*
import de.fraunhofer.iem.dataprovider.toolResult.ToolRunRepository import de.fraunhofer.iem.dataprovider.toolResult.ToolRunService
import jakarta.annotation.PreDestroy import jakarta.annotation.PreDestroy
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
...@@ -42,7 +42,7 @@ class DetektDone(override val taskId: UUID, val sarif: Sarif) : TaskDone() ...@@ -42,7 +42,7 @@ class DetektDone(override val taskId: UUID, val sarif: Sarif) : TaskDone()
class TaskManager( class TaskManager(
private val config: Config, private val config: Config,
private val repositoryRepository: RepositoryRepository, private val repositoryRepository: RepositoryRepository,
private val toolRunRepository: ToolRunRepository private val toolRunService: ToolRunService
) { ) {
// The used default dispatcher is ok for CPU-bound workloads. However, // The used default dispatcher is ok for CPU-bound workloads. However,
...@@ -128,8 +128,8 @@ class TaskManager( ...@@ -128,8 +128,8 @@ class TaskManager(
analysisResultsPath, analysisResultsPath,
::addEvent, ::addEvent,
event.repoId, event.repoId,
repositoryRepository, groupId,
toolRunRepository, groupId toolRunService
) )
val detektTask = DetektTask( val detektTask = DetektTask(
...@@ -137,9 +137,8 @@ class TaskManager( ...@@ -137,9 +137,8 @@ class TaskManager(
analysisResultsPath, analysisResultsPath,
::addEvent, ::addEvent,
event.repoId, event.repoId,
repositoryRepository, groupID = groupId,
toolRunRepository, toolRunService
groupID = groupId
) )
taskIds.add(odcTask.taskID) taskIds.add(odcTask.taskID)
......
package de.fraunhofer.iem.dataprovider.taskManager.tasks package de.fraunhofer.iem.dataprovider.taskManager.tasks
import de.fraunhofer.iem.dataprovider.gitlab.RepositoryRepository
import de.fraunhofer.iem.dataprovider.taskManager.Event import de.fraunhofer.iem.dataprovider.taskManager.Event
import de.fraunhofer.iem.dataprovider.toolResult.ToolRunRepository import de.fraunhofer.iem.dataprovider.toolResult.ToolRunService
import org.springframework.core.io.ClassPathResource import org.springframework.core.io.ClassPathResource
import org.springframework.core.io.Resource import org.springframework.core.io.Resource
import java.nio.file.Path import java.nio.file.Path
...@@ -15,9 +13,8 @@ class DetektTask( ...@@ -15,9 +13,8 @@ class DetektTask(
projectPath: String, outputPath: String, projectPath: String, outputPath: String,
override val responseChannel: suspend (task: Event) -> Unit, override val responseChannel: suspend (task: Event) -> Unit,
override val repoId: UUID, override val repoId: UUID,
override val repository: RepositoryRepository, override val groupID: UUID? = null,
override val toolRunRepository: ToolRunRepository, override val toolRunService: ToolRunService
override val groupID: UUID? = null
) : SarifTask() { ) : SarifTask() {
private val resource: Resource = ClassPathResource("scripts/detekt.sh") private val resource: Resource = ClassPathResource("scripts/detekt.sh")
......
package de.fraunhofer.iem.dataprovider.taskManager.tasks package de.fraunhofer.iem.dataprovider.taskManager.tasks
import de.fraunhofer.iem.dataprovider.gitlab.RepositoryRepository
import de.fraunhofer.iem.dataprovider.taskManager.Event import de.fraunhofer.iem.dataprovider.taskManager.Event
import de.fraunhofer.iem.dataprovider.toolResult.ToolRunRepository import de.fraunhofer.iem.dataprovider.toolResult.ToolRunService
import org.springframework.core.io.ClassPathResource import org.springframework.core.io.ClassPathResource
import org.springframework.core.io.Resource import org.springframework.core.io.Resource
import java.nio.file.Path import java.nio.file.Path
...@@ -15,9 +14,8 @@ class OdcTask( ...@@ -15,9 +14,8 @@ class OdcTask(
projectPath: String, outputPath: String, projectPath: String, outputPath: String,
override val responseChannel: suspend (task: Event) -> Unit, override val responseChannel: suspend (task: Event) -> Unit,
override val repoId: UUID, override val repoId: UUID,
override val repository: RepositoryRepository, override val groupID: UUID? = null,
override val toolRunRepository: ToolRunRepository, override val toolRunService: ToolRunService
override val groupID: UUID? = null
) : SarifTask() { ) : SarifTask() {
private val resource: Resource = ClassPathResource("scripts/odc.sh") private val resource: Resource = ClassPathResource("scripts/odc.sh")
......
package de.fraunhofer.iem.dataprovider.taskManager.tasks package de.fraunhofer.iem.dataprovider.taskManager.tasks
import de.fraunhofer.iem.dataprovider.gitlab.RepositoryRepository
import de.fraunhofer.iem.dataprovider.sarif.Sarif import de.fraunhofer.iem.dataprovider.sarif.Sarif
import de.fraunhofer.iem.dataprovider.sarif.asDbObject
import de.fraunhofer.iem.dataprovider.sarif.getSarifFromFilePath import de.fraunhofer.iem.dataprovider.sarif.getSarifFromFilePath
import de.fraunhofer.iem.dataprovider.taskManager.SarifProcessDone import de.fraunhofer.iem.dataprovider.taskManager.SarifProcessDone
import de.fraunhofer.iem.dataprovider.taskManager.SarifProcessGroupDone import de.fraunhofer.iem.dataprovider.taskManager.SarifProcessGroupDone
import de.fraunhofer.iem.dataprovider.toolResult.ToolRunRepository import de.fraunhofer.iem.dataprovider.toolResult.ToolRunService
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.IOException
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
...@@ -48,8 +47,7 @@ sealed class ProcessTask : Task() { ...@@ -48,8 +47,7 @@ sealed class ProcessTask : Task() {
sealed class SarifTask : ProcessTask() { sealed class SarifTask : ProcessTask() {
protected abstract val repoId: UUID protected abstract val repoId: UUID
protected abstract val repository: RepositoryRepository protected abstract val toolRunService: ToolRunService
protected abstract val toolRunRepository: ToolRunRepository
protected abstract val resultPath: Path protected abstract val resultPath: Path
...@@ -59,16 +57,13 @@ sealed class SarifTask : ProcessTask() { ...@@ -59,16 +57,13 @@ sealed class SarifTask : ProcessTask() {
// has findings it might return an exit code != 0 even tho the process finished correctly // has findings it might return an exit code != 0 even tho the process finished correctly
logger.info("Handle Process return in $javaClass") logger.info("Handle Process return in $javaClass")
val sarifResult = getSarifFromFilePath(resultPath) try {
val repo = repository.findById(repoId) val sarifResult = getSarifFromFilePath(resultPath)
val sarifDb = sarifResult.asDbObject() toolRunService.saveSarif(sarifResult, repoId)
val results = toolRunRepository.saveAll(sarifDb) sendResult(sarifResult)
} catch (e: IOException) {
repo.ifPresent { // TODO: send meaningful event and react on error
it.addToolResults(results)
repository.save(it)
} }
sendResult(sarifResult)
} }
override suspend fun sendResult(sarif: Sarif) { override suspend fun sendResult(sarif: Sarif) {
......
package de.fraunhofer.iem.dataprovider.toolResult
import org.springframework.data.jpa.repository.JpaRepository
import java.util.*
interface RuleRepository : JpaRepository<Rule, UUID> {
fun findByTool_Id(id: UUID): List<Rule>
}
\ No newline at end of file
package de.fraunhofer.iem.dataprovider.toolResult
import org.springframework.data.jpa.repository.JpaRepository
import java.util.*
interface ToolRepository : JpaRepository<Tool, UUID> {
fun findByFullNameIgnoreCaseAndNameIgnoreCaseAndVersionIgnoreCase(
fullName: String?,
name: String?,
version: String?
): Tool?
}
\ No newline at end of file
...@@ -24,8 +24,7 @@ class ToolRun { ...@@ -24,8 +24,7 @@ class ToolRun {
@Column(name = "id", nullable = false) @Column(name = "id", nullable = false)
var id: UUID? = null var id: UUID? = null
@OneToOne(orphanRemoval = true, cascade = [CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.DETACH])
@OneToOne(orphanRemoval = true, cascade = [CascadeType.ALL])
@JoinColumn(name = "tool_id") @JoinColumn(name = "tool_id")
var tool: Tool? = null var tool: Tool? = null
...@@ -36,6 +35,24 @@ class ToolRun { ...@@ -36,6 +35,24 @@ class ToolRun {
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
var repository: Repository? = null var repository: Repository? = null
@OneToMany(
mappedBy = "toolRun",
cascade = [CascadeType.MERGE, CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.DETACH],
orphanRemoval = true
)
var rules: MutableSet<Rule> = mutableSetOf()
fun addRules(rules: Collection<Rule>) {
rules.forEach {
this.addRule(it)
}
}
fun addRule(rule: Rule) {
rules.add(rule)
rule.toolRun = this
}
@OneToMany(mappedBy = "toolRun", cascade = [CascadeType.ALL], orphanRemoval = true) @OneToMany(mappedBy = "toolRun", cascade = [CascadeType.ALL], orphanRemoval = true)
var toolResults: MutableSet<ToolResult> = mutableSetOf() var toolResults: MutableSet<ToolResult> = mutableSetOf()
...@@ -68,7 +85,11 @@ class Tool { ...@@ -68,7 +85,11 @@ class Tool {
@Column(name = "version") @Column(name = "version")
var version: String? = null var version: String? = null
@OneToMany(mappedBy = "tool", cascade = [CascadeType.ALL], orphanRemoval = true) @OneToMany(
mappedBy = "tool",
cascade = [CascadeType.MERGE, CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.DETACH],
orphanRemoval = true
)
var rules: MutableSet<Rule> = mutableSetOf() var rules: MutableSet<Rule> = mutableSetOf()
fun addRules(rules: Collection<Rule>) { fun addRules(rules: Collection<Rule>) {
...@@ -81,6 +102,16 @@ class Tool { ...@@ -81,6 +102,16 @@ class Tool {
rules.add(rule) rules.add(rule)
rule.tool = this rule.tool = this
} }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false
other as Tool
return id != null && id == other.id
}
override fun hashCode(): Int = javaClass.hashCode()
} }
...@@ -186,9 +217,16 @@ class Rule { ...@@ -186,9 +217,16 @@ class Rule {
@Column(name = "short_description", columnDefinition = "TEXT") @Column(name = "short_description", columnDefinition = "TEXT")
var shortDescription: String? = null var shortDescription: String? = null
@OneToMany(mappedBy = "rule", cascade = [CascadeType.ALL], orphanRemoval = true) @OneToMany(
mappedBy = "rule",
cascade = [CascadeType.MERGE, CascadeType.REFRESH, CascadeType.REFRESH, CascadeType.DETACH],
orphanRemoval = true
)
var toolResults: MutableSet<ToolResult> = mutableSetOf() var toolResults: MutableSet<ToolResult> = mutableSetOf()
@ManyToOne
var toolRun: ToolRun? = null
fun addResultLocations(toolResults: Collection<ToolResult>) { fun addResultLocations(toolResults: Collection<ToolResult>) {
toolResults.forEach { toolResults.forEach {
this.addResultLocation(it) this.addResultLocation(it)
......
package de.fraunhofer.iem.dataprovider.toolResult
import de.fraunhofer.iem.dataprovider.gitlab.RepositoryRepository
import de.fraunhofer.iem.dataprovider.sarif.Sarif
import de.fraunhofer.iem.dataprovider.sarif.asDbObject
import org.springframework.stereotype.Service
import java.util.*
@Service
class ToolRunService(
private val repositoryRepository: RepositoryRepository,
private val toolRunRepository: ToolRunRepository,
private val toolRepository: ToolRepository,
private val ruleRepository: RuleRepository
) {
// TODO: this func should be a suspend fun. We can achieve this by
// wrapping the db return types in flux, mono, or futures
fun saveSarif(sarif: Sarif, repoId: UUID) {
val repo = repositoryRepository.findById(repoId)
sarif.runs.forEach { run ->
val fullName = run.tool.driver.fullName
val name = run.tool.driver.name
val version = run.tool.driver.version
val tool =
toolRepository.findByFullNameIgnoreCaseAndNameIgnoreCaseAndVersionIgnoreCase(fullName, name, version)
?: toolRepository.save(run.tool.asDbObject())
val rules = if (tool.id != null) {
ruleRepository.findByTool_Id(tool.id!!).toMutableList()
} else {
mutableListOf()
}
run.tool.driver.rules.forEach { sarifRule ->
if (rules.find { it.sarifRuleId == sarifRule.id } == null) {
val rule = ruleRepository.save(sarifRule.asDbObject())
rules.add(rule)
tool.addRule(rule)
}
}
val toolResults = run.results.map { sarifResult ->
val tr = sarifResult.asDbObject()
rules.filter { it.sarifRuleId == sarifResult.ruleId }
.forEach { it.addResultLocation(tr) }
tr
}
val toolRun = run.asDbObject()
toolRun.tool = tool
toolRun.addRules(rules)
toolRun.addToolResults(toolResults)
val result = toolRunRepository.save(toolRun)
toolRepository.save(tool)
repo.ifPresent {
it.addToolResult(result)
repositoryRepository.save(it)
}
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment

Consent

On this website, we use the web analytics service Matomo to analyze and review the use of our website. Through the collected statistics, we can improve our offerings and make them more appealing for you. Here, you can decide whether to allow us to process your data and set corresponding cookies for these purposes, in addition to technically necessary cookies. Further information on data protection—especially regarding "cookies" and "Matomo"—can be found in our privacy policy. You can withdraw your consent at any time.