Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions api/v1/mapping/src/commonMain/kotlin/ApiMappings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ import org.eclipse.apoapsis.ortserver.api.v1.model.ShortestDependencyPath as Api
import org.eclipse.apoapsis.ortserver.api.v1.model.SourceCodeOrigin as ApiSourceCodeOrigin
import org.eclipse.apoapsis.ortserver.api.v1.model.SubmoduleFetchStrategy as ApiSubmoduleFetchStrategy
import org.eclipse.apoapsis.ortserver.api.v1.model.User as ApiUser
import org.eclipse.apoapsis.ortserver.api.v1.model.UserDisplayName as ApiUserDisplayName
import org.eclipse.apoapsis.ortserver.api.v1.model.UserGroup as ApiUserGroup
import org.eclipse.apoapsis.ortserver.api.v1.model.VcsInfo as ApiVcsInfo
import org.eclipse.apoapsis.ortserver.api.v1.model.VcsInfoCurationData as ApiVcsInfoCurationData
Expand All @@ -93,6 +92,7 @@ import org.eclipse.apoapsis.ortserver.model.AdvisorJob
import org.eclipse.apoapsis.ortserver.model.AdvisorJobConfiguration
import org.eclipse.apoapsis.ortserver.model.AnalyzerJob
import org.eclipse.apoapsis.ortserver.model.AnalyzerJobConfiguration
import org.eclipse.apoapsis.ortserver.model.AppliedVulnerabilityResolution
import org.eclipse.apoapsis.ortserver.model.ContentManagementSection
import org.eclipse.apoapsis.ortserver.model.EcosystemStats
import org.eclipse.apoapsis.ortserver.model.EnvironmentConfig
Expand Down Expand Up @@ -126,7 +126,6 @@ import org.eclipse.apoapsis.ortserver.model.Severity
import org.eclipse.apoapsis.ortserver.model.SourceCodeOrigin
import org.eclipse.apoapsis.ortserver.model.SubmoduleFetchStrategy
import org.eclipse.apoapsis.ortserver.model.User
import org.eclipse.apoapsis.ortserver.model.UserDisplayName
import org.eclipse.apoapsis.ortserver.model.UserGroup
import org.eclipse.apoapsis.ortserver.model.VulnerabilityFilters
import org.eclipse.apoapsis.ortserver.model.VulnerabilityForRunsFilters
Expand Down Expand Up @@ -393,7 +392,9 @@ fun OrtRun.mapToApi(jobs: ApiJobs) =
resolvedJobConfigContext = resolvedJobConfigContext,
environmentConfigPath = environmentConfigPath,
traceId = traceId,
userDisplayName = userDisplayName?.mapToApi()
userDisplayName = userDisplayName?.mapToApi(),
outdated = outdated,
outdatedMessage = outdatedMessage
)

fun OrtRun.mapToApiSummary(jobs: ApiJobSummaries) =
Expand All @@ -414,7 +415,9 @@ fun OrtRun.mapToApiSummary(jobs: ApiJobSummaries) =
jobConfigContext = jobConfigContext,
resolvedJobConfigContext = resolvedJobConfigContext,
environmentConfigPath = environmentConfigPath,
userDisplayName = userDisplayName?.mapToApi()
userDisplayName = userDisplayName?.mapToApi(),
outdated = outdated,
outdatedMessage = outdatedMessage
)

fun OrtRunSummary.mapToApi() =
Expand Down Expand Up @@ -595,12 +598,21 @@ fun AdvisorDetails.mapToApi() = ApiAdvisorDetails(
capabilities = capabilities.map { ApiAdvisorCapability.valueOf(it.name) }.toSet()
)

fun AppliedVulnerabilityResolution.mapToApi() =
ApiVulnerabilityResolution(
externalId = resolution.externalId,
reason = resolution.reason,
comment = resolution.comment,
definition = definition?.mapToApi()
)

fun VulnerabilityWithDetails.mapToApi() =
ApiVulnerabilityWithDetails(
vulnerability = vulnerability.mapToApi(),
identifier = identifier.mapToApi(),
rating = rating.mapToApi(),
resolutions = resolutions.map { it.mapToApi() },
newMatchingResolutionDefinitions = newMatchingResolutionDefinitions.map { it.mapToApi() },
advisor = advisor.mapToApi(),
purl = purl
)
Expand Down Expand Up @@ -842,8 +854,6 @@ fun Project.mapToApi() = ApiProject(
scopeNames = scopeNames
)

fun UserDisplayName.mapToApi() = ApiUserDisplayName(username = username, fullName = fullName)

fun ContentManagementSection.mapToApi() = ApiContentManagementSection(
id = id,
isEnabled = isEnabled,
Expand Down
14 changes: 13 additions & 1 deletion api/v1/model/src/commonMain/kotlin/OrtRun.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ package org.eclipse.apoapsis.ortserver.api.v1.model
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable

import org.eclipse.apoapsis.ortserver.shared.apimodel.UserDisplayName

@Serializable
data class OrtRun(
/**
Expand Down Expand Up @@ -136,7 +138,17 @@ data class OrtRun(
/**
* The display name of the user that triggered the scan.
*/
val userDisplayName: UserDisplayName? = null
val userDisplayName: UserDisplayName? = null,

/**
* A flag to indicate if the results of the run are outdated, e.g. because of a new resolution.
*/
val outdated: Boolean = false,

/**
* A message describing why the results of the run are outdated.
*/
val outdatedMessage: String? = null
Comment on lines +143 to +151
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need both outdated and outdatedMessage? Theoretically, we could define that a run is outdated if outdatedMessage is non-null, and never allow outdatedMessage to be null for and outdated run (i.e. outdated runs always need to provide a message, which is probably good practice anyway).

On the other hand, being explicit with outdated also has its advantages, but complicates the logic a bit, I guess.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, this was something I was wondering about too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume there is a limited list of reasons why a run can get outdated so I would suggest to create an enum for that, then it could be outdated: List<OutdatedReason> with, for example, OutdatedReason.ISSUE_RESOLUTIONS_CHANGED.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What your opinion @mnonnenmacher about having both these properties?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No strong opinion but I have a tendency to only have one property with the list of reasons and if it is empty or null it means the run is not outdated.

)

/**
Expand Down
14 changes: 13 additions & 1 deletion api/v1/model/src/commonMain/kotlin/OrtRunSummary.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ package org.eclipse.apoapsis.ortserver.api.v1.model
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable

import org.eclipse.apoapsis.ortserver.shared.apimodel.UserDisplayName

/**
* The summary of an ORT run.
*/
Expand Down Expand Up @@ -116,7 +118,17 @@ data class OrtRunSummary(
/**
* The display name of the user that triggered this run.
*/
val userDisplayName: UserDisplayName? = null
val userDisplayName: UserDisplayName? = null,

/**
* A flag to indicate if the results of the run are outdated, e.g. because of a new resolution.
*/
val outdated: Boolean = false,

/**
* A message describing why the results of the run are outdated.
*/
val outdatedMessage: String? = null
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ package org.eclipse.apoapsis.ortserver.api.v1.model

import kotlinx.serialization.Serializable

import org.eclipse.apoapsis.ortserver.shared.apimodel.VulnerabilityResolutionDefinition

/**
* Defines the resolution of a Vulnerability. This can be used to silence false positives, or vulnerabilities that
* have been identified as not being relevant.
Expand All @@ -29,5 +31,8 @@ import kotlinx.serialization.Serializable
data class VulnerabilityResolution(
val externalId: String,
val reason: String,
val comment: String
val comment: String,

/** The definition of the [VulnerabilityResolution], if available. */
val definition: VulnerabilityResolutionDefinition? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ package org.eclipse.apoapsis.ortserver.api.v1.model

import kotlinx.serialization.Serializable

import org.eclipse.apoapsis.ortserver.shared.apimodel.VulnerabilityResolutionDefinition

/**
* A data class to gather information and related data about a [Vulnerability].
*/
Expand All @@ -34,6 +36,9 @@ data class VulnerabilityWithDetails(

val resolutions: List<VulnerabilityResolution> = emptyList(),

/** The resolution definitions that match this vulnerability but were not yet available during the run. */
val newMatchingResolutionDefinitions: List<VulnerabilityResolutionDefinition> = emptyList(),

/** Details of the used advisor. */
val advisor: AdvisorDetails,

Expand Down
45 changes: 45 additions & 0 deletions components/resolutions/api-model/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2025 The ORT Server Authors (See <https://github.com/eclipse-apoapsis/ort-server/blob/main/NOTICE>)
*
* 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
*/

plugins {
id("ort-server-kotlin-multiplatform-conventions")
id("ort-server-publication-conventions")

// Apply third-party plugins.
alias(libs.plugins.kotlinSerialization)
}

group = "org.eclipse.apoapsis.ortserver.components.resolutions"

kotlin {
linuxX64()
macosArm64()
macosX64()
mingwX64()

sourceSets {
commonMain {
dependencies {
api(projects.shared.apiModel)

implementation(libs.kotlinxSerializationJson)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2025 The ORT Server Authors (See <https://github.com/eclipse-apoapsis/ort-server/blob/main/NOTICE>)
*
* 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.components.resolutions

import kotlinx.serialization.Serializable

import org.eclipse.apoapsis.ortserver.shared.apimodel.OptionalValue
import org.eclipse.apoapsis.ortserver.shared.apimodel.VulnerabilityResolutionReason

/**
* The request object for updating a vulnerability resolution.
*/
@Serializable
data class PatchVulnerabilityResolution(
/**
* The list of vulnerability ID matchers (regular expressions) to match the ids of the vulnerabilities to resolve.
*/
val idMatchers: OptionalValue<List<String>> = OptionalValue.Absent,

/** The reason why the vulnerability is resolved. */
val reason: OptionalValue<VulnerabilityResolutionReason> = OptionalValue.Absent,

/** A comment to further explain why the [reason] is applicable here. */
val comment: OptionalValue<String> = OptionalValue.Absent
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2025 The ORT Server Authors (See <https://github.com/eclipse-apoapsis/ort-server/blob/main/NOTICE>)
*
* 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.components.resolutions

import kotlinx.serialization.Serializable

import org.eclipse.apoapsis.ortserver.shared.apimodel.VulnerabilityResolutionReason

/**
* The request object for creating a vulnerability resolution.
*/
@Serializable
data class PostVulnerabilityResolution(
/** The ID of the run in which context the vulnerability resolution is made in. */
val contextRunId: Long,

/**
* The list of vulnerability ID matchers (regular expressions) to match the ids of the vulnerabilities to resolve.
*/
val idMatchers: List<String>,

/** The reason why the vulnerability is resolved. */
val reason: VulnerabilityResolutionReason,

/** A comment to further explain why the [reason] is applicable here. */
val comment: String
)
59 changes: 59 additions & 0 deletions components/resolutions/backend/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2025 The ORT Server Authors (See <https://github.com/eclipse-apoapsis/ort-server/blob/main/NOTICE>)
*
* 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
*/

plugins {
id("ort-server-kotlin-component-backend-conventions")
id("ort-server-publication-conventions")
}

group = "org.eclipse.apoapsis.ortserver.components.resolutions"

dependencies {
api(projects.model)
api(projects.services.ortRunService)

api(libs.exposedCore)

implementation(projects.dao)

routesImplementation(projects.components.authorizationKeycloak.backend)
routesImplementation(projects.components.resolutions.apiModel)
routesImplementation(projects.shared.apiMappings)
routesImplementation(projects.shared.apiModel)
routesImplementation(projects.shared.ktorUtils)

routesImplementation(ktorLibs.http)
routesImplementation(ktorLibs.server.auth)
routesImplementation(ktorLibs.server.core)
routesImplementation(libs.kotlinxDatetime)
routesImplementation(libs.ktorOpenApi)

testImplementation(testFixtures(projects.dao))
testImplementation(testFixtures(projects.shared.ktorUtils))

testImplementation(ktorLibs.client.core)
testImplementation(ktorLibs.http)
testImplementation(ktorLibs.server.auth)
testImplementation(ktorLibs.server.core)
testImplementation(ktorLibs.server.testHost)
testImplementation(libs.kotestAssertionsCore)
testImplementation(libs.kotestAssertionsKtor)
testImplementation(libs.kotestFrameworkEngine)
testImplementation(libs.mockk)
}
Loading
Loading