From 479293bd8a531c18f51e3c84fbe70769e943fc6c Mon Sep 17 00:00:00 2001
From: Jan-Niclas Struewer <j.n.struewer@gmail.com>
Date: Mon, 25 Sep 2023 17:40:22 +0200
Subject: [PATCH] added ort api connection

---
 .../dataprovider/DataProviderApplication.kt   |   2 +
 .../dataprovider/configuration/ApiPaths.kt    |   4 +-
 .../configuration/OpenCodeApiProperties.kt    |  24 +++
 .../debug/controller/MetricsController.kt     |  22 ---
 .../kpi/metrics/MetricsService.kt             |  15 +-
 .../dataprovider/kpi/service/KPIService.kt    |  52 +++---
 .../dataprovider/taskManager/TaskManager.kt   | 173 ------------------
 .../taskManager/tasks/tools/ort/OrtApiTask.kt |   2 +-
 .../tools/ort/dto/VulnerabilityDto.kt         |   3 +
 .../tasks => }/tools/ort/json/DataJson.kt     |   2 +-
 .../tasks => }/tools/ort/json/OrtJson.kt      |   2 +-
 .../tools/ort/json/ReferenceJson.kt           |   2 +-
 .../tasks => }/tools/ort/json/ResultJson.kt   |   4 +-
 .../tools/ort/service/OrtService.kt           |  62 +++++++
 src/main/resources/application.properties     |   5 +-
 15 files changed, 146 insertions(+), 228 deletions(-)
 create mode 100644 src/main/kotlin/de/fraunhofer/iem/dataprovider/configuration/OpenCodeApiProperties.kt
 delete mode 100644 src/main/kotlin/de/fraunhofer/iem/dataprovider/debug/controller/MetricsController.kt
 delete mode 100644 src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/TaskManager.kt
 create mode 100644 src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/dto/VulnerabilityDto.kt
 rename src/main/kotlin/de/fraunhofer/iem/dataprovider/{taskManager/tasks => }/tools/ort/json/DataJson.kt (83%)
 rename src/main/kotlin/de/fraunhofer/iem/dataprovider/{taskManager/tasks => }/tools/ort/json/OrtJson.kt (76%)
 rename src/main/kotlin/de/fraunhofer/iem/dataprovider/{taskManager/tasks => }/tools/ort/json/ReferenceJson.kt (80%)
 rename src/main/kotlin/de/fraunhofer/iem/dataprovider/{taskManager/tasks => }/tools/ort/json/ResultJson.kt (89%)
 create mode 100644 src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/service/OrtService.kt

diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/DataProviderApplication.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/DataProviderApplication.kt
index 27be12dc..6f72be00 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/DataProviderApplication.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/DataProviderApplication.kt
@@ -1,6 +1,7 @@
 package de.fraunhofer.iem.dataprovider
 
 import de.fraunhofer.iem.dataprovider.configuration.DirectoryPathsProperties
+import de.fraunhofer.iem.dataprovider.configuration.OpenCodeApiProperties
 import de.fraunhofer.iem.dataprovider.configuration.OpenCodeGitlabApiProperties
 import de.fraunhofer.iem.dataprovider.configuration.security.SecurityProperties
 import org.springframework.boot.autoconfigure.SpringBootApplication
@@ -12,6 +13,7 @@ import org.springframework.boot.runApplication
 @EnableConfigurationProperties(
     DirectoryPathsProperties::class,
     OpenCodeGitlabApiProperties::class,
+    OpenCodeApiProperties::class,
     SecurityProperties::class
 )
 class DataProviderApplication
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/configuration/ApiPaths.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/configuration/ApiPaths.kt
index c85024f5..4a311a71 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/configuration/ApiPaths.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/configuration/ApiPaths.kt
@@ -3,13 +3,13 @@ package de.fraunhofer.iem.dataprovider.configuration
 object ApiPaths {
     private const val BASE = "/api"
 
-    const val GITLAB = "$BASE/gitlab"
+    private const val GITLAB = "$BASE/gitlab"
     const val OPENCODE_REPO_CHANGED = "$GITLAB/opencode/repoChanged"
 
     const val DEBUG = "$BASE/debug/metrics"
     const val DEBUG_RECALCULATE_KPIS = "$DEBUG/recalculateAllKPIs"
 
-    const val KPI = "$BASE/kpi"
+    private const val KPI = "$BASE/kpi"
     const val KPI_ID = "$KPI/{id}"
     const val KPI_ROOT_REPOSITORY = "$KPI/root/repository/{id}"
 
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/configuration/OpenCodeApiProperties.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/configuration/OpenCodeApiProperties.kt
new file mode 100644
index 00000000..f3ecdde4
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/configuration/OpenCodeApiProperties.kt
@@ -0,0 +1,24 @@
+package de.fraunhofer.iem.dataprovider.configuration
+
+import jakarta.annotation.PostConstruct
+import jakarta.validation.constraints.NotBlank
+import org.springframework.boot.context.properties.ConfigurationProperties
+import org.springframework.validation.annotation.Validated
+import java.net.URL
+
+
+@ConfigurationProperties(prefix = "opencode.api")
+@Validated
+data class OpenCodeApiProperties(
+    @NotBlank
+    val basePath: String,
+    @NotBlank
+    val ort: String
+) {
+    @PostConstruct
+    fun postConstruct() {
+        // There is no try catch block around the operations on purpose!
+        // We want to throw here if this operations fail.
+        URL(basePath).toURI()
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/debug/controller/MetricsController.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/debug/controller/MetricsController.kt
deleted file mode 100644
index 699bd0fe..00000000
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/debug/controller/MetricsController.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package de.fraunhofer.iem.dataprovider.debug.controller
-
-import de.fraunhofer.iem.dataprovider.configuration.ApiPaths
-import de.fraunhofer.iem.dataprovider.logger.getLogger
-import de.fraunhofer.iem.dataprovider.taskManager.TaskManager
-import de.fraunhofer.iem.dataprovider.taskManager.events.RecalculateAllKpisEvent
-import org.springframework.web.bind.annotation.PostMapping
-import org.springframework.web.bind.annotation.RestController
-
-@RestController
-class MetricsController(
-    private val taskManager: TaskManager
-) {
-
-    private val logger = getLogger(javaClass)
-
-    @PostMapping(ApiPaths.DEBUG_RECALCULATE_KPIS)
-    suspend fun recalculateAllKPIs() {
-        logger.info("Recalculation of all KPIs was triggered")
-        taskManager.addEvent(RecalculateAllKpisEvent)
-    }
-}
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 e6a4f8f1..718e9071 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
@@ -4,6 +4,7 @@ import de.fraunhofer.iem.dataprovider.kpi.metrics.repositoryDetails.service.Repo
 import de.fraunhofer.iem.dataprovider.kpi.service.KPIService
 import de.fraunhofer.iem.dataprovider.repository.service.RepositoryService
 import de.fraunhofer.iem.dataprovider.toolRun.service.ToolRunService
+import de.fraunhofer.iem.dataprovider.tools.ort.service.OrtService
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.async
@@ -15,7 +16,8 @@ class MetricsService(
     private val repositoryService: RepositoryService,
     private val toolRunService: ToolRunService,
     private val repositoryDetailsService: RepositoryDetailsService,
-    private val kpiService: KPIService
+    private val kpiService: KPIService,
+    private val ortService: OrtService
 ) {
 
     private val defaultScope = CoroutineScope(Dispatchers.Default)
@@ -60,6 +62,11 @@ class MetricsService(
          * }
          */
 
+        val vulnerabilityKpis = async {
+            val vulnerabilityDtos = ortService.getOrtResults(repoId)
+            ortService.calculateVulnerabilityKpis(vulnerabilityDtos)
+        }
+
 
         val repositoryDetailsKpi = async {
             val repoDetailsDto = repositoryDetailsService.getRepositoryDetails(repoId)
@@ -71,7 +78,11 @@ class MetricsService(
          * joinAll(toolKpi)
          * calculateKpiTree(toolKpi, ...)
          */
-        kpiService.calculateAndSaveKpiTree(toolRun.repository!!, repositoryDetailsKpi.await())
+        kpiService.calculateAndSaveKpiTree(
+            repository = toolRun.repository!!,
+            repositoryDetailsKpi = repositoryDetailsKpi.await(),
+            vulnerabilityKpis = vulnerabilityKpis.await()
+        )
     }
 
 }
\ No newline at end of file
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 d304a0ec..63a5ee35 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
@@ -7,6 +7,7 @@ import de.fraunhofer.iem.dataprovider.kpi.metrics.repositoryDetails.dto.Reposito
 import de.fraunhofer.iem.dataprovider.kpi.repository.KPIHierarchyEdgeRepository
 import de.fraunhofer.iem.dataprovider.kpi.repository.KPIRepository
 import de.fraunhofer.iem.dataprovider.kpi.strategy.AggregationKPICalculationStrategy
+import de.fraunhofer.iem.dataprovider.kpi.strategy.MaximumKPICalculationStrategy
 import de.fraunhofer.iem.dataprovider.kpi.strategy.RatioKPICalculationStrategy
 import de.fraunhofer.iem.dataprovider.logger.getLogger
 import de.fraunhofer.iem.dataprovider.repository.entity.RepositoryEntity
@@ -22,14 +23,22 @@ class KPIService(
 
     private val logger = getLogger(javaClass)
 
-    fun calculateAndSaveKpiTree(repository: RepositoryEntity, repoDetailsEntity: RepositoryDetailsKpisDto) {
-        val rootKPI = generateKPITree(repoDetailsEntity)
+    fun calculateAndSaveKpiTree(
+        repository: RepositoryEntity,
+        repositoryDetailsKpi: RepositoryDetailsKpisDto,
+        vulnerabilityKpis: List<KPICreateDto>
+    ) {
+        val rootKPI =
+            generateKPITree(repositoryDetailsKpi = repositoryDetailsKpi, vulnerabilityKpis = vulnerabilityKpis)
         calculateKPIs(rootKPI)
         storeAndPurgeOld(repository, rootKPI)
     }
 
 
-    private fun generateKPITree(repoDetailsEntity: RepositoryDetailsKpisDto): KPICreateDto {
+    private fun generateKPITree(
+        repositoryDetailsKpi: RepositoryDetailsKpisDto,
+        vulnerabilityKpis: List<KPICreateDto>
+    ): KPICreateDto {
 
 
         val signedCommitsRatioKPI =
@@ -39,8 +48,8 @@ class KPIService(
                 false,
                 RatioKPICalculationStrategy()
             )
-        signedCommitsRatioKPI.addChildKPI(repoDetailsEntity.numberOfCommitsKpi, 1.0)
-        signedCommitsRatioKPI.addChildKPI(repoDetailsEntity.numberOfSignedCommitsKPI, 1.0)
+        signedCommitsRatioKPI.addChildKPI(repositoryDetailsKpi.numberOfCommitsKpi, 1.0)
+        signedCommitsRatioKPI.addChildKPI(repositoryDetailsKpi.numberOfSignedCommitsKPI, 1.0)
 
         val processComplianceKPI = KPICreateDto(
             "Process Compliance Score",
@@ -56,26 +65,28 @@ class KPIService(
             AggregationKPICalculationStrategy()
         )
 
-        processComplianceKPI.addChildKPI(repoDetailsEntity.isDefaultBranchProtectedKPI, 0.5)
+        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 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()
-//
+        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()
+        )
 
+        vulnerabilityKpis.forEach { maximalDependencyVulnerabilityKPI.addChildKPI(it, 0.0) }
+        securityKPI.addChildKPI(maximalDependencyVulnerabilityKPI, 0.5)
         //TODO: this code will be called from the dependency api request task !
 //        val dependencyDtos = dependencyService.getDependenciesForRepository(repoId)
 //        // We change the structure to associate vulnerabilities with dependencies instead of dependencies with vulnerabilities
@@ -104,7 +115,7 @@ class KPIService(
         )
         rootKPI.addChildKPI(processTransparencyKPI, 0.25)
         rootKPI.addChildKPI(processComplianceKPI, 0.25)
-//        rootKPI.addChildKPI(securityKPI, 0.5)
+        rootKPI.addChildKPI(securityKPI, 0.5)
         return rootKPI
     }
 
@@ -238,5 +249,4 @@ class KPIService(
         }
     }
 
-
 }
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/TaskManager.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/TaskManager.kt
deleted file mode 100644
index d4241779..00000000
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/TaskManager.kt
+++ /dev/null
@@ -1,173 +0,0 @@
-package de.fraunhofer.iem.dataprovider.taskManager
-
-import de.fraunhofer.iem.dataprovider.configuration.DirectoryPathsProperties
-import de.fraunhofer.iem.dataprovider.configuration.OpenCodeGitlabApiProperties
-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.taskManager.events.Event
-import de.fraunhofer.iem.dataprovider.tool.service.ToolService
-import de.fraunhofer.iem.dataprovider.toolRun.service.ToolRunService
-import jakarta.annotation.PostConstruct
-import jakarta.annotation.PreDestroy
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.launch
-import org.springframework.stereotype.Component
-
-
-/**
- * The Task Manager takes tasks and distributes them to
- * underlying workers. Internally it uses a channel
- * to manage incoming tasks.
- */
-@Component
-class TaskManager(
-    private val directoryPathsProperties: DirectoryPathsProperties,
-    private val openCodeGitlabConfiguration: OpenCodeGitlabApiProperties,
-    private val toolRunService: ToolRunService,
-    private val toolService: ToolService,
-    private val repositoryService: RepositoryService,
-    private val kpiService: KPIService,
-) {
-
-    // The used default dispatcher is ok for CPU-bound workloads. However,
-    // if they block for a long time it's better to use a custom thread
-    // pool solution.
-    private val worker = Worker("Worker")
-
-    // Should be used for long-running tasks, which DON'T use CPU power and
-    // are non-blocking
-    private val ioWorker = Worker("IO-Worker", CoroutineScope(Dispatchers.IO))
-
-    private val mainScope = CoroutineScope(Dispatchers.Default)
-    private val channel: Channel<Event> = Channel()
-
-    suspend fun addEvent(event: Event) {
-        channel.send(event)
-    }
-
-    @PostConstruct
-    private fun start() {
-        mainScope.launch {
-            for (task in channel) {
-                onReceive(task)
-            }
-        }
-    }
-
-    @PreDestroy
-    fun close() {
-        channel.close()
-        worker.close()
-        ioWorker.close()
-    }
-
-
-    private val logger = getLogger(javaClass)
-    private val groupTaskManager = GroupTaskManager(::onReceive)
-    suspend fun onReceive(event: Event) {
-        logger.info("[${Thread.currentThread().name}] add task called in Task Manager $event")
-//
-//        when (event) {
-//            is RepoChangedEvent -> {
-//                ioWorker.addTask(
-//                    GetGitlabProjectTask(
-//                        event.repoId,
-//                        openCodeGitlabConfiguration,
-//                        ::addEvent,
-//                        repositoryService,
-//                    )
-//                )
-//            }
-//
-//            is GetGitlabProjectDoneEvent -> {
-//                // TODO: we should replace the git clone task with the temporary OCCMD task, as only OCCMD
-//
-//                val groupId = groupTaskManager.createTaskGroup(event.repoId)
-//
-////                    val occmdTask = OccmdTask(
-////                        event.outputDirectory,
-////                        config.toolResultsTargetDirectory,
-////                        openCodeGitlabConfiguration,
-////                        repositoryService,
-////                        ::addEvent,
-////                        event.repoId,
-////                        groupId,
-////                        toolRunService
-////                    )
-//                ioWorker.addTask(
-//                    OrtApiTask(
-//                        ::addEvent,
-//                        event.repoId,
-//                        toolService,
-//                        repositoryService
-//                    )
-//                )
-//
-////                    groupTaskManager.addTaskToGroup(groupId, occmdTask.taskID)
-////
-////                    worker.addTask(occmdTask)
-//            }
-//
-//            is GroupTaskDoneEvent -> {
-//                logger.info("GroupTaskDoneEvent received")
-//                groupTaskManager.taskInGroupFinished(event.groupId, event.taskId)
-//            }
-//
-//            is GroupTasksDoneEvent -> {
-//                logger.info("Adding repository details task")
-//                worker.addTask(
-//                    GetRepositoryDetailsTask(
-//                        event.repoId,
-//                        openCodeGitlabConfiguration,
-//                        repositoryService,
-//                        ::addEvent
-//                    )
-//                )
-//            }
-//
-//            is GetRepositoryDetailsDoneEvent -> {
-//                worker.addTask(
-//                    MetricsTask(
-//                        event.repoId,
-//                        repositoryService,
-//                        kpiService,
-//                        ::addEvent,
-//                        toolRunService
-//                    )
-//                )
-//            }
-//
-//            is RecalculateAllKpisEvent -> {
-//                repositoryService.getAllRepositories().forEach { repo ->
-//                    worker.addTask(
-//                        MetricsTask(
-//                            repo.id!!,
-//                            repositoryService,
-//                            kpiService,
-//                            ::addEvent,
-//                            toolRunService
-//                        )
-//                    )
-//                }
-//            }
-//
-//            is TaskFailedEvent -> {
-//                logger.info("task failed event received. ${event.throwable}")
-//            }
-//
-//            is GroupTaskFailedEvent -> {
-//                logger.info("Group task failed event received. ${event.throwable} ")
-//                groupTaskManager.taskInGroupFinished(event.groupId, event.taskId)
-//            }
-//
-//            else -> {
-//                logger.info("Received event without special handling associated $event")
-//            }
-//        }
-        logger.info("[${Thread.currentThread().name}] add task finished in Task Manager $event")
-    }
-
-}
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/OrtApiTask.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/OrtApiTask.kt
index fad54c41..34ae9d41 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/OrtApiTask.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/OrtApiTask.kt
@@ -3,8 +3,8 @@ package de.fraunhofer.iem.dataprovider.taskManager.tasks.tools.ort
 import de.fraunhofer.iem.dataprovider.repository.service.RepositoryService
 import de.fraunhofer.iem.dataprovider.taskManager.events.Event
 import de.fraunhofer.iem.dataprovider.taskManager.tasks.Task
-import de.fraunhofer.iem.dataprovider.taskManager.tasks.tools.ort.json.OrtJson
 import de.fraunhofer.iem.dataprovider.tool.service.ToolService
+import de.fraunhofer.iem.dataprovider.tools.ort.json.OrtJson
 import io.ktor.client.*
 import io.ktor.client.call.*
 import io.ktor.client.engine.cio.*
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/dto/VulnerabilityDto.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/dto/VulnerabilityDto.kt
new file mode 100644
index 00000000..c26385a1
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/dto/VulnerabilityDto.kt
@@ -0,0 +1,3 @@
+package de.fraunhofer.iem.dataprovider.tools.ort.dto
+
+data class VulnerabilityDto(val cveIdentifier: String, val packageName: String, val severity: Double)
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/DataJson.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/DataJson.kt
similarity index 83%
rename from src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/DataJson.kt
rename to src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/DataJson.kt
index dd84fd5c..6f6ba58c 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/DataJson.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/DataJson.kt
@@ -1,4 +1,4 @@
-package de.fraunhofer.iem.dataprovider.taskManager.tasks.tools.ort.json
+package de.fraunhofer.iem.dataprovider.tools.ort.json
 
 
 import kotlinx.serialization.SerialName
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/OrtJson.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/OrtJson.kt
similarity index 76%
rename from src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/OrtJson.kt
rename to src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/OrtJson.kt
index 2b211ec2..1173032f 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/OrtJson.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/OrtJson.kt
@@ -1,4 +1,4 @@
-package de.fraunhofer.iem.dataprovider.taskManager.tasks.tools.ort.json
+package de.fraunhofer.iem.dataprovider.tools.ort.json
 
 
 import kotlinx.serialization.SerialName
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/ReferenceJson.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/ReferenceJson.kt
similarity index 80%
rename from src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/ReferenceJson.kt
rename to src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/ReferenceJson.kt
index 19e5af82..58d3bd7f 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/ReferenceJson.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/ReferenceJson.kt
@@ -1,4 +1,4 @@
-package de.fraunhofer.iem.dataprovider.taskManager.tasks.tools.ort.json
+package de.fraunhofer.iem.dataprovider.tools.ort.json
 
 
 import kotlinx.serialization.SerialName
diff --git a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/ResultJson.kt b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/ResultJson.kt
similarity index 89%
rename from src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/ResultJson.kt
rename to src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/ResultJson.kt
index f551be03..de0edba9 100644
--- a/src/main/kotlin/de/fraunhofer/iem/dataprovider/taskManager/tasks/tools/ort/json/ResultJson.kt
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/json/ResultJson.kt
@@ -1,4 +1,4 @@
-package de.fraunhofer.iem.dataprovider.taskManager.tasks.tools.ort.json
+package de.fraunhofer.iem.dataprovider.tools.ort.json
 
 
 import kotlinx.serialization.SerialName
@@ -24,4 +24,4 @@ data class ResultJson(
     val updatedAt: String?,
     @SerialName("version")
     val version: String?
-)
\ No newline at end of file
+)
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
new file mode 100644
index 00000000..1b446dd5
--- /dev/null
+++ b/src/main/kotlin/de/fraunhofer/iem/dataprovider/tools/ort/service/OrtService.kt
@@ -0,0 +1,62 @@
+package de.fraunhofer.iem.dataprovider.tools.ort.service
+
+import de.fraunhofer.iem.dataprovider.configuration.OpenCodeApiProperties
+import de.fraunhofer.iem.dataprovider.kpi.dto.KPICreateDto
+import de.fraunhofer.iem.dataprovider.kpi.strategy.RawValueKPICalculationStrategy
+import de.fraunhofer.iem.dataprovider.tools.ort.dto.VulnerabilityDto
+import de.fraunhofer.iem.dataprovider.tools.ort.json.OrtJson
+import io.ktor.client.*
+import io.ktor.client.call.*
+import io.ktor.client.engine.cio.*
+import io.ktor.client.plugins.contentnegotiation.*
+import io.ktor.client.request.*
+import io.ktor.client.statement.*
+import io.ktor.serialization.kotlinx.json.*
+import kotlinx.serialization.json.Json
+import org.springframework.stereotype.Service
+
+@Service
+class OrtService(private val openCodeApiProperties: OpenCodeApiProperties) {
+
+    val client = HttpClient(CIO) {
+        install(ContentNegotiation) {
+            json(
+                Json { ignoreUnknownKeys = true }
+            )
+        }
+    }
+
+    suspend fun getOrtResults(repoId: Long): List<VulnerabilityDto> {
+        val response: HttpResponse = client.get(getToolApiPath(repoId))
+        val ortJson = response.body<OrtJson>()
+        client.close()
+
+        if (ortJson.code == 200) {
+            return ortJson.result.mapNotNull {
+                if (it.cveId != null && it.packageName != null && it.severity != null) {
+                    VulnerabilityDto(it.cveId, it.packageName, it.severity)
+                } else {
+                    null
+                }
+            }
+        }
+        return emptyList()
+    }
+
+    fun calculateVulnerabilityKpis(vulnerabilityDtos: List<VulnerabilityDto>): List<KPICreateDto> {
+        return vulnerabilityDtos.map {
+            KPICreateDto(
+                "Vulnerability ${it.cveIdentifier}",
+                "Affected package: ${it.packageName}",
+                false,
+                RawValueKPICalculationStrategy((it.severity * 10).toInt()),
+                displayScore = it.severity.toString()
+            )
+        }
+    }
+
+    private fun getToolApiPath(repoId: Long): String {
+        return "${openCodeApiProperties.basePath}106${openCodeApiProperties.ort}"
+    }
+
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index b37ce441..7fbe091c 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,9 +1,11 @@
 spring.config.import=optional:classpath:.env[.properties]
-
 # Config for the OpencoDE platform
 # Token can be an empty string to access public repositories only
 opencode.host=https://gitlab.opencode.de/
 opencode.access-token=${OC_GL_APIKEY}
+# Tool APIs
+opencode.api.base-path=https://sl.dev.o4oe.de/api/v1/project/
+opencode.api.ort=/cve-result
 
 # DB Login data
 spring.datasource.url=jdbc:postgresql://${host}:26257/${DB_USER}?sslmode=${ssl_mode}&sslrootcert=${ca_crt}&sslcert=${ssl_cert}&sslkey=${ssl_key}
@@ -14,7 +16,6 @@ security.api-key=${API_KEY}
 security.admin-password=${ADMIN_PASSWORD}
 directories.git-clone-target-directory=${GIT_CLONE_TARGET_DIRECTORY}
 directories.tool-results-target-directory=${TOOL_RESULTS_TARGET_DIRECTORY}
-
 server.port=${PORT}
 # Generates db schema if it doesn't exist in db
 spring.jpa.generate-ddl=true
-- 
GitLab