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

Merge branch 'feature/dependencies' into 'dev'

Further refactoring and general improvements

See merge request !5
parents 7f51c251 91ab4218
Branches
Tags
1 merge request!5Further refactoring and general improvements
Showing
with 262 additions and 29 deletions
......@@ -49,10 +49,15 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-actuator")
developmentOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(module = "mockito-core")
}
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testRuntimeOnly("com.h2database:h2")
testImplementation("com.ninja-squad:springmockk:4.0.0")
testImplementation("org.springframework.security:spring-security-test")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1")
testImplementation("io.mockk:mockk:1.13.5")
}
tasks.withType<KotlinCompile> {
......
......@@ -18,6 +18,7 @@ class SecurityConfiguration {
authorizeExchange {
authorize("/gitlab/repoChanged", permitAll)
authorize("/debug/metrics/latestRuns/{platform}/{id}", permitAll)
authorize("/debug/metrics/recalculateAllKPIs", permitAll)
authorize("/kpi/{id}", permitAll)
authorize("/kpi/root/repository/{id}", permitAll)
authorize("/repository", permitAll)
......
......@@ -3,15 +3,17 @@ package de.fraunhofer.iem.dataprovider.debug.controller
import de.fraunhofer.iem.dataprovider.debug.dto.*
import de.fraunhofer.iem.dataprovider.gitlab.enumeration.PlatformEnum
import de.fraunhofer.iem.dataprovider.logger.getLogger
import de.fraunhofer.iem.dataprovider.taskManager.TaskManager
import de.fraunhofer.iem.dataprovider.taskManager.events.RecalculateAllKpisEvent
import de.fraunhofer.iem.dataprovider.toolRun.service.ToolRunService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping("/debug/metrics")
class MetricsController(private val toolRunService: ToolRunService) {
class MetricsController(
private val toolRunService: ToolRunService,
private val taskManager: TaskManager
) {
private val logger = getLogger(javaClass)
......@@ -30,4 +32,9 @@ class MetricsController(private val toolRunService: ToolRunService) {
}
return ToolResultsDto(repoDto, trDto)
}
@PostMapping("/recalculateAllKPIs")
suspend fun recalculateAllKPIs() {
taskManager.addEvent(RecalculateAllKpisEvent)
}
}
\ No newline at end of file
package de.fraunhofer.iem.dataprovider.dependency.dto
import de.fraunhofer.iem.dataprovider.dependency.entity.DependencyEntity
data class DependencyCreateDto(
val name: String,
val vulnerabilities: MutableList<VulnerabilityCreateDto> = mutableListOf()
) {
fun toDbObject(): DependencyEntity {
val dependency = DependencyEntity()
dependency.name = this.name
dependency.vulnerabilities = this.vulnerabilities.map { vulnerability ->
val vulnerabilityEntity = vulnerability.toDbObject()
vulnerabilityEntity.dependency = dependency
vulnerabilityEntity
}.toMutableSet()
return dependency
}
}
package de.fraunhofer.iem.dataprovider.dependency.dto
import de.fraunhofer.iem.dataprovider.dependency.entity.VulnerabilityEntity
data class VulnerabilityCreateDto(
val cveIdentifier: String,
val vulnerabilityScore: List<VulnerabilityScoreCreateDto> = mutableListOf()
) {
fun toDbObject(): VulnerabilityEntity {
val vulnerabilityEntity = VulnerabilityEntity()
vulnerabilityEntity.cveIdentifier = this.cveIdentifier
vulnerabilityEntity.vulnerabilityScores = this.vulnerabilityScore.map { score ->
val score = score.toDbObject()
score.vulnerability = vulnerabilityEntity
score
}.toMutableSet()
return vulnerabilityEntity
}
}
package de.fraunhofer.iem.dataprovider.dependency.dto
import de.fraunhofer.iem.dataprovider.dependency.entity.VulnerabilityScoreEntity
import de.fraunhofer.iem.dataprovider.dependency.enumeration.VulnerabilityScoringSystemEnum
data class VulnerabilityScoreCreateDto(
val severity: String,
val scoringSystem: VulnerabilityScoringSystemEnum
) {
fun toDbObject(): VulnerabilityScoreEntity {
val vulnerabilityScoreEntity = VulnerabilityScoreEntity()
vulnerabilityScoreEntity.scoringSystem = this.scoringSystem
vulnerabilityScoreEntity.severity = this.severity
return vulnerabilityScoreEntity
}
}
package de.fraunhofer.iem.dataprovider.dependency.entity
import jakarta.persistence.*
import org.hibernate.Hibernate
import java.util.*
@Entity
@Table(name = "dependency")
class DependencyEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false)
var id: UUID? = null
@Column(name = "name", length = 600)
var name: String? = null
@OneToMany(
mappedBy = "dependency",
cascade = [CascadeType.ALL],
orphanRemoval = true
)
var vulnerabilities: MutableSet<VulnerabilityEntity> = mutableSetOf()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false
other as DependencyEntity
return id != null && id == other.id
}
override fun hashCode(): Int = javaClass.hashCode()
}
\ No newline at end of file
package de.fraunhofer.iem.dataprovider.dependency.entity
import jakarta.persistence.*
import org.hibernate.Hibernate
import java.util.*
@Entity
@Table(name = "vulnerability")
class VulnerabilityEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false)
var id: UUID? = null
@Column(name = "cve_identifier")
var cveIdentifier: String? = null
@ManyToOne
@JoinColumn(name = "dependency_id")
var dependency: DependencyEntity? = null
@OneToMany(
mappedBy = "vulnerability",
cascade = [CascadeType.ALL],
orphanRemoval = true
)
var vulnerabilityScores: MutableSet<VulnerabilityScoreEntity> = mutableSetOf()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false
other as VulnerabilityEntity
return id != null && id == other.id
}
override fun hashCode(): Int = javaClass.hashCode()
}
\ No newline at end of file
package de.fraunhofer.iem.dataprovider.dependency.entity
import de.fraunhofer.iem.dataprovider.dependency.enumeration.VulnerabilityScoringSystemEnum
import jakarta.persistence.*
import org.hibernate.Hibernate
import java.util.*
@Entity
@Table(name = "vulnerability_score")
class VulnerabilityScoreEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false)
var id: UUID? = null
@Column(name = "severity")
var severity: String? = null
@Enumerated(EnumType.STRING)
@Column(name = "scoring_system")
var scoringSystem: VulnerabilityScoringSystemEnum? = null
@ManyToOne
@JoinColumn(name = "vulnerability_id")
var vulnerability: VulnerabilityEntity? = null
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false
other as VulnerabilityScoreEntity
return id != null && id == other.id
}
override fun hashCode(): Int = javaClass.hashCode()
}
\ No newline at end of file
package de.fraunhofer.iem.dataprovider.dependency.enumeration
enum class VulnerabilityScoringSystemEnum {
CVSSV3;
companion object {
fun fromString(value: String): VulnerabilityScoringSystemEnum? {
return values().find { it.name.equals(value, ignoreCase = true) }
}
}
}
\ No newline at end of file
package de.fraunhofer.iem.dataprovider.dependency.repository
import de.fraunhofer.iem.dataprovider.dependency.entity.DependencyEntity
import org.springframework.data.jpa.repository.JpaRepository
import java.util.*
interface DependencyRepository : JpaRepository<DependencyEntity, UUID>
package de.fraunhofer.iem.dataprovider.dependency.service
import de.fraunhofer.iem.dataprovider.dependency.entity.DependencyEntity
import de.fraunhofer.iem.dataprovider.dependency.repository.DependencyRepository
import org.springframework.stereotype.Service
@Service
class DependencyService(private val dependencyRepository: DependencyRepository) {
fun save(dependencyEntity: DependencyEntity) {
dependencyRepository.save(dependencyEntity)
}
}
\ No newline at end of file
......@@ -6,7 +6,7 @@ import java.sql.Timestamp
import java.time.Instant
class KPIDto(val name: String, val description: String, val isRoot: Boolean, private val calculationStrategy: KPICalculationStrategy) {
class KPICreateDto(val name: String, val description: String, val isRoot: Boolean, private val calculationStrategy: KPICalculationStrategy) {
val hierarchyEdges: MutableList<KPIHierarchyEdgeDto> = mutableListOf<KPIHierarchyEdgeDto>()
var value: Int? = null
......@@ -14,15 +14,15 @@ class KPIDto(val name: String, val description: String, val isRoot: Boolean, pri
this.value = calculationStrategy.calculateKPI(this.hierarchyEdges)
}
fun addChildKPI(kpiDto: KPIDto, weight: Double) {
val hierarchyEdge = KPIHierarchyEdgeDto(this, kpiDto, weight)
fun addChildKPI(kpiCreateDto: KPICreateDto, weight: Double) {
val hierarchyEdge = KPIHierarchyEdgeDto(this, kpiCreateDto, weight)
this.hierarchyEdges.add(hierarchyEdge)
}
fun toDbObject(): KPIEntity {
val kpiEntity = KPIEntity()
kpiEntity.name = this.name
kpiEntity.value = this.value
kpiEntity.score = this.value
kpiEntity.description = this.description
kpiEntity.isRoot = this.isRoot
kpiEntity.timestamp = Timestamp.from(Instant.now())
......
package de.fraunhofer.iem.dataprovider.kpi.dto
data class KPIHierarchyEdgeDto (val from: KPIDto, val to: KPIDto, val weight: Double)
\ No newline at end of file
data class KPIHierarchyEdgeDto (val from: KPICreateDto, val to: KPICreateDto, val weight: Double)
\ No newline at end of file
......@@ -22,10 +22,16 @@ class KPIEntity {
var repository: RepositoryEntity? = null
@OneToMany(mappedBy = "from", cascade = [CascadeType.MERGE, CascadeType.REMOVE], orphanRemoval = true)
var hierarchyEdges: MutableSet<KPIHierarchyEdgeEntitiy> = mutableSetOf()
var hierarchyEdges: MutableSet<KPIHierarchyEdgeEntity> = mutableSetOf()
@Column(name = "value")
var value: Int? = null
@Column(name = "score")
var score: Int? = null
@Column(name = "min")
var min: Int? = null
@Column(name = "max")
var max: Int? = null
@Column(name = "is_root")
var isRoot: Boolean? = null
......@@ -49,7 +55,7 @@ class KPIEntity {
}
return KPIResponseDto(
this.id!!,
this.value!!,
this.score!!,
this.name!!,
this.description!!,
this.isRoot!!,
......
......@@ -5,7 +5,7 @@ import java.util.*
@Entity
@Table(name = "kpi_hierarchy_edge")
class KPIHierarchyEdgeEntitiy {
class KPIHierarchyEdgeEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false)
......
package de.fraunhofer.iem.dataprovider.kpi.repository
import de.fraunhofer.iem.dataprovider.kpi.entity.KPIHierarchyEdgeEntitiy
import de.fraunhofer.iem.dataprovider.kpi.entity.KPIHierarchyEdgeEntity
import org.springframework.data.jpa.repository.JpaRepository
import java.util.*
interface KPIHierarchyEdgeRepository : JpaRepository<KPIHierarchyEdgeEntitiy, UUID> {}
interface KPIHierarchyEdgeRepository : JpaRepository<KPIHierarchyEdgeEntity, UUID> {}
package de.fraunhofer.iem.dataprovider.kpi.service
import de.fraunhofer.iem.dataprovider.kpi.dto.KPIDto
import de.fraunhofer.iem.dataprovider.kpi.dto.KPICreateDto
import de.fraunhofer.iem.dataprovider.kpi.entity.KPIEntity
import de.fraunhofer.iem.dataprovider.kpi.entity.KPIHierarchyEdgeEntitiy
import de.fraunhofer.iem.dataprovider.kpi.entity.KPIHierarchyEdgeEntity
import de.fraunhofer.iem.dataprovider.kpi.repository.KPIHierarchyEdgeRepository
import de.fraunhofer.iem.dataprovider.kpi.repository.KPIRepository
import de.fraunhofer.iem.dataprovider.logger.getLogger
......@@ -16,7 +16,7 @@ class KPIService(private val kpiRepository: KPIRepository, private val kpiHierar
private val logger = getLogger(javaClass)
private fun calculateKPIsRecursively(kpi: KPIDto, visited: MutableSet<KPIDto>) {
private fun calculateKPIsRecursively(kpi: KPICreateDto, visited: MutableSet<KPICreateDto>) {
// Check if the KPI has already been visited
if (visited.contains(kpi)) {
return
......@@ -40,21 +40,21 @@ class KPIService(private val kpiRepository: KPIRepository, private val kpiHierar
visited.add(kpi)
}
fun calculateKPIs(rootKPI: KPIDto) {
val visited: MutableSet<KPIDto> = mutableSetOf()
fun calculateKPIs(rootKPI: KPICreateDto) {
val visited: MutableSet<KPICreateDto> = mutableSetOf()
calculateKPIsRecursively(rootKPI, visited)
}
fun storeAndPurgeOld(repositoryEntity: RepositoryEntity, rootKPI: KPIDto) {
fun storeAndPurgeOld(repositoryEntity: RepositoryEntity, rootKPI: KPICreateDto) {
purgeAllKPIs(repositoryEntity)
val kpiEntityDtoToEntityMapping: MutableMap<KPIDto, KPIEntity> = mutableMapOf()
val kpiEntityDtoToEntityMapping: MutableMap<KPICreateDto, KPIEntity> = mutableMapOf()
storeKPI(repositoryEntity, rootKPI, kpiEntityDtoToEntityMapping)
}
private fun storeKPI(
repositoryEntity: RepositoryEntity,
kpi: KPIDto,
kpiEntityDtoToEntityMapping: MutableMap<KPIDto, KPIEntity>
kpi: KPICreateDto,
kpiEntityDtoToEntityMapping: MutableMap<KPICreateDto, KPIEntity>
) {
// already visited
if (kpiEntityDtoToEntityMapping.contains(kpi)) {
......@@ -82,7 +82,7 @@ class KPIService(private val kpiRepository: KPIRepository, private val kpiHierar
kpiRepository.save(kpiEntity)
logger.info("Storing node ${kpi.name}")
for (hierarchyEdge in kpi.hierarchyEdges) {
val hierarchyEdgeEntity = KPIHierarchyEdgeEntitiy()
val hierarchyEdgeEntity = KPIHierarchyEdgeEntity()
hierarchyEdgeEntity.from = kpiEntity
hierarchyEdgeEntity.to = kpiEntityDtoToEntityMapping[hierarchyEdge.to]
hierarchyEdgeEntity.weight = hierarchyEdge.weight
......
package de.fraunhofer.iem.dataprovider.repository.entity
import de.fraunhofer.iem.dataprovider.dependency.entity.DependencyEntity
import de.fraunhofer.iem.dataprovider.gitlab.enumeration.PlatformEnum
import de.fraunhofer.iem.dataprovider.tool.entity.ToolEntity
import de.fraunhofer.iem.dataprovider.toolRun.entity.ToolRunEntity
......@@ -54,6 +55,13 @@ class RepositoryEntity {
)
var toolEntities: MutableSet<ToolEntity> = mutableSetOf()
@ManyToMany
@JoinTable(
name = "repository_dependencies",
joinColumns = [JoinColumn(name = "repository_id")],
inverseJoinColumns = [JoinColumn(name = "dependency_id")]
)
var dependencyEntities: MutableSet<DependencyEntity> = mutableSetOf()
fun addToolResults(toolRuns: Collection<ToolRunEntity>) {
toolRuns.forEach {
this.addToolResult(it)
......
......@@ -178,6 +178,12 @@ class TaskManager(
worker.addTask(MetricsTask(event.repoId, repositoryService, kpiService, ::addEvent))
}
is RecalculateAllKpisEvent -> {
repositoryService.getAllRepositories().forEach { repo ->
worker.addTask(MetricsTask(repo.id!!, repositoryService, kpiService, ::addEvent))
}
}
else -> {
logger.info("Received event without special handling associated $event")
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
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.