Skip to content

Commit 43a7d27

Browse files
committed
feat(dao): Inject vulnerability resolutions to repository configuration
Inject vulnerability resolutions that have been made for the repository on the server into the repository configuration. Also save the connection between the vulnerability resolution definition and the repository configuration in order to be able to connect the applied resolution to the definition in a later phase when returning vulnerabilities for a run. Relates to #1009. Signed-off-by: Johanna Lamppu <[email protected]>
1 parent 0b9c1f3 commit 43a7d27

File tree

5 files changed

+151
-3
lines changed

5 files changed

+151
-3
lines changed

dao/src/main/kotlin/repositories/repositoryconfiguration/DaoRepositoryConfigurationRepository.kt

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.eclipse.apoapsis.ortserver.dao.blockingQuery
2323
import org.eclipse.apoapsis.ortserver.dao.entityQuery
2424
import org.eclipse.apoapsis.ortserver.dao.mapAndDeduplicate
2525
import org.eclipse.apoapsis.ortserver.dao.repositories.ortrun.OrtRunDao
26+
import org.eclipse.apoapsis.ortserver.dao.tables.VulnerabilityResolutionDefinitionsTable
2627
import org.eclipse.apoapsis.ortserver.dao.tables.shared.IdentifierDao
2728
import org.eclipse.apoapsis.ortserver.model.repositories.RepositoryConfigurationRepository
2829
import org.eclipse.apoapsis.ortserver.model.runs.repository.Curations
@@ -36,8 +37,12 @@ import org.eclipse.apoapsis.ortserver.model.runs.repository.ProvenanceSnippetCho
3637
import org.eclipse.apoapsis.ortserver.model.runs.repository.RepositoryAnalyzerConfiguration
3738
import org.eclipse.apoapsis.ortserver.model.runs.repository.RepositoryConfiguration
3839
import org.eclipse.apoapsis.ortserver.model.runs.repository.Resolutions
40+
import org.eclipse.apoapsis.ortserver.model.runs.repository.VulnerabilityResolution
3941

4042
import org.jetbrains.exposed.sql.Database
43+
import org.jetbrains.exposed.sql.SizedCollection
44+
import org.jetbrains.exposed.sql.SizedIterable
45+
import org.jetbrains.exposed.sql.and
4146

4247
/**
4348
* An implementation of [RepositoryConfigurationRepository] that stores repository configurations in
@@ -55,7 +60,38 @@ class DaoRepositoryConfigurationRepository(private val db: Database) : Repositor
5560
licenseChoices: LicenseChoices,
5661
provenanceSnippetChoices: List<ProvenanceSnippetChoices>
5762
): RepositoryConfiguration = db.blockingQuery {
58-
RepositoryConfigurationDao.new {
63+
val ortRun = OrtRunDao[ortRunId].mapToModel()
64+
val vulnerabilityResolutions = mapAndDeduplicate(
65+
resolutions.vulnerabilities,
66+
VulnerabilityResolutionDao::getOrPut
67+
)
68+
69+
val idToVulnerabilityResolutionDaos = VulnerabilityResolutionDefinitionsTable
70+
.select(VulnerabilityResolutionDefinitionsTable.columns)
71+
.where {
72+
(VulnerabilityResolutionDefinitionsTable.repositoryId eq ortRun.repositoryId) and
73+
(VulnerabilityResolutionDefinitionsTable.archived eq false)
74+
}
75+
.associateBy({ row -> row[VulnerabilityResolutionDefinitionsTable.id].value }, { row ->
76+
row[VulnerabilityResolutionDefinitionsTable.idMatchers].map { idMatcher ->
77+
VulnerabilityResolutionDao.getOrPut(
78+
VulnerabilityResolution(
79+
idMatcher,
80+
row[VulnerabilityResolutionDefinitionsTable.reason],
81+
row[VulnerabilityResolutionDefinitionsTable.comment]
82+
)
83+
)
84+
}
85+
})
86+
87+
val combinedVulnerabilityResolutions: SizedIterable<VulnerabilityResolutionDao> = SizedCollection(
88+
buildList {
89+
addAll(vulnerabilityResolutions.toList())
90+
addAll(idToVulnerabilityResolutionDaos.values.flatten())
91+
}.distinctBy { it.id.value }
92+
)
93+
94+
val repositoryConfiguration = RepositoryConfigurationDao.new {
5995
this.ortRun = OrtRunDao[ortRunId]
6096
this.repositoryAnalyzerConfiguration = analyzerConfig?.let {
6197
RepositoryAnalyzerConfigurationDao.getOrPut(it)
@@ -66,8 +102,7 @@ class DaoRepositoryConfigurationRepository(private val db: Database) : Repositor
66102
this.issueResolutions = mapAndDeduplicate(resolutions.issues, IssueResolutionDao::getOrPut)
67103
this.ruleViolationResolutions =
68104
mapAndDeduplicate(resolutions.ruleViolations, RuleViolationResolutionDao::getOrPut)
69-
this.vulnerabilityResolutions =
70-
mapAndDeduplicate(resolutions.vulnerabilities, VulnerabilityResolutionDao::getOrPut)
105+
this.vulnerabilityResolutions = combinedVulnerabilityResolutions
71106
this.curations = mapAndDeduplicate(curations.packages, ::createPackageCuration)
72107
this.licenseFindingCurations =
73108
mapAndDeduplicate(curations.licenseFindings, LicenseFindingCurationDao::getOrPut)
@@ -78,6 +113,19 @@ class DaoRepositoryConfigurationRepository(private val db: Database) : Repositor
78113
mapAndDeduplicate(licenseChoices.packageLicenseChoices, ::createPackageLicenseChoice)
79114
this.provenanceSnippetChoices = mapAndDeduplicate(provenanceSnippetChoices, SnippetChoicesDao::getOrPut)
80115
}.mapToModel()
116+
117+
idToVulnerabilityResolutionDaos.forEach {
118+
(vulnerabilityResolutionDefinitionId, vulnerabilityResolutionDaoList) ->
119+
vulnerabilityResolutionDaoList.forEach {
120+
RepositoryConfigurationsVulnerabilityResolutionsTable.addDefinitionId(
121+
repositoryConfiguration.id,
122+
it.id.value,
123+
vulnerabilityResolutionDefinitionId
124+
)
125+
}
126+
}
127+
128+
repositoryConfiguration
81129
}
82130

83131
override fun get(id: Long): RepositoryConfiguration? = db.entityQuery {

dao/src/main/kotlin/repositories/repositoryconfiguration/RepositoryConfigurationsVulnerabilityResolutionsTable.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919

2020
package org.eclipse.apoapsis.ortserver.dao.repositories.repositoryconfiguration
2121

22+
import org.eclipse.apoapsis.ortserver.dao.tables.VulnerabilityResolutionDefinitionsTable
23+
2224
import org.jetbrains.exposed.sql.Table
25+
import org.jetbrains.exposed.sql.and
26+
import org.jetbrains.exposed.sql.update
2327

2428
/**
2529
* An intermediate table to store references from [RepositoryConfigurationsTable] and [VulnerabilityResolutionsTable].
@@ -28,7 +32,19 @@ object RepositoryConfigurationsVulnerabilityResolutionsTable :
2832
Table("repository_configurations_vulnerability_resolutions") {
2933
val repositoryConfigurationId = reference("repository_configuration_id", RepositoryConfigurationsTable)
3034
val vulnerabilityResolutionId = reference("vulnerability_resolution_id", VulnerabilityResolutionsTable)
35+
val vulnerabilityResolutionDefinitionId = reference(
36+
"vulnerability_resolution_definition_id",
37+
VulnerabilityResolutionDefinitionsTable
38+
).nullable()
3139

3240
override val primaryKey: PrimaryKey
3341
get() = PrimaryKey(repositoryConfigurationId, vulnerabilityResolutionId, name = "${tableName}_pkey")
42+
43+
fun addDefinitionId(repositoryConfigId: Long, vulnerabilityResId: Long, vulnerabilityResolutionDefId: Long) =
44+
update({
45+
(repositoryConfigurationId eq repositoryConfigId) and
46+
(vulnerabilityResolutionId eq vulnerabilityResId)
47+
}) { stmt ->
48+
stmt[vulnerabilityResolutionDefinitionId] = vulnerabilityResolutionDefId
49+
}
3450
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ALTER TABLE repository_configurations_vulnerability_resolutions
2+
ADD COLUMN vulnerability_resolution_definition_id bigint
3+
REFERENCES vulnerability_resolution_definitions NULL;

dao/src/test/kotlin/repositories/repositoryconfiguration/DaoRepositoryConfigurationRepositoryTest.kt

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,18 @@ package org.eclipse.apoapsis.ortserver.dao.repositories.repositoryconfiguration
2121

2222
import io.kotest.core.spec.style.WordSpec
2323
import io.kotest.matchers.collections.containExactly
24+
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
25+
import io.kotest.matchers.collections.shouldHaveSize
2426
import io.kotest.matchers.nulls.shouldBeNull
2527
import io.kotest.matchers.nulls.shouldNotBeNull
2628
import io.kotest.matchers.should
2729
import io.kotest.matchers.shouldBe
2830

2931
import org.eclipse.apoapsis.ortserver.dao.test.DatabaseTestExtension
3032
import org.eclipse.apoapsis.ortserver.dao.test.Fixtures
33+
import org.eclipse.apoapsis.ortserver.model.RepositoryId
3134
import org.eclipse.apoapsis.ortserver.model.RepositoryType
35+
import org.eclipse.apoapsis.ortserver.model.VulnerabilityResolutionReason
3236
import org.eclipse.apoapsis.ortserver.model.runs.Identifier
3337
import org.eclipse.apoapsis.ortserver.model.runs.PackageManagerConfiguration
3438
import org.eclipse.apoapsis.ortserver.model.runs.RemoteArtifact
@@ -141,6 +145,62 @@ class DaoRepositoryConfigurationRepositoryTest : WordSpec({
141145
includes.paths should containExactly(pathInclude)
142146
}
143147
}
148+
149+
"inject vulnerability resolutions that have been defined for the repository" {
150+
fixtures.createVulnerabilityResolutionDefinition(
151+
idMatchers = listOf("CVE-2020-15250", "GHSA-269g-pwp5-87pp"),
152+
reason = VulnerabilityResolutionReason.INEFFECTIVE_VULNERABILITY
153+
)
154+
155+
val ortRun2Id = fixtures.createOrtRun().id
156+
157+
val createdRepositoryConfiguration = repositoryConfigurationRepository.create(
158+
ortRun2Id, repositoryConfig
159+
)
160+
161+
val dbEntry = repositoryConfigurationRepository.get(createdRepositoryConfiguration.id)
162+
163+
dbEntry shouldNotBeNull {
164+
resolutions.vulnerabilities shouldHaveSize 3
165+
resolutions.vulnerabilities shouldContainExactlyInAnyOrder listOf(
166+
vulnerabilityResolution,
167+
VulnerabilityResolution(
168+
"CVE-2020-15250",
169+
VulnerabilityResolutionReason.INEFFECTIVE_VULNERABILITY.name,
170+
"Comment."
171+
),
172+
VulnerabilityResolution(
173+
"GHSA-269g-pwp5-87pp",
174+
VulnerabilityResolutionReason.INEFFECTIVE_VULNERABILITY.name,
175+
"Comment."
176+
)
177+
)
178+
}
179+
}
180+
181+
"not inject vulnerability resolutions made for other repositories" {
182+
fixtures.createVulnerabilityResolutionDefinition(
183+
RepositoryId(fixtures.ortRun.repositoryId),
184+
ortRunId,
185+
listOf("CVE-2020-15250", "GHSA-269g-pwp5-87pp"),
186+
VulnerabilityResolutionReason.INEFFECTIVE_VULNERABILITY,
187+
"comment"
188+
)
189+
190+
val repo2Id = fixtures.createRepository(url = "https://example.com/repo2.git").id
191+
val run2Id = fixtures.createOrtRun(repo2Id).id
192+
193+
val createdRepositoryConfiguration = repositoryConfigurationRepository.create(
194+
run2Id, repositoryConfig
195+
)
196+
197+
val dbEntry = repositoryConfigurationRepository.get(createdRepositoryConfiguration.id)
198+
199+
dbEntry shouldNotBeNull {
200+
resolutions.vulnerabilities shouldHaveSize 1
201+
resolutions.vulnerabilities.first() shouldBe vulnerabilityResolution
202+
}
203+
}
144204
}
145205

146206
"get" should {

dao/src/testFixtures/kotlin/Fixtures.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package org.eclipse.apoapsis.ortserver.dao.test
2222
import kotlinx.datetime.Clock
2323

2424
import org.eclipse.apoapsis.ortserver.dao.blockingQuery
25+
import org.eclipse.apoapsis.ortserver.dao.dbQuery
2526
import org.eclipse.apoapsis.ortserver.dao.repositories.advisorjob.DaoAdvisorJobRepository
2627
import org.eclipse.apoapsis.ortserver.dao.repositories.advisorrun.DaoAdvisorRunRepository
2728
import org.eclipse.apoapsis.ortserver.dao.repositories.analyzerjob.DaoAnalyzerJobRepository
@@ -41,6 +42,7 @@ import org.eclipse.apoapsis.ortserver.dao.repositories.resolvedconfiguration.Dao
4142
import org.eclipse.apoapsis.ortserver.dao.repositories.scannerjob.DaoScannerJobRepository
4243
import org.eclipse.apoapsis.ortserver.dao.repositories.scannerrun.DaoScannerRunRepository
4344
import org.eclipse.apoapsis.ortserver.dao.repositories.secret.DaoSecretRepository
45+
import org.eclipse.apoapsis.ortserver.dao.tables.VulnerabilityResolutionDefinitionsTable
4446
import org.eclipse.apoapsis.ortserver.dao.tables.shared.IdentifierDao
4547
import org.eclipse.apoapsis.ortserver.model.AdvisorJobConfiguration
4648
import org.eclipse.apoapsis.ortserver.model.AnalyzerJobConfiguration
@@ -50,9 +52,11 @@ import org.eclipse.apoapsis.ortserver.model.Jobs
5052
import org.eclipse.apoapsis.ortserver.model.NotifierJobConfiguration
5153
import org.eclipse.apoapsis.ortserver.model.PluginConfig
5254
import org.eclipse.apoapsis.ortserver.model.ReporterJobConfiguration
55+
import org.eclipse.apoapsis.ortserver.model.RepositoryId
5356
import org.eclipse.apoapsis.ortserver.model.RepositoryType
5457
import org.eclipse.apoapsis.ortserver.model.ScannerJobConfiguration
5558
import org.eclipse.apoapsis.ortserver.model.Severity
59+
import org.eclipse.apoapsis.ortserver.model.VulnerabilityResolutionReason
5660
import org.eclipse.apoapsis.ortserver.model.runs.AnalyzerConfiguration
5761
import org.eclipse.apoapsis.ortserver.model.runs.DependencyGraph
5862
import org.eclipse.apoapsis.ortserver.model.runs.Environment
@@ -74,6 +78,7 @@ import org.jetbrains.exposed.sql.Database
7478
* A helper class to manage test fixtures. It provides default instances as well as helper functions to create custom
7579
* instances.
7680
*/
81+
@Suppress("TooManyFunctions")
7782
class Fixtures(private val db: Database) {
7883
val advisorJobRepository = DaoAdvisorJobRepository(db)
7984
val advisorRunRepository = DaoAdvisorRunRepository(db)
@@ -343,4 +348,20 @@ class Fixtures(private val db: Database) {
343348
isMetadataOnly = false,
344349
isModified = false
345350
)
351+
352+
suspend fun createVulnerabilityResolutionDefinition(
353+
hierarchyId: RepositoryId = RepositoryId(repository.id),
354+
contextRunId: Long = ortRun.id,
355+
idMatchers: List<String>,
356+
reason: VulnerabilityResolutionReason,
357+
comment: String = "Comment."
358+
) = db.dbQuery {
359+
VulnerabilityResolutionDefinitionsTable.insert(
360+
hierarchyId,
361+
contextRunId,
362+
idMatchers,
363+
reason,
364+
comment
365+
)
366+
}
346367
}

0 commit comments

Comments
 (0)