diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/service/KPIService.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/service/KPIService.kt index 949e07dae528b18225843029e115d6b9fed513a8..f2b96e364a520e4ecef721f19184cc54302e29a3 100644 --- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/service/KPIService.kt +++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/kpi/service/KPIService.kt @@ -2,12 +2,7 @@ package de.fraunhofer.iem.app.kpi.service import de.fraunhofer.iem.app.kpi.dto.KPITreeChildResponseDto import de.fraunhofer.iem.app.kpi.dto.KPITreeResponseDto -import de.fraunhofer.iem.app.logger.getLogger -import de.fraunhofer.iem.app.repository.dto.RepositoryDetailsDto -import de.fraunhofer.iem.app.tools.occmd.enumeration.Checks -import de.fraunhofer.iem.app.tools.occmd.json.RawResultJson import de.fraunhofer.iem.kpiCalculator.core.KpiCalculator -import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpi import de.fraunhofer.iem.kpiCalculator.model.kpi.hierarchy.DefaultHierarchy import de.fraunhofer.iem.kpiCalculator.model.kpi.hierarchy.KpiResultHierarchy @@ -16,8 +11,6 @@ import org.springframework.stereotype.Service @Service class KPIService { - private val logger = getLogger(javaClass) - fun calculateKpiHierarchy(rawValueKpis: List<RawValueKpi>): KpiResultHierarchy { return KpiCalculator.calculateKpis(DefaultHierarchy.get(), rawValueKpis) } @@ -52,82 +45,4 @@ class KPIService { ) } - /** - * This method calculates the OccmdCreateKpiDtos based upon the given tool results. - */ - fun calculateOccmdKpis(rawOccmdResults: List<RawResultJson>): List<RawValueKpi> { - val kpis = mutableListOf<RawValueKpi>() - - rawOccmdResults.forEach { - when (val check = Checks.fromString(it.check)) { - Checks.CheckedInBinaries -> - kpis.add( - RawValueKpi( - kind = KpiId.CHECKED_IN_BINARIES, - score = (it.score * 100).toInt() - ) - ) - - Checks.SastUsageBasic -> - kpis.add( - RawValueKpi( - kind = KpiId.SAST_USAGE, - score = (it.score * 100).toInt() - ) - ) - - Checks.Secrets -> - kpis.add( - RawValueKpi( - kind = KpiId.SECRETS, - score = (it.score * 100).toInt() - ) - ) - - Checks.CommentsInCode -> - kpis.add( - RawValueKpi( - kind = KpiId.COMMENTS_IN_CODE, - score = (it.score * 100).toInt() - ) - ) - - Checks.DocumentationInfrastructure -> - kpis.add( - RawValueKpi( - kind = KpiId.DOCUMENTATION_INFRASTRUCTURE, - score = (it.score * 100).toInt() - ) - ) - - else -> - logger.warn("Unknown OCCMD result. $check") - } - } - - return kpis - } - - /** - * Creates a named map of RepositoryCreateDtos, based upon the provided repository details. - * This method only returns raw KPIs. - */ - fun calculateRepositoryDetailsKpis(repoDetailsDto: RepositoryDetailsDto): List<RawValueKpi> { - return listOf( - RawValueKpi( - kind = KpiId.NUMBER_OF_COMMITS, - score = repoDetailsDto.numberOfCommits - ), - RawValueKpi( - kind = KpiId.NUMBER_OF_SIGNED_COMMITS, - score = repoDetailsDto.numberOfSignedCommits - ), - RawValueKpi( - kind = KpiId.IS_DEFAULT_BRANCH_PROTECTED, - score = if (repoDetailsDto.isDefaultBranchProtected) 100 else 0 - ) - ) - } - - } diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/toolRun/service/ToolRunService.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/toolRun/service/ToolRunService.kt index 5c003c1c1a43a9cd1f7f7e9c94d1c027ccb3ae21..ea1ae18174fc59bb645c53b56265f74ef9ee77c6 100644 --- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/toolRun/service/ToolRunService.kt +++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/toolRun/service/ToolRunService.kt @@ -1,6 +1,5 @@ package de.fraunhofer.iem.app.toolRun.service -import de.fraunhofer.iem.app.kpi.service.KPIService import de.fraunhofer.iem.app.logger.getLogger import de.fraunhofer.iem.app.repository.service.RepositoryService import de.fraunhofer.iem.app.tool.enumeration.ToolType @@ -9,15 +8,15 @@ import de.fraunhofer.iem.app.tools.gitlab.service.RepositoryDetailsService import de.fraunhofer.iem.app.tools.occmd.service.OccmdService import de.fraunhofer.iem.app.tools.ort.service.OrtService import de.fraunhofer.iem.kpiCalculator.adapter.cve.CveAdapter +import de.fraunhofer.iem.kpiCalculator.adapter.occmd.OccmdAdapter +import de.fraunhofer.iem.kpiCalculator.adapter.vcs.VcsAdapter import de.fraunhofer.iem.kpiCalculator.model.adapter.AdapterResult import kotlinx.coroutines.* import org.springframework.stereotype.Service @Service class ToolRunService( - private val repositoryDetailsService: RepositoryDetailsService, - private val kpiService: KPIService, private val ortService: OrtService, private val occmdService: OccmdService, private val repositoryService: RepositoryService, @@ -80,12 +79,25 @@ class ToolRunService( async { val repoDetailsDto = repositoryDetailsService.getRepositoryDetails(projectId) - Pair(repositoryDetailsService.getToolDto(), kpiService.calculateRepositoryDetailsKpis(repoDetailsDto)) + val rawValueRepoKpis = + VcsAdapter.transformDataToKpi(repoDetailsDto) + + val result = if (rawValueRepoKpis is AdapterResult.Success) { + listOf(rawValueRepoKpis.rawValueKpi) + } else { + listOf() + } + + Pair(repositoryDetailsService.getToolDto(), result) }, async { val rawOccmdResults = occmdService.runOccmd(projectId, repoDto.uri) - Pair(occmdService.getToolDto(), kpiService.calculateOccmdKpis(rawOccmdResults)) + val rawValueKpiCreateDtos = + OccmdAdapter.transformDataToKpi(rawOccmdResults).filterIsInstance<AdapterResult.Success>() + .map { it.rawValueKpi } + + Pair(occmdService.getToolDto(), rawValueKpiCreateDtos) } ) diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/occmd/service/OccmdService.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/occmd/service/OccmdService.kt index f3bae5b177af9015908e4266c189ad4a13cba7fb..ae3e2bb40e466fcfad5609401d8eca0787555ae7 100644 --- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/occmd/service/OccmdService.kt +++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/occmd/service/OccmdService.kt @@ -5,7 +5,7 @@ import de.fraunhofer.iem.app.configuration.OpenCodeGitlabApiProperties import de.fraunhofer.iem.app.logger.getLogger import de.fraunhofer.iem.app.tool.dto.CreateToolDto import de.fraunhofer.iem.app.tool.enumeration.ToolType -import de.fraunhofer.iem.app.tools.occmd.json.RawResultJson +import de.fraunhofer.iem.kpiCalculator.model.adapter.occmd.OccmdDto import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.coroutineScope @@ -43,7 +43,7 @@ class OccmdService( * the DTOs. */ @OptIn(ExperimentalPathApi::class) - suspend fun runOccmd(projectId: Long, repoUrl: String): List<RawResultJson> { + suspend fun runOccmd(projectId: Long, repoUrl: String): List<OccmdDto> { logger.info("runOccmd for repo $projectId") val rawOccmdResults = try { // clone repo @@ -88,9 +88,9 @@ class OccmdService( execPath: String, flags: Array<String>, ioDispatcher: CoroutineDispatcher = Dispatchers.IO - ): List<RawResultJson> = + ): List<OccmdDto> = coroutineScope { - val toolResults = mutableListOf<RawResultJson>() + val toolResults = mutableListOf<OccmdDto>() if (isExecutable(execPath)) { val process = withContext(ioDispatcher) { ProcessBuilder(execPath, *flags).start() @@ -106,7 +106,7 @@ class OccmdService( process.inputStream.bufferedReader().forEachLine { try { logger.info("Decoding $it") - val occmdResults: Array<RawResultJson> = json.decodeFromString(it) + val occmdResults: Array<OccmdDto> = json.decodeFromString(it) toolResults.addAll(occmdResults) } catch (e: Exception) { logger.error("Decoding of occmd result failed $it") diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/ort/service/OrtService.kt b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/ort/service/OrtService.kt index f00015bb7bd3e3af7952e66514a8ff106aeab0c8..0b60e29e38be269a89a0ef57d7bd39d8890cf100 100644 --- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/ort/service/OrtService.kt +++ b/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/ort/service/OrtService.kt @@ -7,7 +7,7 @@ import de.fraunhofer.iem.app.tool.enumeration.ToolType import de.fraunhofer.iem.app.tools.ort.json.OrtJson import de.fraunhofer.iem.app.tools.ort.json.ResultJson import de.fraunhofer.iem.app.utilities.HttpClientWrapper -import de.fraunhofer.iem.kpiCalculator.model.adapter.VulnerabilityDto +import de.fraunhofer.iem.kpiCalculator.model.adapter.vulnerability.VulnerabilityDto import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.client.statement.* diff --git a/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/KpiAdapter.kt b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/KpiAdapter.kt index b7ca13577a1a02dd6741c0124a891714339d28bd..ab93079a772342ea01d4fdee6923686cb7cbd843 100644 --- a/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/KpiAdapter.kt +++ b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/KpiAdapter.kt @@ -1,12 +1,9 @@ package de.fraunhofer.iem.kpiCalculator.adapter import de.fraunhofer.iem.kpiCalculator.model.adapter.AdapterResult -import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId interface KpiAdapter<T> { - val kpiId: KpiId - fun transformDataToKpi(data: List<T>): List<AdapterResult> fun transformDataToKpi(data: T): AdapterResult = transformDataToKpi(listOf(data)).first() } diff --git a/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapter.kt b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapter.kt index 931c3a3db6bf4ddf9dc716dbd34dd694361b2fa4..d224c435f87fd929c22ffe9f6037448019c3b527 100644 --- a/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapter.kt +++ b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapter.kt @@ -3,13 +3,11 @@ package de.fraunhofer.iem.kpiCalculator.adapter.cve import de.fraunhofer.iem.kpiCalculator.adapter.KpiAdapter import de.fraunhofer.iem.kpiCalculator.model.adapter.AdapterResult import de.fraunhofer.iem.kpiCalculator.model.adapter.ErrorType -import de.fraunhofer.iem.kpiCalculator.model.adapter.VulnerabilityDto +import de.fraunhofer.iem.kpiCalculator.model.adapter.vulnerability.VulnerabilityDto import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpi object CveAdapter : KpiAdapter<VulnerabilityDto> { - override val kpiId: KpiId - get() = KpiId.VULNERABILITY_SCORE override fun transformDataToKpi(data: List<VulnerabilityDto>): List<AdapterResult> { return data @@ -17,7 +15,7 @@ object CveAdapter : KpiAdapter<VulnerabilityDto> { return@map if (isValid(it)) { AdapterResult.Success( RawValueKpi( - kind = kpiId, + kind = KpiId.VULNERABILITY_SCORE, score = (it.severity * 10).toInt() ) ) diff --git a/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/occmd/OccmdAdapter.kt b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/occmd/OccmdAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..d114b7acc6ada38540637545f88782355727f932 --- /dev/null +++ b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/occmd/OccmdAdapter.kt @@ -0,0 +1,62 @@ +package de.fraunhofer.iem.kpiCalculator.adapter.occmd + +import de.fraunhofer.iem.kpiCalculator.adapter.KpiAdapter +import de.fraunhofer.iem.kpiCalculator.model.adapter.AdapterResult +import de.fraunhofer.iem.kpiCalculator.model.adapter.occmd.Checks +import de.fraunhofer.iem.kpiCalculator.model.adapter.occmd.OccmdDto +import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId +import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpi + +object OccmdAdapter : KpiAdapter<OccmdDto> { + + override fun transformDataToKpi(data: List<OccmdDto>): List<AdapterResult> { + + return data.mapNotNull { + return@mapNotNull when (Checks.fromString(it.check)) { + Checks.CheckedInBinaries -> + AdapterResult.Success( + RawValueKpi( + kind = KpiId.CHECKED_IN_BINARIES, + score = (it.score * 100).toInt() + ) + ) + + Checks.SastUsageBasic -> + AdapterResult.Success( + RawValueKpi( + kind = KpiId.SAST_USAGE, + score = (it.score * 100).toInt() + ) + ) + + Checks.Secrets -> + AdapterResult.Success( + RawValueKpi( + kind = KpiId.SECRETS, + score = (it.score * 100).toInt() + ) + ) + + Checks.CommentsInCode -> + AdapterResult.Success( + RawValueKpi( + kind = KpiId.COMMENTS_IN_CODE, + score = (it.score * 100).toInt() + ) + ) + + Checks.DocumentationInfrastructure -> + AdapterResult.Success( + RawValueKpi( + kind = KpiId.DOCUMENTATION_INFRASTRUCTURE, + score = (it.score * 100).toInt() + ) + ) + + else -> { + null + } + } + } + } +} diff --git a/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/vcs/VcsAdapter.kt b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/vcs/VcsAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..4d79696714eb16cfdccde00638c229c3ae958649 --- /dev/null +++ b/kpi-calculator/adapter/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/vcs/VcsAdapter.kt @@ -0,0 +1,43 @@ +package de.fraunhofer.iem.kpiCalculator.adapter.vcs + +import de.fraunhofer.iem.app.repository.dto.RepositoryDetailsDto +import de.fraunhofer.iem.kpiCalculator.adapter.KpiAdapter +import de.fraunhofer.iem.kpiCalculator.model.adapter.AdapterResult +import de.fraunhofer.iem.kpiCalculator.model.adapter.ErrorType +import de.fraunhofer.iem.kpiCalculator.model.kpi.KpiId +import de.fraunhofer.iem.kpiCalculator.model.kpi.RawValueKpi + +object VcsAdapter : KpiAdapter<RepositoryDetailsDto> { + + override fun transformDataToKpi(data: List<RepositoryDetailsDto>): List<AdapterResult> { + + if (data.size != 1) { + return listOf( + AdapterResult.Error(type = ErrorType.DATA_VALIDATION_ERROR) + ) + } + + //XXX: we need to decide about error handling in adapters + val repoDetailsDto = data.first() + return listOf( + AdapterResult.Success( + RawValueKpi( + kind = KpiId.NUMBER_OF_COMMITS, + score = repoDetailsDto.numberOfCommits + ) + ), + AdapterResult.Success( + RawValueKpi( + kind = KpiId.NUMBER_OF_SIGNED_COMMITS, + score = repoDetailsDto.numberOfSignedCommits + ) + ), + AdapterResult.Success( + RawValueKpi( + kind = KpiId.IS_DEFAULT_BRANCH_PROTECTED, + score = if (repoDetailsDto.isDefaultBranchProtected) 100 else 0 + ) + ) + ) + } +} diff --git a/kpi-calculator/adapter/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapterTest.kt b/kpi-calculator/adapter/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapterTest.kt index 7e8b07aba998fbc1a8b87ece0addd0757e010b60..484e2fc4db8001df2036e9f9ef94fee54ce4b59c 100644 --- a/kpi-calculator/adapter/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapterTest.kt +++ b/kpi-calculator/adapter/src/test/kotlin/de/fraunhofer/iem/kpiCalculator/adapter/cve/CveAdapterTest.kt @@ -2,7 +2,7 @@ package de.fraunhofer.iem.kpiCalculator.adapter.cve import de.fraunhofer.iem.kpiCalculator.model.adapter.AdapterResult import de.fraunhofer.iem.kpiCalculator.model.adapter.ErrorType -import de.fraunhofer.iem.kpiCalculator.model.adapter.VulnerabilityDto +import de.fraunhofer.iem.kpiCalculator.model.adapter.vulnerability.VulnerabilityDto import org.junit.jupiter.api.Test import kotlin.test.fail diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/occmd/enumeration/Checks.kt b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/occmd/Checks.kt similarity index 88% rename from app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/occmd/enumeration/Checks.kt rename to kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/occmd/Checks.kt index a4a7353099eea5fe3939b5f8bd5a166e454555f9..ec2885783308dde80ec4456e6115e8d0b78c1c59 100644 --- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/occmd/enumeration/Checks.kt +++ b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/occmd/Checks.kt @@ -1,4 +1,4 @@ -package de.fraunhofer.iem.app.tools.occmd.enumeration +package de.fraunhofer.iem.kpiCalculator.model.adapter.occmd enum class Checks(val checkName: String) { SastUsageBasic("SastUsageBasic"), diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/occmd/json/RawResultJson.kt b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/occmd/OccmdDto.kt similarity index 83% rename from app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/occmd/json/RawResultJson.kt rename to kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/occmd/OccmdDto.kt index 3390c050bdfca8baa7bbfaf929629d3551819bbb..2942e5fe83b892c77710aa9ba24651dd242e8340 100644 --- a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/tools/occmd/json/RawResultJson.kt +++ b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/occmd/OccmdDto.kt @@ -1,4 +1,4 @@ -package de.fraunhofer.iem.app.tools.occmd.json +package de.fraunhofer.iem.kpiCalculator.model.adapter.occmd import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -8,7 +8,7 @@ import kotlinx.serialization.json.JsonObject * The result of an occmd check performed on an OpenCodDE project. */ @Serializable -data class RawResultJson( +data class OccmdDto( @SerialName("check") val check: String, @SerialName("id") diff --git a/app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/dto/RepositoryDetailsDto.kt b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/vcs/RepositoryDetailsDto.kt similarity index 100% rename from app/backend/src/main/kotlin/de/fraunhofer/iem/app/repository/dto/RepositoryDetailsDto.kt rename to kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/vcs/RepositoryDetailsDto.kt diff --git a/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/VulnerabilityDto.kt b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/vulnerability/VulnerabilityDto.kt similarity index 60% rename from kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/VulnerabilityDto.kt rename to kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/vulnerability/VulnerabilityDto.kt index d03226a1f63b1a5eb516cd95b7dd00fdb2220205..b1041e4a578666cb0701be95f26cbe851c6cdf34 100644 --- a/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/VulnerabilityDto.kt +++ b/kpi-calculator/model/src/main/kotlin/de/fraunhofer/iem/kpiCalculator/model/adapter/vulnerability/VulnerabilityDto.kt @@ -1,3 +1,3 @@ -package de.fraunhofer.iem.kpiCalculator.model.adapter +package de.fraunhofer.iem.kpiCalculator.model.adapter.vulnerability data class VulnerabilityDto(val cveIdentifier: String, val packageName: String, val severity: Double)