diff --git a/api/v1/mapping/src/commonMain/kotlin/Mappings.kt b/api/v1/mapping/src/commonMain/kotlin/Mappings.kt index 20fc6d21ac..771c92f960 100644 --- a/api/v1/mapping/src/commonMain/kotlin/Mappings.kt +++ b/api/v1/mapping/src/commonMain/kotlin/Mappings.kt @@ -66,6 +66,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 @@ -108,6 +110,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 @@ -123,6 +126,7 @@ import org.eclipse.apoapsis.ortserver.model.runs.RemoteArtifact import org.eclipse.apoapsis.ortserver.model.runs.VcsInfo import org.eclipse.apoapsis.ortserver.model.runs.advisor.Vulnerability import org.eclipse.apoapsis.ortserver.model.runs.advisor.VulnerabilityReference +import org.eclipse.apoapsis.ortserver.model.runs.evaluator.RuleViolation import org.eclipse.apoapsis.ortserver.model.util.ListQueryParameters import org.eclipse.apoapsis.ortserver.model.util.ListQueryResult import org.eclipse.apoapsis.ortserver.model.util.OptionalValue @@ -477,6 +481,20 @@ fun VulnerabilityWithIdentifier.mapToApi() = fun Vulnerability.mapToApi() = ApiVulnerability(externalId, summary, description, references.map { it.mapToApi() }) +fun RuleViolationWithIdentifier.mapToApi() = ApiRuleViolationWithIdentifier( + ruleViolation.mapToApi(), + identifier.mapToApi() +) + +fun RuleViolation.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 0000000000..928df6739e --- /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 0000000000..924410c36d --- /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 0f40b0478f..5334e564e2 100644 --- a/core/src/main/kotlin/api/RunsRoute.kt +++ b/core/src/main/kotlin/api/RunsRoute.kt @@ -43,6 +43,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 @@ -53,6 +54,7 @@ import org.eclipse.apoapsis.ortserver.logaccess.LogFileService import org.eclipse.apoapsis.ortserver.logaccess.LogLevel import org.eclipse.apoapsis.ortserver.logaccess.LogSource 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 @@ -60,6 +62,7 @@ import org.eclipse.apoapsis.ortserver.model.runs.Package 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 @@ -71,6 +74,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) { _ -> @@ -132,6 +136,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 b64fe3fff9..846cd277d5 100644 --- a/core/src/main/kotlin/apiDocs/RunsDocs.kt +++ b/core/src/main/kotlin/apiDocs/RunsDocs.kt @@ -34,6 +34,9 @@ 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 import org.eclipse.apoapsis.ortserver.api.v1.model.VcsInfo @@ -205,6 +208,89 @@ 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( + "OCaaS Policy C1 Strict Copyleft", + "GPL-1.0-or-later", + "DETECTED", + Severity.ERROR, + "License GPL-1.0-or-later found for package 'Maven:org.glassfish.jersey." + + "media:jersey-media-jaxb:2.42' is categorized as strict-copyleft which " + + "must not be used for BT05 Client application applications.", + "Find more information about the [strict-copyleft](https://inside-" + + "docupedia.bosch.com/confluence/x/2gNahg) and the [strict-copyleft-with-saas]" + + "(https://inside-docupedia.bosch.com/confluence/x/4ANahg) categories.\n" + + "Information about this policy and how to fix this issue can be found " + + "[here](https://inside-docupedia.bosch.com/confluence/x/pdOXc).\n\n" + + "If this is a false-positive or ineffective finding, it can be fixed in your " + + "`.ort.yml` file:\n\n" + + "```yaml\n" + + "---\n" + + "package_configurations:\n" + + "- id: \"Maven:org.glassfish.jersey.media:jersey-media-jaxb:2.42\"\n" + + " source_artifact_url: \"https://repo.maven.apache.org/maven2/org/glassfish/" + + "jersey/media/jersey-media-jaxb/2.42/jersey-media-jaxb-2.42-sources.jar\"\n" + + " license_finding_curations:\n" + + " - path: \"META-INF/NOTICE.md\"\n" + + " start_lines: \"84\"\n" + + " line_count: 1\n" + + " detected_license: \"GPL-1.0-or-later\"\n" + + " concluded_license: \n" + + " reason: \n" + + " comment: \"\"\n" + + "\n" + + "```\n" + + "Documentation how to configure package configurations in the `.ort.yml` " + + "file can be found\n" + + "[here](https://oss-review-toolkit.org/ort/docs/configuration/ort-yml" + + "#curating-project-license-findings)." + ), + 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."