From 39288bb6061d07675385b18e0369ae0a5d65ff49 Mon Sep 17 00:00:00 2001 From: Kamil Bielecki Date: Fri, 20 Sep 2024 09:30:53 +0200 Subject: [PATCH 1/4] feat(test): Add new identifier related fixture Signed-off-by: Kamil Bielecki --- dao/src/testFixtures/kotlin/Fixtures.kt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/dao/src/testFixtures/kotlin/Fixtures.kt b/dao/src/testFixtures/kotlin/Fixtures.kt index 6c9ce081a..8d49e0a62 100644 --- a/dao/src/testFixtures/kotlin/Fixtures.kt +++ b/dao/src/testFixtures/kotlin/Fixtures.kt @@ -53,6 +53,7 @@ import org.eclipse.apoapsis.ortserver.model.ReporterJobConfiguration import org.eclipse.apoapsis.ortserver.model.RepositoryType import org.eclipse.apoapsis.ortserver.model.ScannerJobConfiguration import org.eclipse.apoapsis.ortserver.model.Severity +import org.eclipse.apoapsis.ortserver.model.runs.Identifier import org.eclipse.apoapsis.ortserver.model.runs.OrtRuleViolation import org.jetbrains.exposed.sql.Database @@ -188,12 +189,19 @@ class Fixtures(private val db: Database) { return Jobs(analyzerJob, advisorJob, scannerJob, evaluatorJob, reporterJob, notifierJob) } - fun createIdentifier() = db.blockingQuery { + fun createIdentifier( + identifier: Identifier = Identifier( + "identifier_type", + "identifier_namespace", + "identifier_package", + "identifier_version" + ) + ): Identifier = db.blockingQuery { IdentifierDao.new { - type = "identifier_type" - namespace = "identifier_namespace" - name = "identifier_package" - version = "identifier_version" + type = identifier.type + namespace = identifier.namespace + name = identifier.name + version = identifier.version }.mapToModel() } From f096f896628e52125d95afede1dd28d7c47d2f11 Mon Sep 17 00:00:00 2001 From: Kamil Bielecki Date: Fri, 20 Sep 2024 09:32:52 +0200 Subject: [PATCH 2/4] feat(dao): Change RuleViolationDao entity inheritance Change RuleViolationDao to inherit from SortableTable to enable paging features. Signed-off-by: Kamil Bielecki --- .../kotlin/tables/runs/evaluator/RuleViolationsTable.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dao/src/main/kotlin/tables/runs/evaluator/RuleViolationsTable.kt b/dao/src/main/kotlin/tables/runs/evaluator/RuleViolationsTable.kt index 0adc0b272..528aa6978 100644 --- a/dao/src/main/kotlin/tables/runs/evaluator/RuleViolationsTable.kt +++ b/dao/src/main/kotlin/tables/runs/evaluator/RuleViolationsTable.kt @@ -21,19 +21,19 @@ package org.eclipse.apoapsis.ortserver.dao.tables.runs.evaluator import org.eclipse.apoapsis.ortserver.dao.tables.runs.shared.IdentifierDao import org.eclipse.apoapsis.ortserver.dao.tables.runs.shared.IdentifiersTable +import org.eclipse.apoapsis.ortserver.dao.utils.SortableEntityClass +import org.eclipse.apoapsis.ortserver.dao.utils.SortableTable import org.eclipse.apoapsis.ortserver.model.Severity import org.eclipse.apoapsis.ortserver.model.runs.OrtRuleViolation import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.LongIdTable import org.jetbrains.exposed.sql.and /** * A table to represent a rule violation. */ -object RuleViolationsTable : LongIdTable("rule_violations") { +object RuleViolationsTable : SortableTable("rule_violations") { val rule = text("rule") val packageIdentifierId = reference("package_identifier_id", IdentifiersTable).nullable() val license = text("license").nullable() @@ -44,7 +44,7 @@ object RuleViolationsTable : LongIdTable("rule_violations") { } class RuleViolationDao(id: EntityID) : LongEntity(id) { - companion object : LongEntityClass(RuleViolationsTable) { + companion object : SortableEntityClass(RuleViolationsTable) { fun getOrPut(ruleViolation: OrtRuleViolation): RuleViolationDao = findByRuleViolation(ruleViolation) ?: RuleViolationDao.new { rule = ruleViolation.rule From 594903e0160d70395b4409459d133354cc005c4f Mon Sep 17 00:00:00 2001 From: Kamil Bielecki Date: Fri, 20 Sep 2024 09:35:37 +0200 Subject: [PATCH 3/4] feat(service): Add RuleViolationService Add service for rule violations results with companion objects. Signed-off-by: Kamil Bielecki --- .../kotlin/RuleViolationWithIdentifier.kt | 31 ++++ .../kotlin/runs/OrtRuleViolation.kt | 3 + .../src/main/kotlin/RuleViolationService.kt | 68 ++++++++ .../test/kotlin/RuleViolationServiceTest.kt | 158 ++++++++++++++++++ 4 files changed, 260 insertions(+) create mode 100644 model/src/commonMain/kotlin/RuleViolationWithIdentifier.kt create mode 100644 services/hierarchy/src/main/kotlin/RuleViolationService.kt create mode 100644 services/hierarchy/src/test/kotlin/RuleViolationServiceTest.kt diff --git a/model/src/commonMain/kotlin/RuleViolationWithIdentifier.kt b/model/src/commonMain/kotlin/RuleViolationWithIdentifier.kt new file mode 100644 index 000000000..2ba37b803 --- /dev/null +++ b/model/src/commonMain/kotlin/RuleViolationWithIdentifier.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The ORT Server Authors (See ) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +package org.eclipse.apoapsis.ortserver.model + +import org.eclipse.apoapsis.ortserver.model.runs.Identifier +import org.eclipse.apoapsis.ortserver.model.runs.OrtRuleViolation + +/** + * A union data class to associate a [OrtRuleViolation] with an [Identifier]. + */ +data class RuleViolationWithIdentifier( + val ruleViolation: OrtRuleViolation, + val identifier: Identifier, +) diff --git a/model/src/commonMain/kotlin/runs/OrtRuleViolation.kt b/model/src/commonMain/kotlin/runs/OrtRuleViolation.kt index 838f189ee..e565133b5 100644 --- a/model/src/commonMain/kotlin/runs/OrtRuleViolation.kt +++ b/model/src/commonMain/kotlin/runs/OrtRuleViolation.kt @@ -23,6 +23,9 @@ import kotlinx.serialization.Serializable import org.eclipse.apoapsis.ortserver.model.Severity +/** + * A data class describing an rule violation that occurred during an ORT run. + */ @Serializable data class OrtRuleViolation( val rule: String, diff --git a/services/hierarchy/src/main/kotlin/RuleViolationService.kt b/services/hierarchy/src/main/kotlin/RuleViolationService.kt new file mode 100644 index 000000000..351d13f27 --- /dev/null +++ b/services/hierarchy/src/main/kotlin/RuleViolationService.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2024 The ORT Server Authors (See ) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +package org.eclipse.apoapsis.ortserver.services + +import org.eclipse.apoapsis.ortserver.dao.dbQuery +import org.eclipse.apoapsis.ortserver.dao.tables.EvaluatorJobsTable +import org.eclipse.apoapsis.ortserver.dao.tables.runs.evaluator.EvaluatorRunsRuleViolationsTable +import org.eclipse.apoapsis.ortserver.dao.tables.runs.evaluator.EvaluatorRunsTable +import org.eclipse.apoapsis.ortserver.dao.tables.runs.evaluator.RuleViolationDao +import org.eclipse.apoapsis.ortserver.dao.tables.runs.evaluator.RuleViolationsTable +import org.eclipse.apoapsis.ortserver.dao.tables.runs.shared.IdentifierDao +import org.eclipse.apoapsis.ortserver.dao.tables.runs.shared.IdentifiersTable +import org.eclipse.apoapsis.ortserver.dao.utils.listCustomQuery +import org.eclipse.apoapsis.ortserver.model.RuleViolationWithIdentifier +import org.eclipse.apoapsis.ortserver.model.util.ListQueryParameters +import org.eclipse.apoapsis.ortserver.model.util.ListQueryResult + +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.ResultRow + +/** + * A service to interact with rule violations. + */ +class RuleViolationService(private val db: Database) { + suspend fun listForOrtRunId( + ortRunId: Long, + parameters: ListQueryParameters = ListQueryParameters.DEFAULT + ): ListQueryResult = db.dbQuery { + val ruleViolationQueryResult = + RuleViolationDao.listCustomQuery(parameters, ResultRow::toRuleViolation) { + val join = RuleViolationsTable innerJoin + EvaluatorRunsRuleViolationsTable innerJoin + EvaluatorRunsTable innerJoin + EvaluatorJobsTable innerJoin + IdentifiersTable + + join.select( + RuleViolationsTable.columns + IdentifiersTable.columns + ).where { EvaluatorJobsTable.ortRunId eq ortRunId } + } + + ListQueryResult(ruleViolationQueryResult.data, parameters, ruleViolationQueryResult.totalCount) + } +} + +private fun ResultRow.toRuleViolation(): RuleViolationWithIdentifier { + return RuleViolationWithIdentifier( + RuleViolationDao.wrapRow(this).mapToModel(), + IdentifierDao.wrapRow(this).mapToModel() + ) +} diff --git a/services/hierarchy/src/test/kotlin/RuleViolationServiceTest.kt b/services/hierarchy/src/test/kotlin/RuleViolationServiceTest.kt new file mode 100644 index 000000000..65855f82c --- /dev/null +++ b/services/hierarchy/src/test/kotlin/RuleViolationServiceTest.kt @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2024 The ORT Server Authors (See ) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +package org.eclipse.apoapsis.ortserver.services + +import io.kotest.core.spec.style.WordSpec +import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.shouldBe + +import kotlinx.datetime.Clock + +import org.eclipse.apoapsis.ortserver.dao.test.DatabaseTestExtension +import org.eclipse.apoapsis.ortserver.dao.test.Fixtures +import org.eclipse.apoapsis.ortserver.dao.utils.toDatabasePrecision +import org.eclipse.apoapsis.ortserver.model.EvaluatorJobConfiguration +import org.eclipse.apoapsis.ortserver.model.JobConfigurations +import org.eclipse.apoapsis.ortserver.model.OrtRun +import org.eclipse.apoapsis.ortserver.model.Severity +import org.eclipse.apoapsis.ortserver.model.runs.Identifier +import org.eclipse.apoapsis.ortserver.model.runs.OrtRuleViolation + +import org.jetbrains.exposed.sql.Database + +class RuleViolationServiceTest : WordSpec() { + + private val dbExtension = extension(DatabaseTestExtension()) + + private lateinit var db: Database + private lateinit var fixtures: Fixtures + + init { + beforeEach { + db = dbExtension.db + fixtures = dbExtension.fixtures + } + + "listForOrtRunId" should { + "return the rule violations for the given ORT run ID" { + val service = RuleViolationService(db) + val ortRun = createRuleViolationEntries() + val results = service.listForOrtRunId(ortRun.id).data + + results shouldHaveSize 2 + + with(results[0]) { + with(ruleViolation) { + rule shouldBe "Rule-1" + license shouldBe "License-1" + licenseSource shouldBe "CONCLUDED" + severity shouldBe Severity.WARNING + message shouldBe "Message-1" + howToFix shouldBe "How_to_fix-1" + } + + with(identifier) { + type shouldBe "Maven" + namespace shouldBe "org.apache.logging.log4j" + name shouldBe "log4j-core" + version shouldBe "2.14.0" + } + } + + with(results[1]) { + with(ruleViolation) { + rule shouldBe "Rule-2" + license shouldBe "License-2" + licenseSource shouldBe "DETECTED" + severity shouldBe Severity.ERROR + message shouldBe "Message-2" + howToFix shouldBe "How_to_fix-2" + } + + with(identifier) { + type shouldBe "Maven" + namespace shouldBe "com.fasterxml.jackson.core" + name shouldBe "jackson-databind" + version shouldBe "2.9.6" + } + } + } + } + } + + private fun generateRuleViolations(): List = + listOf( + OrtRuleViolation( + "Rule-1", + Identifier( + "Maven", + "org.apache.logging.log4j", + "log4j-core", + "2.14.0" + ), + "License-1", + "CONCLUDED", + Severity.WARNING, + "Message-1", + "How_to_fix-1" + ), + OrtRuleViolation( + "Rule-2", + Identifier( + "Maven", + "com.fasterxml.jackson.core", + "jackson-databind", + "2.9.6" + ), + "License-2", + "DETECTED", + Severity.ERROR, + "Message-2", + "How_to_fix-2" + ) + ) + + private fun createRuleViolationEntries(): OrtRun { + val repository = fixtures.createRepository() + + val ortRun = fixtures.createOrtRun( + repositoryId = repository.id, + revision = "revision", + jobConfigurations = JobConfigurations() + ) + + val evaluatorJob = fixtures.createEvaluatorJob( + ortRunId = ortRun.id, + configuration = EvaluatorJobConfiguration() + ) + + val ruleViolations = this.generateRuleViolations() + ruleViolations.forEach { it.packageId?.let { identifier -> fixtures.createIdentifier(identifier) } } + + fixtures.evaluatorRunRepository.create( + evaluatorJobId = evaluatorJob.id, + startTime = Clock.System.now().toDatabasePrecision(), + endTime = Clock.System.now().toDatabasePrecision(), + violations = ruleViolations + ) + + return ortRun + } +} From 4bb24dab4aef283f3a9d595ec9260925427c1ac6 Mon Sep 17 00:00:00 2001 From: Kamil Bielecki Date: Fri, 20 Sep 2024 09:37:37 +0200 Subject: [PATCH 4/4] feat(service): Add RuleViolationAPI Add API endpoint for rule violations list under /runs/{run_id}/rule-violations. Signed-off-by: Kamil Bielecki --- .../mapping/src/commonMain/kotlin/Mappings.kt | 18 +++++ .../src/commonMain/kotlin/RuleViolation.kt | 32 ++++++++ .../kotlin/RuleViolationWithIdentifier.kt | 28 +++++++ core/src/main/kotlin/api/RunsRoute.kt | 21 ++++++ core/src/main/kotlin/apiDocs/RunsDocs.kt | 73 +++++++++++++++++++ 5 files changed, 172 insertions(+) create mode 100644 api/v1/model/src/commonMain/kotlin/RuleViolation.kt create mode 100644 api/v1/model/src/commonMain/kotlin/RuleViolationWithIdentifier.kt diff --git a/api/v1/mapping/src/commonMain/kotlin/Mappings.kt b/api/v1/mapping/src/commonMain/kotlin/Mappings.kt index 14c1ded85..d444eaff9 100644 --- a/api/v1/mapping/src/commonMain/kotlin/Mappings.kt +++ b/api/v1/mapping/src/commonMain/kotlin/Mappings.kt @@ -67,6 +67,8 @@ import org.eclipse.apoapsis.ortserver.api.v1.model.ReporterJob as ApiReporterJob import org.eclipse.apoapsis.ortserver.api.v1.model.ReporterJobConfiguration as ApiReporterJobConfiguration import org.eclipse.apoapsis.ortserver.api.v1.model.Repository as ApiRepository import org.eclipse.apoapsis.ortserver.api.v1.model.RepositoryType as ApiRepositoryType +import org.eclipse.apoapsis.ortserver.api.v1.model.RuleViolation as ApiRuleViolation +import org.eclipse.apoapsis.ortserver.api.v1.model.RuleViolationWithIdentifier as ApiRuleViolationWithIdentifier import org.eclipse.apoapsis.ortserver.api.v1.model.ScannerJob as ApiScannerJob import org.eclipse.apoapsis.ortserver.api.v1.model.ScannerJobConfiguration as ApiScannerJobConfiguration import org.eclipse.apoapsis.ortserver.api.v1.model.Secret as ApiSecret @@ -110,6 +112,7 @@ import org.eclipse.apoapsis.ortserver.model.ReporterJob import org.eclipse.apoapsis.ortserver.model.ReporterJobConfiguration import org.eclipse.apoapsis.ortserver.model.Repository import org.eclipse.apoapsis.ortserver.model.RepositoryType +import org.eclipse.apoapsis.ortserver.model.RuleViolationWithIdentifier import org.eclipse.apoapsis.ortserver.model.ScannerJob import org.eclipse.apoapsis.ortserver.model.ScannerJobConfiguration import org.eclipse.apoapsis.ortserver.model.Secret @@ -118,6 +121,7 @@ import org.eclipse.apoapsis.ortserver.model.SourceCodeOrigin import org.eclipse.apoapsis.ortserver.model.VulnerabilityWithIdentifier import org.eclipse.apoapsis.ortserver.model.runs.Identifier import org.eclipse.apoapsis.ortserver.model.runs.Issue +import org.eclipse.apoapsis.ortserver.model.runs.OrtRuleViolation import org.eclipse.apoapsis.ortserver.model.runs.Package import org.eclipse.apoapsis.ortserver.model.runs.PackageManagerConfiguration import org.eclipse.apoapsis.ortserver.model.runs.ProcessedDeclaredLicense @@ -481,6 +485,20 @@ fun VulnerabilityWithIdentifier.mapToApi() = fun Vulnerability.mapToApi() = ApiVulnerability(externalId, summary, description, references.map { it.mapToApi() }) +fun RuleViolationWithIdentifier.mapToApi() = ApiRuleViolationWithIdentifier( + ruleViolation.mapToApi(), + identifier.mapToApi() +) + +fun OrtRuleViolation.mapToApi() = ApiRuleViolation( + rule, + license, + licenseSource, + severity.mapToApi(), + message, + howToFix +) + fun Identifier.mapToApi() = ApiIdentifier(type, namespace, name, version) fun VulnerabilityReference.mapToApi() = ApiVulnerabilityReference(url, scoringSystem, severity, score, vector) diff --git a/api/v1/model/src/commonMain/kotlin/RuleViolation.kt b/api/v1/model/src/commonMain/kotlin/RuleViolation.kt new file mode 100644 index 000000000..928df6739 --- /dev/null +++ b/api/v1/model/src/commonMain/kotlin/RuleViolation.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The ORT Server Authors (See ) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +package org.eclipse.apoapsis.ortserver.api.v1.model + +import kotlinx.serialization.Serializable + +@Serializable +data class RuleViolation( + val rule: String, + val license: String?, + val licenseSource: String?, + val severity: Severity, + val message: String, + val howToFix: String +) diff --git a/api/v1/model/src/commonMain/kotlin/RuleViolationWithIdentifier.kt b/api/v1/model/src/commonMain/kotlin/RuleViolationWithIdentifier.kt new file mode 100644 index 000000000..924410c36 --- /dev/null +++ b/api/v1/model/src/commonMain/kotlin/RuleViolationWithIdentifier.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 The ORT Server Authors (See ) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +package org.eclipse.apoapsis.ortserver.api.v1.model + +import kotlinx.serialization.Serializable + +@Serializable +data class RuleViolationWithIdentifier( + val ruleViolation: RuleViolation, + val identifier: Identifier +) diff --git a/core/src/main/kotlin/api/RunsRoute.kt b/core/src/main/kotlin/api/RunsRoute.kt index b62c54dea..fc83e3636 100644 --- a/core/src/main/kotlin/api/RunsRoute.kt +++ b/core/src/main/kotlin/api/RunsRoute.kt @@ -44,6 +44,7 @@ import org.eclipse.apoapsis.ortserver.core.apiDocs.getLogsByRunId import org.eclipse.apoapsis.ortserver.core.apiDocs.getOrtRunById import org.eclipse.apoapsis.ortserver.core.apiDocs.getPackagesByRunId import org.eclipse.apoapsis.ortserver.core.apiDocs.getReportByRunIdAndFileName +import org.eclipse.apoapsis.ortserver.core.apiDocs.getRuleViolationsByRunId import org.eclipse.apoapsis.ortserver.core.apiDocs.getVulnerabilitiesByRunId import org.eclipse.apoapsis.ortserver.core.authorization.requirePermission import org.eclipse.apoapsis.ortserver.core.utils.pagingOptions @@ -55,6 +56,7 @@ import org.eclipse.apoapsis.ortserver.logaccess.LogLevel import org.eclipse.apoapsis.ortserver.logaccess.LogSource import org.eclipse.apoapsis.ortserver.model.IssueWithIdentifier import org.eclipse.apoapsis.ortserver.model.OrtRun +import org.eclipse.apoapsis.ortserver.model.RuleViolationWithIdentifier import org.eclipse.apoapsis.ortserver.model.VulnerabilityWithIdentifier import org.eclipse.apoapsis.ortserver.model.authorization.RepositoryPermission import org.eclipse.apoapsis.ortserver.model.repositories.OrtRunRepository @@ -63,6 +65,7 @@ import org.eclipse.apoapsis.ortserver.services.IssueService import org.eclipse.apoapsis.ortserver.services.PackageService import org.eclipse.apoapsis.ortserver.services.ReportStorageService import org.eclipse.apoapsis.ortserver.services.RepositoryService +import org.eclipse.apoapsis.ortserver.services.RuleViolationService import org.eclipse.apoapsis.ortserver.services.VulnerabilityService import org.koin.ktor.ext.inject @@ -75,6 +78,7 @@ fun Route.runs() = route("runs/{runId}") { val ortRunRepository by inject() val repositoryService by inject() val vulnerabilityService by inject() + val ruleViolationService by inject() val packageService by inject() get(getOrtRunById) { _ -> @@ -152,6 +156,23 @@ fun Route.runs() = route("runs/{runId}") { } } + route("rule-violations") { + get(getRuleViolationsByRunId) { + call.forRun(ortRunRepository) { ortRun -> + requirePermission(RepositoryPermission.READ_ORT_RUNS.roleName(ortRun.repositoryId)) + + val pagingOptions = call.pagingOptions(SortProperty("external_id", SortDirection.ASCENDING)) + + val ruleViolationsForOrtRun = + ruleViolationService.listForOrtRunId(ortRun.id, pagingOptions.mapToModel()) + + val pagedResponse = ruleViolationsForOrtRun.mapToApi(RuleViolationWithIdentifier::mapToApi) + + call.respond(HttpStatusCode.OK, pagedResponse) + } + } + } + route("packages") { get(getPackagesByRunId) { call.forRun(ortRunRepository) { ortRun -> diff --git a/core/src/main/kotlin/apiDocs/RunsDocs.kt b/core/src/main/kotlin/apiDocs/RunsDocs.kt index 416a07a5c..84b4c9b3d 100644 --- a/core/src/main/kotlin/apiDocs/RunsDocs.kt +++ b/core/src/main/kotlin/apiDocs/RunsDocs.kt @@ -36,6 +36,8 @@ import org.eclipse.apoapsis.ortserver.api.v1.model.PagedResponse import org.eclipse.apoapsis.ortserver.api.v1.model.PagingData import org.eclipse.apoapsis.ortserver.api.v1.model.ProcessedDeclaredLicense import org.eclipse.apoapsis.ortserver.api.v1.model.RemoteArtifact +import org.eclipse.apoapsis.ortserver.api.v1.model.RuleViolation +import org.eclipse.apoapsis.ortserver.api.v1.model.RuleViolationWithIdentifier import org.eclipse.apoapsis.ortserver.api.v1.model.Severity import org.eclipse.apoapsis.ortserver.api.v1.model.SortDirection import org.eclipse.apoapsis.ortserver.api.v1.model.SortProperty @@ -252,6 +254,77 @@ val getVulnerabilitiesByRunId: OpenApiRoute.() -> Unit = { } } +val getRuleViolationsByRunId: OpenApiRoute.() -> Unit = { + operationId = "GetRuleViolationsByRunId" + summary = "Get the rules violations found in an ORT run." + tags = listOf("RuleViolations") + + request { + pathParameter("runId") { + description = "The ID of the ORT run." + } + + standardListQueryParameters() + } + + response { + HttpStatusCode.OK to { + description = "Success." + jsonBody> { + example("Get vulnerabilities for an ORT run") { + value = PagedResponse( + listOf( + RuleViolationWithIdentifier( + RuleViolation( + "Unmapped declared license found", + "GPL-1.0-or-later", + "DETECTED", + Severity.ERROR, + "The declared license 'LPGL-2.1' could not be mapped to a valid SPDX expression.", + """ + |Please add a declared license mapping via a curation for package + |'SpdxDocumentFile::hal:7.70.0'. + |If this is a false-positive or ineffective finding, it can be fixed in your + |`.ort.yml` file: + |```yaml + |--- + |curations: + | packages: + | - id: \"SpdxDocumentFile::hal:7.70.0\" + | curations: + | comment: \"\" + | declared_license_mapping: + | LPGL-2.1: + |``` + |Documentation in how to configure curations in the `.ort.yml` file can be found + |[here](https://oss-review-toolkit.org/ort/docs/configuration/ort-yml). + """.trimMargin() + ), + Identifier( + "Maven", + "org.glassfish.jersey.media", + "jersey-media-jaxb", + "2.42" + ) + ) + ), + PagingData( + limit = 20, + offset = 0, + totalCount = 1, + sortProperties = listOf(SortProperty("packageUrl", SortDirection.ASCENDING)) + ) + ) + } + } + } + + HttpStatusCode.NotFound to { + description = "The ORT run does not exist." + } + } +} + val getPackagesByRunId: OpenApiRoute.() -> Unit = { operationId = "GetPackagesByRunId" summary = "Get the packages found in an ORT run."