From 8697a4a99cf6e1f65fb286299b6938e07b1b6954 Mon Sep 17 00:00:00 2001 From: Jan-Niclas Struewer <j.n.struewer@gmail.com> Date: Wed, 4 Oct 2023 17:14:02 +0200 Subject: [PATCH] started preparations for error handling --- .../iem/dataprovider/kpi/dto/KPICreateDto.kt | 8 +++-- .../dataprovider/kpi/dto/KPIResponseDto.kt | 3 +- .../iem/dataprovider/kpi/entity/KPIEntity.kt | 6 +++- .../kpi/metrics/MetricsService.kt | 32 +++++++++++++++---- .../dto/RepositoryDetailsKpiDto.kt | 6 ++-- .../service/RepositoryDetailsService.kt | 3 -- .../dataprovider/kpi/service/KPIService.kt | 23 ++++++------- .../strategy/RatioKPICalculationStrategy.kt | 4 +-- .../tools/occmd/service/OccmdService.kt | 3 -- .../tools/ort/service/OrtService.kt | 1 - 10 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/dto/KPICreateDto.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/dto/KPICreateDto.kt index 2232cbd1..35f0a089 100644 --- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/dto/KPICreateDto.kt +++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/dto/KPICreateDto.kt @@ -9,9 +9,10 @@ import java.time.Instant class KPICreateDto( val name: String, private val description: String, - private val isRoot: Boolean, private val calculationStrategy: KPICalculationStrategy, - private val displayScore: String? = null + private val displayScore: String? = null, + private val isEmpty: Boolean = true, + private val isRoot: Boolean = false ) { val hierarchyEdges: MutableList<KPIHierarchyEdgeDto> = mutableListOf() var value: Int? = null @@ -33,6 +34,7 @@ class KPICreateDto( kpiEntity.isRoot = this.isRoot kpiEntity.timestamp = Timestamp.from(Instant.now()) kpiEntity.displayScore = this.displayScore + kpiEntity.isEmpty = this.isEmpty return kpiEntity } -} \ No newline at end of file +} diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/dto/KPIResponseDto.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/dto/KPIResponseDto.kt index 1114ca83..fb7e3371 100644 --- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/dto/KPIResponseDto.kt +++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/dto/KPIResponseDto.kt @@ -10,5 +10,6 @@ data class KPIResponseDto( val isRoot: Boolean, val displayValue: String? = null, val children: List<KPIChildResponseDto>, - val repositoryId: UUID + val repositoryId: UUID, + val isEmpty: Boolean ) diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/entity/KPIEntity.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/entity/KPIEntity.kt index 92a7c280..1dbd8e5d 100644 --- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/entity/KPIEntity.kt +++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/entity/KPIEntity.kt @@ -39,6 +39,9 @@ class KPIEntity { @Column(name = "is_root") var isRoot: Boolean? = null + @Column(name = "is_empty") + var isEmpty: Boolean? = null + @Column(name = "name") var name: String? = null @@ -64,7 +67,8 @@ class KPIEntity { this.isRoot!!, this.displayScore, childrenList, - this.repository!!.id!! + this.repository!!.id!!, + this.isEmpty!! ) } } diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/MetricsService.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/MetricsService.kt index d51b1789..201b8276 100644 --- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/MetricsService.kt +++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/MetricsService.kt @@ -1,9 +1,12 @@ package de.fraunhofer.iem.dataprovider.kpi.metrics +import de.fraunhofer.iem.dataprovider.kpi.metrics.repositoryDetails.dto.RepositoryDetailsKpisDto import de.fraunhofer.iem.dataprovider.kpi.metrics.repositoryDetails.service.RepositoryDetailsService import de.fraunhofer.iem.dataprovider.kpi.service.KPIService +import de.fraunhofer.iem.dataprovider.logger.getLogger import de.fraunhofer.iem.dataprovider.repository.service.RepositoryService import de.fraunhofer.iem.dataprovider.toolRun.service.ToolRunService +import de.fraunhofer.iem.dataprovider.tools.occmd.dto.OccmdKpisDto import de.fraunhofer.iem.dataprovider.tools.occmd.service.OccmdService import de.fraunhofer.iem.dataprovider.tools.ort.service.OrtService import kotlinx.coroutines.CoroutineScope @@ -23,8 +26,8 @@ class MetricsService( ) { private val defaultScope = CoroutineScope(Dispatchers.Default) - val ioScope = CoroutineScope(Dispatchers.IO) - + private val ioScope = CoroutineScope(Dispatchers.IO) + private val logger = getLogger(javaClass) /** * Warning: Long running function! @@ -84,13 +87,20 @@ class MetricsService( kpis } - val repositoryDetailsKpi = async { + val repositoryDetailsKpiDeferred = async { val repoDetailsDto = repositoryDetailsService.getRepositoryDetails(repoId) toolRun.toolEntities.add(repositoryDetailsService.toolEntity) repositoryDetailsService.calculateRepositoryDetailsKpis(repoDetailsDto) } - val occmdKpis = async { + val repositoryDetailsKpi = try { + repositoryDetailsKpiDeferred.await() + } catch (e: Exception) { + logger.error("Exception occurred during OccmdKpi retrieval") + RepositoryDetailsKpisDto(null, null, null) + } + + val occmdKpiDeferred = async { val rawOccmdResults = occmdService.runOccmd(repoId, toolRun.repository?.url!!) if (rawOccmdResults.isNotEmpty()) { toolRun.toolEntities.add(occmdService.toolEntity) @@ -98,6 +108,16 @@ class MetricsService( occmdService.calculateOccmdKpis(rawOccmdResults) } + val occmdKpis: OccmdKpisDto = try { + occmdKpiDeferred.await() + } catch (e: Exception) { + logger.error("Exception occurred during OccmdKpi retrieval") + // TODO: this should be the "neutral element" for the Occmd data + // The neutral element should not influence other dependent KPI + // calculation in a positive or negative way. + OccmdKpisDto(null, null, null) + } + /** * Calculate KPI tree by awaiting all tool KPIs * joinAll(toolKpi) @@ -105,9 +125,9 @@ class MetricsService( */ kpiService.calculateAndSaveKpiTree( repository = toolRun.repository!!, - repositoryDetailsKpi = repositoryDetailsKpi.await(), + repositoryDetailsKpi = repositoryDetailsKpi, vulnerabilityKpis = vulnerabilityKpis.await(), - occmdKpis = occmdKpis.await() + occmdKpis = occmdKpis ) toolRunService.saveToolRunEntitiy(toolRun) diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/repositoryDetails/dto/RepositoryDetailsKpiDto.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/repositoryDetails/dto/RepositoryDetailsKpiDto.kt index 1f56c6d2..35e1f1ae 100644 --- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/repositoryDetails/dto/RepositoryDetailsKpiDto.kt +++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/repositoryDetails/dto/RepositoryDetailsKpiDto.kt @@ -3,7 +3,7 @@ package de.fraunhofer.iem.dataprovider.kpi.metrics.repositoryDetails.dto import de.fraunhofer.iem.dataprovider.kpi.dto.KPICreateDto data class RepositoryDetailsKpisDto( - val numberOfCommitsKpi: KPICreateDto, - val numberOfSignedCommitsKPI: KPICreateDto, - val isDefaultBranchProtectedKPI: KPICreateDto, + val numberOfCommitsKpi: KPICreateDto?, + val numberOfSignedCommitsKPI: KPICreateDto?, + val isDefaultBranchProtectedKPI: KPICreateDto?, ) diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/repositoryDetails/service/RepositoryDetailsService.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/repositoryDetails/service/RepositoryDetailsService.kt index 9e1821b8..fe9ac104 100644 --- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/repositoryDetails/service/RepositoryDetailsService.kt +++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/metrics/repositoryDetails/service/RepositoryDetailsService.kt @@ -33,19 +33,16 @@ class RepositoryDetailsService(private val openCodeGitlabApi: OpenCodeGitlabApi, val numberOfCommitsKPI = KPICreateDto( "Number of Commits", "Total number of commits on the default branch of the repository.", - false, RawValueKPICalculationStrategy(repoDetailsDto.numberOfCommits) ) val numberOfSignedCommitsKPI = KPICreateDto( "Number of Signed Commits", "Total number of signed and verified commits on the default branch of the repository.", - false, RawValueKPICalculationStrategy(repoDetailsDto.numberOfSignedCommits) ) val isDefaultBranchProtectedKPI = KPICreateDto( "Default Branch Protection", "Used to assess compliance with a standard development process. For this purpose, it is examined whether the standard development branch is protected against unintentional changes.", - false, RawValueKPICalculationStrategy(if (repoDetailsDto.isDefaultBranchProtected) 100 else 0) ) diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/service/KPIService.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/service/KPIService.kt index 70e5f98c..3fa80c1f 100644 --- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/service/KPIService.kt +++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/service/KPIService.kt @@ -51,42 +51,43 @@ class KPIService( KPICreateDto( "Commit Signature Ratio", "Used to assess compliance with a common and transparent development process. It is desirable that all commits are signed by their authors. Therefore, the ratio of signed commits to all commits is determined to calculate this metric.", - false, RatioKPICalculationStrategy() ) - signedCommitsRatioKPI.addChildKPI(repositoryDetailsKpi.numberOfCommitsKpi, 1.0) - signedCommitsRatioKPI.addChildKPI(repositoryDetailsKpi.numberOfSignedCommitsKPI, 1.0) + if (repositoryDetailsKpi.numberOfCommitsKpi != null && repositoryDetailsKpi.numberOfSignedCommitsKPI != null) { + signedCommitsRatioKPI.addChildKPI(repositoryDetailsKpi.numberOfCommitsKpi, 1.0) + signedCommitsRatioKPI.addChildKPI(repositoryDetailsKpi.numberOfSignedCommitsKPI, 1.0) + } val processComplianceKPI = KPICreateDto( "Process Compliance Score", "Assesses the development process of the software provided. For this purpose, the development process traceable in the repository is compared with common development standards to enable an assessment.", - false, AggregationKPICalculationStrategy() ) + if (repositoryDetailsKpi.isDefaultBranchProtectedKPI != null) { + processComplianceKPI.addChildKPI(repositoryDetailsKpi.isDefaultBranchProtectedKPI, 0.5) + } + processComplianceKPI.addChildKPI(signedCommitsRatioKPI, 0.5) + val processTransparencyKPI = KPICreateDto( "Process Transparency Score", "Assesses the transparency resp. traceability of the development process of the provided software for external parties. For this purpose, various analyzes are performed that assess the availability of information about the software development process within the repository.", - false, AggregationKPICalculationStrategy() ) - processComplianceKPI.addChildKPI(repositoryDetailsKpi.isDefaultBranchProtectedKPI, 0.5) - processComplianceKPI.addChildKPI(signedCommitsRatioKPI, 0.5) + processTransparencyKPI.addChildKPI(signedCommitsRatioKPI, 1.0) val securityKPI = KPICreateDto( "Security Score", "Assesses the security of the software provided. For this purpose, various security-relevant analyzes are carried out, which, among other things, check the external dependencies or the code for vulnerabilities.", - false, AggregationKPICalculationStrategy() ) val maximalDependencyVulnerabilityKPI = KPICreateDto( "Maximal Dependency Vulnerability Score", "This score is calculated by the following formula: 100 - (max(CVSS score) * 10). Thus, a lower value indicates a more critical vulnerability.", - false, // This strategy is tied to this specific KPI. It calculates 100 - max(children). Children are already multiplied by 10 MaximumKPICalculationStrategy() ) @@ -108,8 +109,8 @@ class KPIService( val rootKPI = KPICreateDto( "Project Score", "Assesses the project resp. the provided software in the aspects of maturity (based on quality, security and usability aspects) as well as development process.", - true, - AggregationKPICalculationStrategy() + AggregationKPICalculationStrategy(), + isRoot = true, ) rootKPI.addChildKPI(processTransparencyKPI, 0.25) rootKPI.addChildKPI(processComplianceKPI, 0.25) diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/RatioKPICalculationStrategy.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/RatioKPICalculationStrategy.kt index daae693e..b758cb52 100644 --- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/RatioKPICalculationStrategy.kt +++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/kpi/strategy/RatioKPICalculationStrategy.kt @@ -10,8 +10,8 @@ class RatioKPICalculationStrategy : KPICalculationStrategy { val firstValue = children[0].to.value val secondValue = children[1].to.value if (firstValue!! >= secondValue!!) { - return ((secondValue / firstValue) * 100).toInt() + return ((secondValue / firstValue) * 100) } - return ((firstValue / secondValue) * 100).toInt() + return ((firstValue / secondValue) * 100) } } diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/occmd/service/OccmdService.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/occmd/service/OccmdService.kt index 5ad46c50..fdd97462 100644 --- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/occmd/service/OccmdService.kt +++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/occmd/service/OccmdService.kt @@ -93,7 +93,6 @@ class OccmdService( checkedInBinaryDto = KPICreateDto( "Checked in Binary", "", - false, RawValueKPICalculationStrategy((it.score * 100).toInt()) ) @@ -101,7 +100,6 @@ class OccmdService( sastUsageDto = KPICreateDto( "SAST usage", "", - false, RawValueKPICalculationStrategy(100 - (it.score * 100).toInt()) ) @@ -109,7 +107,6 @@ class OccmdService( secretsDto = KPICreateDto( "Secrets", "", - false, RawValueKPICalculationStrategy((it.score * 10).toInt()) ) diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/service/OrtService.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/service/OrtService.kt index 24bcc0eb..88de3941 100644 --- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/service/OrtService.kt +++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/service/OrtService.kt @@ -58,7 +58,6 @@ class OrtService(private val openCodeApiProperties: OpenCodeApiProperties, priva KPICreateDto( "Vulnerability ${it.cveIdentifier}", "Affected package: ${it.packageName}", - false, RawValueKPICalculationStrategy((it.severity * 10).toInt()), displayScore = it.severity.toString() ) -- GitLab