From 2f5139340defbb5d9f70fde2549b5b1f3f15cd6e Mon Sep 17 00:00:00 2001 From: Kodai Doki Date: Tue, 22 Jul 2025 10:54:33 +0900 Subject: [PATCH 1/3] Add permission tests for MySQL, PostgreSQL, Oracle and SQL Server --- .github/workflows/permission-check.yaml | 497 ++++++++++++++++++ core/build.gradle | 32 ++ .../JdbcAdminPermissionIntegrationTest.java | 29 + .../com/scalar/db/storage/jdbc/JdbcEnv.java | 15 + .../jdbc/JdbcPermissionIntegrationTest.java | 28 + .../storage/jdbc/JdbcPermissionTestUtils.java | 151 ++++++ 6 files changed, 752 insertions(+) create mode 100644 core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcAdminPermissionIntegrationTest.java create mode 100644 core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionIntegrationTest.java create mode 100644 core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java diff --git a/.github/workflows/permission-check.yaml b/.github/workflows/permission-check.yaml index bd56dbeaa3..0eced7fd1f 100644 --- a/.github/workflows/permission-check.yaml +++ b/.github/workflows/permission-check.yaml @@ -114,3 +114,500 @@ jobs: with: name: dynamo_permission_integration_test_reports path: core/build/reports/tests/integrationTestDynamoPermission + + integration-test-permission-jdbc-mysql-5-7: + name: MySQL 5.7 Permission Integration Test + runs-on: ubuntu-latest + + steps: + - name: Run MySQL 5.7 + run: | + docker run -e MYSQL_ROOT_PASSWORD=mysql -p 3306:3306 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_bin + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: mysql_5.7_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-mysql-8-0: + name: MySQL 8.0 Permission Integration Test + runs-on: ubuntu-latest + + steps: + - name: Run MySQL 8.0 + run: | + docker run -e MYSQL_ROOT_PASSWORD=mysql -p 3306:3306 -d mysql:8.0 --character-set-server=utf8mb4 --collation-server=utf8mb4_bin + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: mysql_8.0_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-mysql-8-4: + name: MySQL 8.4 Permission Integration Test + runs-on: ubuntu-latest + + steps: + - name: Run MySQL 8.4 + run: | + docker run -e MYSQL_ROOT_PASSWORD=mysql -p 3306:3306 -d mysql:8.4 --character-set-server=utf8mb4 --collation-server=utf8mb4_bin + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: mysql_8.4_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-postgresql-13: + name: PostgreSQL 13 Permission Integration Test + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:13-alpine + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + ports: + - 5432:5432 + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:postgresql://localhost:5432/postgres -Dscalardb.jdbc.username=postgres -Dscalardb.jdbc.password=postgres + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: postgresql_13_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-postgresql-14: + name: PostgreSQL 14 Permission Integration Test + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:14-alpine + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + ports: + - 5432:5432 + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:postgresql://localhost:5432/postgres -Dscalardb.jdbc.username=postgres -Dscalardb.jdbc.password=postgres + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: postgresql_14_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-postgresql-15: + name: PostgreSQL 15 Permission Integration Test + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:15-alpine + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + ports: + - 5432:5432 + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:postgresql://localhost:5432/postgres -Dscalardb.jdbc.username=postgres -Dscalardb.jdbc.password=postgres + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: postgresql_15_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-postgresql-16: + name: PostgreSQL 16 Permission Integration Test + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:16-alpine + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + ports: + - 5432:5432 + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:postgresql://localhost:5432/postgres -Dscalardb.jdbc.username=postgres -Dscalardb.jdbc.password=postgres + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: postgresql_16_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-postgresql-17: + name: PostgreSQL 17 Permission Integration Test + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:17-alpine + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + ports: + - 5432:5432 + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:postgresql://localhost:5432/postgres -Dscalardb.jdbc.username=postgres -Dscalardb.jdbc.password=postgres + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: postgresql_17_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-oracle-19: + name: Oracle 19 Permission Integration Test + runs-on: ubuntu-latest + + services: + oracle: + image: ghcr.io/scalar-labs/oracle/db-prebuilt:19 + credentials: + username: ${{ github.repository_owner }} + password: ${{ secrets.CR_PAT }} + ports: + - 1521:1521 + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:oracle:thin:@//localhost:1521/ORCLPDB1 -Dscalardb.jdbc.username=SYSTEM -Dscalardb.jdbc.password=Oracle + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: oracle_19_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-oracle-21: + name: Oracle 21 Permission Integration Test + runs-on: ubuntu-latest + + services: + oracle: + image: ghcr.io/scalar-labs/oracle/db-prebuilt:21 + credentials: + username: ${{ github.repository_owner }} + password: ${{ secrets.CR_PAT }} + ports: + - 1521:1521 + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:oracle:thin:@//localhost:1521/ORCLPDB1 -Dscalardb.jdbc.username=SYSTEM -Dscalardb.jdbc.password=Oracle + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: oracle_21_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-oracle-23: + name: Oracle 23 Permission Integration Test + runs-on: ubuntu-latest + + services: + oracle: + image: ghcr.io/scalar-labs/oracle/db-prebuilt:23 + credentials: + username: ${{ github.repository_owner }} + password: ${{ secrets.CR_PAT }} + ports: + - 1521:1521 + + steps: + - name: Free up ~14GB of disk space by removing the Android SDK + run: | + echo "Storage available before deletion" + df -h / + echo + sudo rm -r /usr/local/lib/android + echo "Storage available after deletion" + df -h / + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.CR_PAT }} + + - name: Start Oracle 23 container + run: docker run -d --name oracle-23 -p 1521:1521 ghcr.io/scalar-labs/oracle/db-prebuilt:23 + + - name: Wait for the container to be ready + timeout-minutes: 5 + run: | + while [ "`docker inspect -f {{.State.Health.Status}} oracle-23`" != "healthy" ] + do + sleep 10 + echo "Container is not yet ready" + done + echo "Container is ready" + + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:oracle:thin:@//localhost:1521/ORCLPDB1 -Dscalardb.jdbc.username=SYSTEM -Dscalardb.jdbc.password=Oracle + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: oracle_23_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-sqlserver-2017: + name: SQL Server 2017 Permission Integration Test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Sql Server 2017 + uses: rails-sqlserver/setup-mssql@v1 + with: + components: sqlcmd,sqlengine + sa-password: "SqlServer17" + version: 2017 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:sqlserver://localhost:1433;encrypt=false -Dscalardb.jdbc.username=sa -Dscalardb.jdbc.password=SqlServer17 + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: sqlserver_2017_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-sqlserver-2019: + name: SQL Server 2019 Permission Integration Test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Sql Server 2019 + uses: rails-sqlserver/setup-mssql@v1 + with: + components: sqlcmd,sqlengine + sa-password: "SqlServer19" + version: 2019 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:sqlserver://localhost:1433;encrypt=false -Dscalardb.jdbc.username=sa -Dscalardb.jdbc.password=SqlServer19 + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: sqlserver_2019_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + integration-test-permission-jdbc-sqlserver-2022: + name: SQL Server 2022 Permission Integration Test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Sql Server 2022 + uses: rails-sqlserver/setup-mssql@v1 + with: + components: sqlcmd,sqlengine + sa-password: "SqlServer22" + version: 2022 + + - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) + uses: actions/setup-java@v4 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_VENDOR }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Execute Gradle 'integrationTestJdbcPermission' task + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:sqlserver://localhost:1433;encrypt=false -Dscalardb.jdbc.username=sa -Dscalardb.jdbc.password=SqlServer22 + + - name: Upload Gradle test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: sqlserver_2022_permission_integration_test_reports + path: core/build/reports/tests/integrationTestJdbcPermission + + diff --git a/core/build.gradle b/core/build.gradle index b446b0ff01..f2072d42fa 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -59,6 +59,9 @@ sourceSets { include '**/com/scalar/db/common/*.java' include '**/com/scalar/db/storage/jdbc/*.java' include '**/com/scalar/db/transaction/jdbc/*.java' + exclude '**/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java' + exclude '**/com/scalar/db/storage/jdbc/JdbcPermissionIntegrationTest.java' + exclude '**/com/scalar/db/storage/jdbc/JdbcAdminPermissionIntegrationTest.java' } resources.srcDir file('src/integration-test/resources') } @@ -101,6 +104,21 @@ sourceSets { } resources.srcDir file('src/integration-test/resources') } + integrationTestJdbcPermission { + java { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file('src/integration-test/java') + include '**/com/scalar/db/common/*.java' + include '**/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java' + include '**/com/scalar/db/storage/jdbc/JdbcAdminTestUtils.java' + include '**/com/scalar/db/storage/jdbc/JdbcTestUtils.java' + include '**/com/scalar/db/storage/jdbc/JdbcEnv.java' + include '**/com/scalar/db/storage/jdbc/JdbcPermissionIntegrationTest.java' + include '**/com/scalar/db/storage/jdbc/JdbcAdminPermissionIntegrationTest.java' + } + resources.srcDir file('src/integration-test/resources') + } } configurations { @@ -128,6 +146,9 @@ configurations { integrationTestDynamoPermissionImplementation.extendsFrom testImplementation integrationTestDynamoPermissionRuntimeOnly.extendsFrom testRuntimeOnly integrationTestDynamoPermissionCompileOnly.extendsFrom testCompileOnly + integrationTestJdbcPermissionImplementation.extendsFrom testImplementation + integrationTestJdbcPermissionRuntimeOnly.extendsFrom testRuntimeOnly + integrationTestJdbcPermissionCompileOnly.extendsFrom testCompileOnly } dependencies { @@ -264,6 +285,17 @@ task integrationTestDynamoPermission(type: Test) { } } +task integrationTestJdbcPermission(type: Test) { + description = 'Runs the integration tests for JDBC permissions.' + group = 'verification' + testClassesDirs = sourceSets.integrationTestJdbcPermission.output.classesDirs + classpath = sourceSets.integrationTestJdbcPermission.runtimeClasspath + outputs.upToDateWhen { false } // ensures integration tests are run every time when called + options { + systemProperties(System.getProperties().findAll { it.key.toString().startsWith("scalardb") }) + } +} + spotless { java { target 'src/*/java/**/*.java' diff --git a/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcAdminPermissionIntegrationTest.java b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcAdminPermissionIntegrationTest.java new file mode 100644 index 0000000000..d3aa5f9392 --- /dev/null +++ b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcAdminPermissionIntegrationTest.java @@ -0,0 +1,29 @@ +package com.scalar.db.storage.jdbc; + +import com.scalar.db.api.DistributedStorageAdminPermissionIntegrationTestBase; +import com.scalar.db.util.AdminTestUtils; +import com.scalar.db.util.PermissionTestUtils; +import java.util.Properties; + +public class JdbcAdminPermissionIntegrationTest + extends DistributedStorageAdminPermissionIntegrationTestBase { + @Override + protected Properties getProperties(String testName) { + return JdbcEnv.getProperties(testName); + } + + @Override + protected Properties getPropertiesForNormalUser(String testName) { + return JdbcEnv.getPropertiesForNormalUser(testName); + } + + @Override + protected AdminTestUtils getAdminTestUtils(String testName) { + return new JdbcAdminTestUtils(getProperties(testName)); + } + + @Override + protected PermissionTestUtils getPermissionTestUtils(String testName) { + return new JdbcPermissionTestUtils(getProperties(testName)); + } +} diff --git a/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcEnv.java b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcEnv.java index 8c297435bc..0bc38bc559 100644 --- a/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcEnv.java +++ b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcEnv.java @@ -7,10 +7,14 @@ public final class JdbcEnv { private static final String PROP_JDBC_URL = "scalardb.jdbc.url"; private static final String PROP_JDBC_USERNAME = "scalardb.jdbc.username"; private static final String PROP_JDBC_PASSWORD = "scalardb.jdbc.password"; + private static final String PROP_JDBC_NORMAL_USERNAME = "scalardb.jdbc.normal_username"; + private static final String PROP_JDBC_NORMAL_PASSWORD = "scalardb.jdbc.normal_password"; private static final String DEFAULT_JDBC_URL = "jdbc:mysql://localhost:3306/"; private static final String DEFAULT_JDBC_USERNAME = "root"; private static final String DEFAULT_JDBC_PASSWORD = "mysql"; + private static final String DEFAULT_JDBC_NORMAL_USERNAME = "test"; + private static final String DEFAULT_JDBC_NORMAL_PASSWORD = "test"; private JdbcEnv() {} @@ -36,6 +40,17 @@ public static Properties getProperties(String testName) { return properties; } + public static Properties getPropertiesForNormalUser(String testName) { + String username = System.getProperty(PROP_JDBC_NORMAL_USERNAME, DEFAULT_JDBC_NORMAL_USERNAME); + String password = System.getProperty(PROP_JDBC_NORMAL_PASSWORD, DEFAULT_JDBC_NORMAL_PASSWORD); + + Properties properties = getProperties(testName); + properties.setProperty(DatabaseConfig.USERNAME, username); + properties.setProperty(DatabaseConfig.PASSWORD, password); + + return properties; + } + public static boolean isSqlite() { Properties properties = new Properties(); properties.setProperty( diff --git a/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionIntegrationTest.java b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionIntegrationTest.java new file mode 100644 index 0000000000..84d7646cbe --- /dev/null +++ b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionIntegrationTest.java @@ -0,0 +1,28 @@ +package com.scalar.db.storage.jdbc; + +import com.scalar.db.api.DistributedStoragePermissionIntegrationTestBase; +import com.scalar.db.util.AdminTestUtils; +import com.scalar.db.util.PermissionTestUtils; +import java.util.Properties; + +public class JdbcPermissionIntegrationTest extends DistributedStoragePermissionIntegrationTestBase { + @Override + protected Properties getProperties(String testName) { + return JdbcEnv.getProperties(testName); + } + + @Override + protected Properties getPropertiesForNormalUser(String testName) { + return JdbcEnv.getPropertiesForNormalUser(testName); + } + + @Override + protected PermissionTestUtils getPermissionTestUtils(String testName) { + return new JdbcPermissionTestUtils(getProperties(testName)); + } + + @Override + protected AdminTestUtils getAdminTestUtils(String testName) { + return new JdbcAdminTestUtils(getProperties(testName)); + } +} diff --git a/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java new file mode 100644 index 0000000000..2b46e61b69 --- /dev/null +++ b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java @@ -0,0 +1,151 @@ +package com.scalar.db.storage.jdbc; + +import com.scalar.db.config.DatabaseConfig; +import com.scalar.db.util.PermissionTestUtils; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Properties; +import org.apache.commons.dbcp2.BasicDataSource; + +public class JdbcPermissionTestUtils implements PermissionTestUtils { + private final RdbEngineStrategy rdbEngine; + private final BasicDataSource dataSource; + + public JdbcPermissionTestUtils(Properties properties) { + JdbcConfig config = new JdbcConfig(new DatabaseConfig(properties)); + rdbEngine = RdbEngineFactory.create(config); + dataSource = JdbcUtils.initDataSourceForAdmin(config, rdbEngine); + } + + @Override + public void createNormalUser(String userName, String password) { + try (Connection connection = dataSource.getConnection()) { + String createUserSql = getCreateUserSql(userName, password); + try (Statement statement = connection.createStatement()) { + statement.execute(createUserSql); + } + } catch (SQLException e) { + throw new RuntimeException("Failed to create user: " + userName, e); + } + } + + @Override + public void dropNormalUser(String userName) { + try (Connection connection = dataSource.getConnection()) { + String dropUserSql = getDropUserSql(userName); + try (Statement statement = connection.createStatement()) { + statement.execute(dropUserSql); + } + } catch (SQLException e) { + throw new RuntimeException("Failed to drop user: " + userName, e); + } + } + + @Override + public void grantRequiredPermission(String userName) { + try (Connection connection = dataSource.getConnection()) { + String[] grantStatements = getGrantPermissionStatements(userName); + try (Statement statement = connection.createStatement()) { + for (String sql : grantStatements) { + statement.execute(sql); + } + } + } catch (SQLException e) { + throw new RuntimeException("Failed to grant permissions to user: " + userName, e); + } + } + + private String getCreateUserSql(String userName, String password) { + if (JdbcTestUtils.isMysql(rdbEngine)) { + return String.format("CREATE USER '%s'@'%%' IDENTIFIED BY '%s'", userName, password); + } else if (JdbcTestUtils.isOracle(rdbEngine)) { + return String.format("CREATE USER %s IDENTIFIED BY %s", userName, password); + } else if (JdbcTestUtils.isPostgresql(rdbEngine)) { + return String.format("CREATE USER %s WITH PASSWORD '%s'", userName, password); + } else if (JdbcTestUtils.isSqlite(rdbEngine)) { + throw new UnsupportedOperationException("SQLite does not support user management"); + } else if (JdbcTestUtils.isSqlServer(rdbEngine)) { + return String.format( + "CREATE LOGIN %s WITH PASSWORD = '%s', DEFAULT_DATABASE = master , CHECK_POLICY = OFF, CHECK_EXPIRATION = OFF; CREATE USER %s FOR LOGIN %s", + userName, password, userName, userName); + } else if (JdbcTestUtils.isDb2(rdbEngine)) { + return String.format("CREATE USER %s IDENTIFIED BY %s", userName, password); + } else { + throw new UnsupportedOperationException("Creating users is not supported for " + rdbEngine); + } + } + + private String getDropUserSql(String userName) { + if (JdbcTestUtils.isMysql(rdbEngine)) { + return String.format("DROP USER '%s'@'%%'", userName); + } else if (JdbcTestUtils.isOracle(rdbEngine)) { + return String.format("DROP USER %s", userName); + } else if (JdbcTestUtils.isPostgresql(rdbEngine)) { + return String.format("DROP USER %s", userName); + } else if (JdbcTestUtils.isSqlite(rdbEngine)) { + throw new UnsupportedOperationException("SQLite does not support user management"); + } else if (JdbcTestUtils.isSqlServer(rdbEngine)) { + return String.format("DROP USER %s; DROP LOGIN %s", userName, userName); + } else if (JdbcTestUtils.isDb2(rdbEngine)) { + return String.format("DROP USER %s", userName); + } else { + throw new UnsupportedOperationException("Dropping users is not supported for " + rdbEngine); + } + } + + private String[] getGrantPermissionStatements(String userName) { + if (JdbcTestUtils.isMysql(rdbEngine)) { + return new String[] { + String.format("GRANT CREATE ON *.* TO '%s'@'%%'", userName), + String.format("GRANT DROP ON *.* TO '%s'@'%%'", userName), + String.format("GRANT INDEX ON *.* TO '%s'@'%%'", userName), + String.format("GRANT ALTER ON *.* TO '%s'@'%%'", userName), + String.format("GRANT SELECT ON *.* TO '%s'@'%%'", userName), + String.format("GRANT INSERT ON *.* TO '%s'@'%%'", userName), + String.format("GRANT UPDATE ON *.* TO '%s'@'%%'", userName), + String.format("GRANT DELETE ON *.* TO '%s'@'%%'", userName) + }; + } else if (JdbcTestUtils.isOracle(rdbEngine)) { + return new String[] { + String.format("GRANT CREATE SESSION TO %s", userName), + String.format("GRANT CREATE USER TO %s", userName), + String.format("GRANT DROP USER TO %s", userName), + String.format("GRANT ALTER USER TO %s", userName), + String.format("GRANT CREATE ANY TABLE TO %s", userName), + String.format("GRANT DROP ANY TABLE TO %s", userName), + String.format("GRANT CREATE ANY INDEX TO %s", userName), + String.format("GRANT DROP ANY INDEX TO %s", userName), + String.format("GRANT ALTER ANY TABLE TO %s", userName), + String.format("GRANT SELECT ANY TABLE TO %s", userName), + String.format("GRANT INSERT ANY TABLE TO %s", userName), + String.format("GRANT UPDATE ANY TABLE TO %s", userName), + String.format("GRANT DELETE ANY TABLE TO %s", userName) + }; + } else if (JdbcTestUtils.isPostgresql(rdbEngine)) { + return new String[] {String.format("ALTER ROLE %s SUPERUSER;", userName)}; + } else if (JdbcTestUtils.isSqlite(rdbEngine)) { + throw new UnsupportedOperationException("SQLite does not support authorization mechanism"); + } else if (JdbcTestUtils.isSqlServer(rdbEngine)) { + return new String[] { + String.format("ALTER ROLE [db_ddladmin] ADD MEMBER %s", userName), + String.format("ALTER ROLE [db_datareader] ADD MEMBER %s", userName), + String.format("ALTER ROLE [db_datawriter] ADD MEMBER %s", userName) + }; + } else if (JdbcTestUtils.isDb2(rdbEngine)) { + return new String[] {}; + } else { + throw new UnsupportedOperationException( + "Granting permissions is not supported for " + rdbEngine); + } + } + + @Override + public void close() { + try { + dataSource.close(); + } catch (Exception e) { + throw new RuntimeException("Failed to close the data source", e); + } + } +} From c35767271d75d8fb869897c78e2f8abc94dc8a00 Mon Sep 17 00:00:00 2001 From: Kodai Doki Date: Tue, 22 Jul 2025 13:02:27 +0900 Subject: [PATCH 2/3] Update --- .../com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java index 2b46e61b69..c24e1c98f5 100644 --- a/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java +++ b/core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java @@ -69,8 +69,6 @@ private String getCreateUserSql(String userName, String password) { return String.format( "CREATE LOGIN %s WITH PASSWORD = '%s', DEFAULT_DATABASE = master , CHECK_POLICY = OFF, CHECK_EXPIRATION = OFF; CREATE USER %s FOR LOGIN %s", userName, password, userName, userName); - } else if (JdbcTestUtils.isDb2(rdbEngine)) { - return String.format("CREATE USER %s IDENTIFIED BY %s", userName, password); } else { throw new UnsupportedOperationException("Creating users is not supported for " + rdbEngine); } @@ -87,8 +85,6 @@ private String getDropUserSql(String userName) { throw new UnsupportedOperationException("SQLite does not support user management"); } else if (JdbcTestUtils.isSqlServer(rdbEngine)) { return String.format("DROP USER %s; DROP LOGIN %s", userName, userName); - } else if (JdbcTestUtils.isDb2(rdbEngine)) { - return String.format("DROP USER %s", userName); } else { throw new UnsupportedOperationException("Dropping users is not supported for " + rdbEngine); } @@ -132,8 +128,6 @@ private String[] getGrantPermissionStatements(String userName) { String.format("ALTER ROLE [db_datareader] ADD MEMBER %s", userName), String.format("ALTER ROLE [db_datawriter] ADD MEMBER %s", userName) }; - } else if (JdbcTestUtils.isDb2(rdbEngine)) { - return new String[] {}; } else { throw new UnsupportedOperationException( "Granting permissions is not supported for " + rdbEngine); From 17eaaca750b5452de63b2255d654c87b07830b68 Mon Sep 17 00:00:00 2001 From: Kodai Doki Date: Tue, 22 Jul 2025 18:52:33 +0900 Subject: [PATCH 3/3] [skip ci] Fix workflow file --- .github/workflows/permission-check.yaml | 76 ++++++++++++++----------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/.github/workflows/permission-check.yaml b/.github/workflows/permission-check.yaml index 0eced7fd1f..b562b7a65b 100644 --- a/.github/workflows/permission-check.yaml +++ b/.github/workflows/permission-check.yaml @@ -135,7 +135,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Execute Gradle 'integrationTestJdbcPermission' task - run: ./gradlew integrationTestJdbcPermission + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:mysql://localhost:3306/ -Dscalardb.jdbc.username=root -Dscalardb.jdbc.password=mysql - name: Upload Gradle test reports if: always() @@ -164,7 +164,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Execute Gradle 'integrationTestJdbcPermission' task - run: ./gradlew integrationTestJdbcPermission + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:mysql://localhost:3306/ -Dscalardb.jdbc.username=root -Dscalardb.jdbc.password=mysql - name: Upload Gradle test reports if: always() @@ -193,7 +193,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Execute Gradle 'integrationTestJdbcPermission' task - run: ./gradlew integrationTestJdbcPermission + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:mysql://localhost:3306/ -Dscalardb.jdbc.username=root -Dscalardb.jdbc.password=mysql - name: Upload Gradle test reports if: always() @@ -422,8 +422,15 @@ jobs: credentials: username: ${{ github.repository_owner }} password: ${{ secrets.CR_PAT }} + env: + ORACLE_PWD: Oracle ports: - 1521:1521 + options: >- + --health-cmd "/opt/oracle/checkDBStatus.sh" + --health-interval 10s + --health-timeout 5s + --health-retries 120 steps: - uses: actions/checkout@v4 @@ -438,7 +445,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Execute Gradle 'integrationTestJdbcPermission' task - run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:oracle:thin:@//localhost:1521/ORCLPDB1 -Dscalardb.jdbc.username=SYSTEM -Dscalardb.jdbc.password=Oracle + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:oracle:thin:@//localhost:1521/XEPDB1 -Dscalardb.jdbc.username=SYSTEM -Dscalardb.jdbc.password=Oracle - name: Upload Gradle test reports if: always() @@ -451,15 +458,6 @@ jobs: name: Oracle 23 Permission Integration Test runs-on: ubuntu-latest - services: - oracle: - image: ghcr.io/scalar-labs/oracle/db-prebuilt:23 - credentials: - username: ${{ github.repository_owner }} - password: ${{ secrets.CR_PAT }} - ports: - - 1521:1521 - steps: - name: Free up ~14GB of disk space by removing the Android SDK run: | @@ -502,7 +500,11 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Execute Gradle 'integrationTestJdbcPermission' task - run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:oracle:thin:@//localhost:1521/ORCLPDB1 -Dscalardb.jdbc.username=SYSTEM -Dscalardb.jdbc.password=Oracle + run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:oracle:thin:@//localhost:1521/FREEPDB1 -Dscalardb.jdbc.username=SYSTEM -Dscalardb.jdbc.password=Oracle + + - name: Stop Oracle 23 container + if: always() + run: docker stop oracle-23 | xargs docker rm - name: Upload Gradle test reports if: always() @@ -513,7 +515,7 @@ jobs: integration-test-permission-jdbc-sqlserver-2017: name: SQL Server 2017 Permission Integration Test - runs-on: ubuntu-latest + runs-on: windows-latest steps: - uses: actions/checkout@v4 @@ -535,7 +537,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Execute Gradle 'integrationTestJdbcPermission' task - run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:sqlserver://localhost:1433;encrypt=false -Dscalardb.jdbc.username=sa -Dscalardb.jdbc.password=SqlServer17 + run: ./gradlew integrationTestJdbcPermission "-Dscalardb.jdbc.url=jdbc:sqlserver://localhost:1433;encrypt=true;trustServerCertificate=true" "-Dscalardb.jdbc.username=sa" "-Dscalardb.jdbc.password=SqlServer17" "-Dfile.encoding=UTF-8" - name: Upload Gradle test reports if: always() @@ -548,16 +550,20 @@ jobs: name: SQL Server 2019 Permission Integration Test runs-on: ubuntu-latest + services: + sqlserver: + image: mcr.microsoft.com/mssql/server:2019-latest + env: + MSSQL_PID: "Express" + SA_PASSWORD: "SqlServer19" + ACCEPT_EULA: "Y" + ports: + - 1433:1433 + options: --name sqlserver19 + steps: - uses: actions/checkout@v4 - - name: Setup Sql Server 2019 - uses: rails-sqlserver/setup-mssql@v1 - with: - components: sqlcmd,sqlengine - sa-password: "SqlServer19" - version: 2019 - - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) uses: actions/setup-java@v4 with: @@ -568,7 +574,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Execute Gradle 'integrationTestJdbcPermission' task - run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:sqlserver://localhost:1433;encrypt=false -Dscalardb.jdbc.username=sa -Dscalardb.jdbc.password=SqlServer19 + run: ./gradlew integrationTestJdbcPermission "-Dscalardb.jdbc.url=jdbc:sqlserver://localhost:1433;encrypt=true;trustServerCertificate=true" "-Dscalardb.jdbc.username=sa" "-Dscalardb.jdbc.password=SqlServer19" - name: Upload Gradle test reports if: always() @@ -581,16 +587,20 @@ jobs: name: SQL Server 2022 Permission Integration Test runs-on: ubuntu-latest + services: + sqlserver: + image: mcr.microsoft.com/mssql/server:2022-latest + env: + MSSQL_PID: "Express" + SA_PASSWORD: "SqlServer22" + ACCEPT_EULA: "Y" + ports: + - 1433:1433 + options: --name sqlserver22 + steps: - uses: actions/checkout@v4 - - name: Setup Sql Server 2022 - uses: rails-sqlserver/setup-mssql@v1 - with: - components: sqlcmd,sqlengine - sa-password: "SqlServer22" - version: 2022 - - name: Set up JDK ${{ env.JAVA_VERSION }} (${{ env.JAVA_VENDOR }}) uses: actions/setup-java@v4 with: @@ -601,7 +611,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Execute Gradle 'integrationTestJdbcPermission' task - run: ./gradlew integrationTestJdbcPermission -Dscalardb.jdbc.url=jdbc:sqlserver://localhost:1433;encrypt=false -Dscalardb.jdbc.username=sa -Dscalardb.jdbc.password=SqlServer22 + run: ./gradlew integrationTestJdbcPermission "-Dscalardb.jdbc.url=jdbc:sqlserver://localhost:1433;encrypt=true;trustServerCertificate=true" "-Dscalardb.jdbc.username=sa" "-Dscalardb.jdbc.password=SqlServer22" - name: Upload Gradle test reports if: always() @@ -609,5 +619,3 @@ jobs: with: name: sqlserver_2022_permission_integration_test_reports path: core/build/reports/tests/integrationTestJdbcPermission - -