aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2024-10-28 12:56:36 +0100
committersonartech <sonartech@sonarsource.com>2024-10-29 20:02:49 +0000
commit122be7bb5860e7d4d643fbce2e5d5b153da8714c (patch)
tree5bdee4e1f4cfeb2bd0516e8d398c11aedf91f7ed
parent62721916c9f1e0b2ca9a6fa3a3fbc3907834f531 (diff)
downloadsonarqube-122be7bb5860e7d4d643fbce2e5d5b153da8714c.tar.gz
sonarqube-122be7bb5860e7d4d643fbce2e5d5b153da8714c.zip
SONAR-23485 Fix NPE when importing FOSSA CVEs
Make published_at and last_modified_at nullable
-rw-r--r--server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/PersistCveStepIT.java40
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistCveStep.java36
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/dependency/CveDto.java13
-rw-r--r--server/sonar-db-dao/src/schema/schema-sq.ddl4
-rw-r--r--server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/AlterCveColumnsToNullableIT.java63
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AlterCveColumnsToNullable.java49
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/DbVersion108.java3
-rw-r--r--sonar-scanner-protocol/src/main/protobuf/scanner_report.proto10
8 files changed, 176 insertions, 42 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/PersistCveStepIT.java b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/PersistCveStepIT.java
index ad030ca4d77..faca0e5bfe6 100644
--- a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/PersistCveStepIT.java
+++ b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/PersistCveStepIT.java
@@ -67,12 +67,14 @@ class PersistCveStepIT {
void execute_shouldInsertNewCVEs() {
Cve cve1 = buildCve("1").build();
Cve cve2 = buildCve("2").build();
- batchReportReader.putCves(List.of(cve1, cve2));
+ Cve cveAllOptionalEmpty = Cve.newBuilder().setCveId("CVE-empty").setDescription("Empty CVE").build();
+ batchReportReader.putCves(List.of(cve1, cve2, cveAllOptionalEmpty));
persistCveStep.execute(new TestComputationStepContext());
assertCvePersistedInDatabase(cve1);
assertCvePersistedInDatabase(cve2);
+ assertCvePersistedInDatabase(cveAllOptionalEmpty);
}
private void assertCvePersistedInDatabase(Cve cve) {
@@ -80,11 +82,31 @@ class PersistCveStepIT {
.orElseGet(() -> fail(String.format("CVE with id %s not found", cve.getCveId())));
assertThat(cveDto.id()).isEqualTo(cve.getCveId());
assertThat(cveDto.description()).isEqualTo(cve.getDescription());
- assertThat(cveDto.cvssScore()).isEqualTo(cve.getCvssScore());
- assertThat(cveDto.epssScore()).isEqualTo(cve.getEpssScore());
- assertThat(cveDto.epssPercentile()).isEqualTo(cve.getEpssPercentile());
- assertThat(cveDto.publishedAt()).isEqualTo(cve.getPublishedDate());
- assertThat(cveDto.lastModifiedAt()).isEqualTo(cve.getLastModifiedDate());
+ if (cve.hasCvssScore()) {
+ assertThat(cveDto.cvssScore()).isEqualTo(cve.getCvssScore());
+ } else {
+ assertThat(cveDto.cvssScore()).isNull();
+ }
+ if (cve.hasEpssScore()) {
+ assertThat(cveDto.epssScore()).isEqualTo(cve.getEpssScore());
+ } else {
+ assertThat(cveDto.epssScore()).isNull();
+ }
+ if (cve.hasEpssPercentile()) {
+ assertThat(cveDto.epssPercentile()).isEqualTo(cve.getEpssPercentile());
+ } else {
+ assertThat(cveDto.epssPercentile()).isNull();
+ }
+ if (cve.hasPublishedDate()) {
+ assertThat(cveDto.publishedAt()).isEqualTo(cve.getPublishedDate());
+ } else {
+ assertThat(cveDto.publishedAt()).isNull();
+ }
+ if (cve.hasLastModifiedDate()) {
+ assertThat(cveDto.lastModifiedAt()).isEqualTo(cve.getLastModifiedDate());
+ } else {
+ assertThat(cveDto.lastModifiedAt()).isNull();
+ }
assertThat(cveDto.uuid()).isNotBlank();
assertThat(cveDto.createdAt()).isNotNull();
assertThat(cveDto.updatedAt()).isNotNull();
@@ -92,8 +114,8 @@ class PersistCveStepIT {
@Test
void execute_shoudUpdateExistingCves() {
- dbClient.cveDao().insert(dbSession, new CveDto("cve-uuid-1", "CVE-1", "Old description 1", 0.0F, 0.0F, 0.0F, 0L, 0L, 0L, 0L));
- dbClient.cveDao().insert(dbSession, new CveDto("cve-uuid-2", "CVE-2", "Old description 2", 0.0F, 0.0F, 0.0F, 0L, 0L, 0L, 0L));
+ dbClient.cveDao().insert(dbSession, new CveDto("cve-uuid-1", "CVE-1", "Old description 1", 10.0, 20.0, 30.0, 0L, 0L, 0L, 0L));
+ dbClient.cveDao().insert(dbSession, new CveDto("cve-uuid-2", "CVE-2", "Old description 2", null, null, null, null, null, 0L, 0L));
db.commit();
Cve cve1 = buildCve("1").build();
Cve cve2 = buildCve("2").build();
@@ -120,7 +142,7 @@ class PersistCveStepIT {
@Test
void execute_shouldUpdateExistingCwesAndInsertNewOnes_whenUpdatingCVEs() {
- dbClient.cveDao().insert(dbSession, new CveDto("cve-uuid-1", "CVE-1", "Old description 1", 0.0F, 0.0F, 0.0F, 0L, 0L, 0L, 0L));
+ dbClient.cveDao().insert(dbSession, new CveDto("cve-uuid-1", "CVE-1", "Old description 1", 0.0, 0.0, 0.0, 0L, 0L, 0L, 0L));
dbClient.cveCweDao().insert(dbSession, new CveCweDto("cve-uuid-1", "CWE-1"));
dbClient.cveCweDao().insert(dbSession, new CveCweDto("cve-uuid-1", "CWE-2"));
db.commit();
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistCveStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistCveStep.java
index 34bd2ad9a3f..304c7280e7a 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistCveStep.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistCveStep.java
@@ -64,7 +64,7 @@ public class PersistCveStep implements ComputationStep {
public void execute(Context context) {
int count = 0;
try (DbSession dbSession = dbClient.openSession(false);
- CloseableIterator<ScannerReport.Cve> batchCves = batchReportReader.readCves()) {
+ CloseableIterator<ScannerReport.Cve> batchCves = batchReportReader.readCves()) {
while (batchCves.hasNext()) {
updateOrInsertCve(dbSession, batchCves.next());
count++;
@@ -91,18 +91,7 @@ public class PersistCveStep implements ComputationStep {
}
private CveDto toDtoForUpdate(ScannerReport.Cve cve, CveDto cveInDb) {
- return new CveDto(
- cveInDb.uuid(),
- cve.getCveId(),
- cve.getDescription(),
- cve.getCvssScore(),
- cve.getEpssScore(),
- cve.getEpssPercentile(),
- cve.getPublishedDate(),
- cve.getLastModifiedDate(),
- cveInDb.createdAt(),
- system2.now()
- );
+ return toDto(cve, cveInDb.uuid(), cveInDb.createdAt(), system2.now());
}
private void deleteThenInsertCwesIfUpdated(DbSession dbSession, ScannerReport.Cve scannerCve, String cveUuid) {
@@ -122,18 +111,21 @@ public class PersistCveStep implements ComputationStep {
private CveDto toDtoForInsert(ScannerReport.Cve cve) {
long now = system2.now();
+ return toDto(cve, uuidFactory.create(), now, now);
+ }
+
+ private static CveDto toDto(ScannerReport.Cve cve, String uuid, Long createdAt, Long updatedAt) {
return new CveDto(
- uuidFactory.create(),
+ uuid,
cve.getCveId(),
cve.getDescription(),
- cve.getCvssScore(),
- cve.getEpssScore(),
- cve.getEpssPercentile(),
- cve.getPublishedDate(),
- cve.getLastModifiedDate(),
- now,
- now
- );
+ cve.hasCvssScore() ? cve.getCvssScore() : null,
+ cve.hasEpssScore() ? cve.getEpssScore() : null,
+ cve.hasEpssPercentile() ? cve.getEpssPercentile() : null,
+ cve.hasPublishedDate() ? cve.getPublishedDate() : null,
+ cve.hasLastModifiedDate() ? cve.getLastModifiedDate() : null,
+ createdAt,
+ updatedAt);
}
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/dependency/CveDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/dependency/CveDto.java
index 53278c024c4..e8c3cd8a21e 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/dependency/CveDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/dependency/CveDto.java
@@ -19,14 +19,21 @@
*/
package org.sonar.db.dependency;
+import javax.annotation.Nullable;
+
public record CveDto(
String uuid,
String id,
String description,
- double cvssScore,
- double epssScore,
- double epssPercentile,
+ @Nullable
+ Double cvssScore,
+ @Nullable
+ Double epssScore,
+ @Nullable
+ Double epssPercentile,
+ @Nullable
Long publishedAt,
+ @Nullable
Long lastModifiedAt,
Long createdAt,
Long updatedAt
diff --git a/server/sonar-db-dao/src/schema/schema-sq.ddl b/server/sonar-db-dao/src/schema/schema-sq.ddl
index 8d87b6f6d02..272b1c156a1 100644
--- a/server/sonar-db-dao/src/schema/schema-sq.ddl
+++ b/server/sonar-db-dao/src/schema/schema-sq.ddl
@@ -263,8 +263,8 @@ CREATE TABLE "CVES"(
"CVSS_SCORE" DOUBLE PRECISION,
"EPSS_SCORE" DOUBLE PRECISION,
"EPSS_PERCENTILE" DOUBLE PRECISION,
- "PUBLISHED_AT" BIGINT NOT NULL,
- "LAST_MODIFIED_AT" BIGINT NOT NULL,
+ "PUBLISHED_AT" BIGINT,
+ "LAST_MODIFIED_AT" BIGINT,
"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL
);
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/AlterCveColumnsToNullableIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/AlterCveColumnsToNullableIT.java
new file mode 100644
index 00000000000..c2d5d754a07
--- /dev/null
+++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/AlterCveColumnsToNullableIT.java
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v108;
+
+import java.sql.SQLException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.sonar.db.MigrationDbTester;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static java.sql.Types.BIGINT;
+import static org.sonar.db.MigrationDbTester.createForMigrationStep;
+
+class AlterCveColumnsToNullableIT {
+
+ private static final String TABLE_NAME = "cves";
+
+ @RegisterExtension
+ public final MigrationDbTester db = createForMigrationStep(AlterCveColumnsToNullable.class);
+
+ private final DdlChange underTest = new AlterCveColumnsToNullable(db.database());
+
+ @Test
+ void execute_shouldUpdateConstraints() throws SQLException {
+ db.assertColumnDefinition(TABLE_NAME, "published_at", BIGINT, null, false);
+ db.assertColumnDefinition(TABLE_NAME, "last_modified_at", BIGINT, null, false);
+
+ underTest.execute();
+
+ db.assertColumnDefinition(TABLE_NAME, "published_at", BIGINT, null, true);
+ db.assertColumnDefinition(TABLE_NAME, "last_modified_at", BIGINT, null, true);
+ }
+
+ @Test
+ void execute_shouldBeReentrant() throws SQLException {
+ db.assertColumnDefinition(TABLE_NAME, "published_at", BIGINT, null, false);
+ db.assertColumnDefinition(TABLE_NAME, "last_modified_at", BIGINT, null, false);
+ underTest.execute();
+
+ underTest.execute();
+
+ db.assertColumnDefinition(TABLE_NAME, "published_at", BIGINT, null, true);
+ db.assertColumnDefinition(TABLE_NAME, "last_modified_at", BIGINT, null, true);
+ }
+
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AlterCveColumnsToNullable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AlterCveColumnsToNullable.java
new file mode 100644
index 00000000000..77d37626a66
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AlterCveColumnsToNullable.java
@@ -0,0 +1,49 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v108;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.def.BigIntegerColumnDef;
+import org.sonar.server.platform.db.migration.sql.AlterColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.BigIntegerColumnDef.newBigIntegerColumnDefBuilder;
+
+public class AlterCveColumnsToNullable extends DdlChange {
+
+ public static final BigIntegerColumnDef LAST_MODIFIED_COLUMN = newBigIntegerColumnDefBuilder().setColumnName("last_modified_at").setIsNullable(true).build();
+ public static final BigIntegerColumnDef PUBLISHED_COLUMN = newBigIntegerColumnDefBuilder().setColumnName("published_at").setIsNullable(true).build();
+
+
+ public AlterCveColumnsToNullable(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(new AlterColumnsBuilder(getDialect(), "cves")
+ .updateColumn(LAST_MODIFIED_COLUMN)
+ .build());
+ context.execute(new AlterColumnsBuilder(getDialect(), "cves")
+ .updateColumn(PUBLISHED_COLUMN)
+ .build());
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/DbVersion108.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/DbVersion108.java
index 412306bceb7..a766c70ab7e 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/DbVersion108.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/DbVersion108.java
@@ -57,7 +57,8 @@ public class DbVersion108 implements DbVersion {
.add(10_8_014, "Drop 'measures_migrated' column on 'project_branches' table", DropMeasuresMigratedColumnInProjectBranchesTable.class)
.add(10_8_015, "Add column 'impacts' in 'active_rules' table", AddImpactsColumnInActiveRulesTable.class)
.add(10_8_016, "Create 'project_dependencies' table", CreateProjectDependenciesTable.class)
- .add(10_8_017, "Enable specific MQR mode", EnableSpecificMqrMode.class);
+ .add(10_8_017, "Enable specific MQR mode", EnableSpecificMqrMode.class)
+ .add(10_8_018, "Make columns 'published_at' and 'last_modified_at' nullable on the 'cves' table", AlterCveColumnsToNullable.class);
}
}
diff --git a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
index fb7ebb72f7f..c062c0ca161 100644
--- a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
+++ b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
@@ -238,11 +238,11 @@ message AdHocRule {
message Cve {
string cve_id = 1;
string description = 2;
- optional float cvss_score = 3;
- optional float epss_score = 4;
- optional float epss_percentile = 5;
- int64 published_date = 6;
- int64 last_modified_date = 7;
+ optional double cvss_score = 3;
+ optional double epss_score = 4;
+ optional double epss_percentile = 5;
+ optional int64 published_date = 6;
+ optional int64 last_modified_date = 7;
repeated string cwe = 8;
}