From 0c1042fd2cc4eb5a4db1db7fe283ceae774e8376 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Wed, 30 Oct 2019 14:24:50 +0100 Subject: [PATCH] SONAR-12512 Migrate sonar.alm.github.app.privateKey.secured property --- .../db/migration/version/v81/DbVersion81.java | 10 +- ...ateDeprecatedGithubPrivateKeyToNewKey.java | 66 +++++++++++ .../version/v81/DbVersion81Test.java | 2 +- ...eprecatedGithubPrivateKeyToNewKeyTest.java | 108 ++++++++++++++++++ .../schema.sql | 11 ++ 5 files changed, 191 insertions(+), 6 deletions(-) create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKey.java create mode 100644 server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKeyTest.java create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKeyTest/schema.sql diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java index 37c9cda8c40..b8ca648b3d0 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java @@ -28,10 +28,10 @@ public class DbVersion81 implements DbVersion { registry .add(3100, "Create ALM_SETTINGS table", CreateAlmSettingsTable.class) .add(3101, "Create PROJECT_ALM_SETTINGS table", CreateProjectAlmSettingsTable.class) - .add(3102, "Migrate GitHub ALM settings from PROPERTIES to ALM_SETTINGS tables", MigrateGithubAlmSettings.class) - .add(3103, "Migrate Bitbucket ALM settings from PROPERTIES to ALM_SETTINGS tables", MigrateBitbucketAlmSettings.class) - .add(3104, "Migrate Azure ALM settings from PROPERTIES to ALM_SETTINGS tables", MigrateAzureAlmSettings.class) - .add(3105, "Delete 'sonar.pullrequest.provider' property", DeleteSonarPullRequestProviderProperty.class) - ; + .add(3102, "Migrate property 'sonar.alm.github.app.privateKey.secured' to 'sonar.alm.github.app.privateKeyContent.secured'", MigrateDeprecatedGithubPrivateKeyToNewKey.class) + .add(3103, "Migrate GitHub ALM settings from PROPERTIES to ALM_SETTINGS tables", MigrateGithubAlmSettings.class) + .add(3104, "Migrate Bitbucket ALM settings from PROPERTIES to ALM_SETTINGS tables", MigrateBitbucketAlmSettings.class) + .add(3105, "Migrate Azure ALM settings from PROPERTIES to ALM_SETTINGS tables", MigrateAzureAlmSettings.class) + .add(3106, "Delete 'sonar.pullrequest.provider' property", DeleteSonarPullRequestProviderProperty.class); } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKey.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKey.java new file mode 100644 index 00000000000..9537350c341 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKey.java @@ -0,0 +1,66 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.v81; + +import java.sql.SQLException; +import java.util.Base64; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.step.DataChange; +import org.sonar.server.platform.db.migration.step.MassUpdate; +import org.sonar.server.platform.db.migration.step.Select; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class MigrateDeprecatedGithubPrivateKeyToNewKey extends DataChange { + + private static final String OLD_KEY = "sonar.alm.github.app.privateKey.secured"; + private static final String NEW_KEY = "sonar.alm.github.app.privateKeyContent.secured"; + + public MigrateDeprecatedGithubPrivateKeyToNewKey(Database db) { + super(db); + } + + @Override + protected void execute(Context context) throws SQLException { + Long newPropertyId = context.prepareSelect("select id from properties where prop_key = ?") + .setString(1, NEW_KEY) + .get(Select.LONG_READER); + if (newPropertyId != null) { + context.prepareUpsert("delete from properties where prop_key = ? ") + .setString(1, OLD_KEY) + .execute() + .commit(); + return; + } + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("select id, text_value from properties where prop_key = ?") + .setString(1, OLD_KEY); + massUpdate.update("update properties set prop_key = ?, text_value = ? where id = ?"); + massUpdate.execute((row, handler) -> { + String propertyEncodedInBAse64 = row.getString(2); + String propertyDecoded = new String(Base64.getDecoder().decode(propertyEncodedInBAse64), UTF_8); + handler.setString(1, NEW_KEY); + handler.setString(2, propertyDecoded); + handler.setLong(3, row.getLong(1)); + return true; + }); + } + +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java index 772a5c35882..64b052cd26c 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java @@ -37,7 +37,7 @@ public class DbVersion81Test { @Test public void verify_migration_count() { - verifyMigrationCount(underTest, 6); + verifyMigrationCount(underTest, 7); } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKeyTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKeyTest.java new file mode 100644 index 00000000000..0d9ba798655 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKeyTest.java @@ -0,0 +1,108 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.v81; + +import java.sql.SQLException; +import java.util.Base64; +import org.assertj.core.groups.Tuple; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.db.CoreDbTester; +import org.sonar.server.platform.db.migration.step.DataChange; + +import static java.util.stream.Collectors.toList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +public class MigrateDeprecatedGithubPrivateKeyToNewKeyTest { + + @Rule + public CoreDbTester db = CoreDbTester.createForSchema(MigrateDeprecatedGithubPrivateKeyToNewKeyTest.class, "schema.sql"); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private DataChange underTest = new MigrateDeprecatedGithubPrivateKeyToNewKey(db.database()); + + @Test + public void migrate_and_decode_old_property_to_new_one() throws SQLException { + String privateKey = ""; + insertProperty("sonar.alm.github.app.privateKey.secured", Base64.getEncoder().encodeToString(privateKey.getBytes())); + + underTest.execute(); + + assertProperties(tuple("sonar.alm.github.app.privateKeyContent.secured", privateKey)); + } + + @Test + public void do_nothing_when_only_new_property() throws SQLException { + String privateKey = ""; + insertProperty("sonar.alm.github.app.privateKeyContent.secured", privateKey); + + underTest.execute(); + + assertProperties(tuple("sonar.alm.github.app.privateKeyContent.secured", privateKey)); + } + + @Test + public void remove_old_property_when_both_new_one_and_old_one_exist() throws SQLException { + String privateKey = ""; + insertProperty("sonar.alm.github.app.privateKey.secured", Base64.getEncoder().encodeToString(privateKey.getBytes())); + insertProperty("sonar.alm.github.app.privateKeyContent.secured", privateKey); + + underTest.execute(); + + assertProperties(tuple("sonar.alm.github.app.privateKeyContent.secured", privateKey)); + } + + @Test + public void migration_is_re_entrant() throws SQLException { + String privateKey = ""; + insertProperty("sonar.alm.github.app.privateKey.secured", Base64.getEncoder().encodeToString(privateKey.getBytes())); + + underTest.execute(); + underTest.execute(); + + assertProperties(tuple("sonar.alm.github.app.privateKeyContent.secured", privateKey)); + } + + private void assertProperties(Tuple... tuples) { + assertThat(db.select("SELECT prop_key, text_value FROM properties") + .stream() + .map(map -> new Tuple(map.get("PROP_KEY"), map.get("TEXT_VALUE"))) + .collect(toList())) + .containsExactlyInAnyOrder(tuples); + } + + private void insertProperty(String key, String value) { + db.executeInsert( + "PROPERTIES", + "PROP_KEY", key, + "RESOURCE_ID", null, + "USER_ID", null, + "IS_EMPTY", false, + "TEXT_VALUE", value, + "CLOB_VALUE", null, + "CREATED_AT", System2.INSTANCE.now()); + } + +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKeyTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKeyTest/schema.sql new file mode 100644 index 00000000000..d84c238cd48 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDeprecatedGithubPrivateKeyToNewKeyTest/schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE "PROPERTIES" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "PROP_KEY" VARCHAR(512) NOT NULL, + "RESOURCE_ID" INTEGER, + "USER_ID" INTEGER, + "IS_EMPTY" BOOLEAN NOT NULL, + "TEXT_VALUE" VARCHAR(4000), + "CLOB_VALUE" CLOB, + "CREATED_AT" BIGINT +); +CREATE INDEX "PROPERTIES_KEY" ON "PROPERTIES" ("PROP_KEY"); -- 2.39.5