Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add forbidden api checker #418

Merged
merged 10 commits into from
Jun 22, 2024
1 change: 1 addition & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ dependencies {
implementation("net.ltgt.gradle:gradle-errorprone-plugin:3.1.0")
implementation("info.solidsoft.gradle.pitest:gradle-pitest-plugin:1.15.0")
implementation("org.gradle:test-retry-gradle-plugin:1.5.9")
implementation(libs.forbiddenapis)
}
18 changes: 18 additions & 0 deletions buildSrc/src/main/kotlin/pg-index-health.forbidden-apis.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis

plugins {
id("java")
id("de.thetaphi.forbiddenapis")
}

forbiddenApis {
bundledSignatures = setOf("jdk-unsafe", "jdk-deprecated", "jdk-internal", "jdk-non-portable", "jdk-system-out", "jdk-reflection")
signaturesFiles = files("${rootDir}/config/forbidden-apis/forbidden-apis.txt")
mfvanek marked this conversation as resolved.
Show resolved Hide resolved
ignoreFailures = false
}

tasks {
test {
dependsOn(withType<CheckForbiddenApis>())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
plugins {
id("pg-index-health.java-compilation")
id("pg-index-health.java-conventions")
id("pg-index-health.forbidden-apis")
}

private val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")

dependencies {
versionCatalog.findLibrary("slf4j-simple").ifPresent {
spotbugsSlf4j(it)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
id("jacoco")
}

val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
private val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")

dependencies {
versionCatalog.findLibrary("jsr305").ifPresent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ plugins {
}

dependencies {
checkstyle("com.thomasjensen.checkstyle.addons:checkstyle-addons:7.0.1")

errorprone("com.google.errorprone:error_prone_core:2.27.1")
errorprone("jp.skypencil.errorprone.slf4j:errorprone-slf4j:0.1.24")

Expand Down Expand Up @@ -75,23 +73,23 @@ tasks {
}

checkstyle {
toolVersion = "10.16.0"
configFile = file("../config/checkstyle/checkstyle.xml")
toolVersion = "10.17.0"
configFile = file("${rootDir}/config/checkstyle/checkstyle.xml")
isIgnoreFailures = false
maxWarnings = 0
maxErrors = 0
}

pmd {
toolVersion = "7.1.0"
toolVersion = "7.2.0"
isConsoleOutput = true
ruleSetFiles = files("../config/pmd/pmd.xml")
ruleSetFiles = files("${rootDir}/config/pmd/pmd.xml")
ruleSets = listOf()
}

spotbugs {
showProgress.set(true)
effort.set(Effort.MAX)
reportLevel.set(Confidence.LOW)
excludeFilter.set(file("../config/spotbugs/exclude.xml"))
excludeFilter.set(file("${rootDir}/config/spotbugs/exclude.xml"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
id("java-library")
id("pg-index-health.java-compilation")
id("pg-index-health.java-conventions")
id("pg-index-health.forbidden-apis")
id("pg-index-health.publish")
}
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/pg-index-health.pitest.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import info.solidsoft.gradle.pitest.PitestTask

plugins {
id("java-library")
id("java")
id("info.solidsoft.pitest")
}

Expand All @@ -11,7 +11,7 @@ dependencies {

pitest {
junit5PluginVersion.set("1.2.1")
pitestVersion.set("1.15.8")
pitestVersion.set("1.16.1")
threads.set(4)
if (System.getenv("STRYKER_DASHBOARD_API_KEY") != null) {
outputFormats.set(setOf("stryker-dashboard"))
Expand Down
5 changes: 0 additions & 5 deletions config/checkstyle/checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,5 @@
<module name="CommentsIndentation">
<property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/>
</module>
<module name="IllegalMethodCall">
mfvanek marked this conversation as resolved.
Show resolved Hide resolved
<property name="illegalMethodNames"
value="emptyList,emptyMap,emptySet,emptyNavigableMap,emptyNavigableSet,emptySortedMap,emptySortedSet,singleton,singletonList,singletonMap,asList,unmodifiableList,unmodifiableSet"/>
<property name="excludedQualifiers" value=""/>
</module>
</module>
</module>
14 changes: 14 additions & 0 deletions config/forbidden-apis/forbidden-apis.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@defaultMessage Avoid using these methods, consider alternative approaches
java.util.Collections#emptyList()
java.util.Collections#emptyMap()
java.util.Collections#emptySet()
java.util.Collections#emptyNavigableMap()
java.util.Collections#emptyNavigableSet()
java.util.Collections#emptySortedMap()
java.util.Collections#emptySortedSet()
java.util.Collections#singleton(java.lang.Object)
java.util.Collections#singletonList(java.lang.Object)
java.util.Collections#singletonMap(java.lang.Object,java.lang.Object)
java.util.Arrays#asList(java.lang.Object[])
java.util.Collections#unmodifiableList(java.util.List)
java.util.Collections#unmodifiableSet(java.util.Set)
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ assertj = "3.25.3"
testcontainers = "1.19.8"
junit = "5.10.2"
mockito = "5.12.0"
forbiddenapis = "3.7"

[libraries]
jsr305 = "com.google.code.findbugs:jsr305:3.0.2"
Expand All @@ -26,6 +27,7 @@ spring-boot-starter-data-jdbc = { group = "org.springframework.boot", name = "sp
detekt-formatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" }
detekt-libraries = { group = "io.gitlab.arturbosch.detekt", name = "detekt-rules-libraries", version.ref = "detekt" }
testcontainers-bom = { group = "org.testcontainers", name = "testcontainers-bom", version.ref = "testcontainers" }
forbiddenapis = { group = "de.thetaphi", name = "forbiddenapis", version.ref = "forbiddenapis" }

[plugins]
spring-boot-gradlePlugin = { id = "org.springframework.boot", version.ref = "spring-boot" }
Expand Down
5 changes: 1 addition & 4 deletions pg-index-health-core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
plugins {
id("java-library")
id("pg-index-health.java-compilation")
id("pg-index-health.java-conventions")
id("pg-index-health.publish")
id("pg-index-health.java-library")
}

description = "pg-index-health-core is a Java library for analyzing and maintaining indexes and tables health in PostgreSQL databases on a specific host."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -80,7 +81,7 @@ public PgParam getParamCurrentValue(@Nonnull final ParamNameAware paramName) {

@Nonnull
private PgParam getCurrentValue(@Nonnull final String paramName) {
final String sqlQuery = String.format("show %s;", paramName);
final String sqlQuery = String.format(Locale.ROOT, "show %s;", paramName);
final List<PgParam> params = QueryExecutors.executeQuery(pgConnection, sqlQuery, rs -> {
final String currentValue = rs.getString(paramName);
return PgParamImpl.of(paramName, currentValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.Locale;

import static io.github.mfvanek.pg.support.AbstractCheckOnHostAssert.assertThat;

class ColumnsWithSerialTypesCheckOnHostTest extends DatabaseAwareTestBase {
Expand All @@ -44,9 +46,9 @@ void onDatabaseWithThem(final String schemaName) {
.hasSize(2)
.containsExactly(
ColumnWithSerialType.ofBigSerial(
Column.ofNotNull(ctx.enrichWithSchema("bad_accounts"), "real_account_id"), String.format("%s.bad_accounts_real_account_id_seq", schemaName)),
Column.ofNotNull(ctx.enrichWithSchema("bad_accounts"), "real_account_id"), String.format(Locale.ROOT, "%s.bad_accounts_real_account_id_seq", schemaName)),
mfvanek marked this conversation as resolved.
Show resolved Hide resolved
ColumnWithSerialType.ofBigSerial(
Column.ofNotNull(ctx.enrichWithSchema("bad_accounts"), "real_client_id"), String.format("%s.bad_accounts_real_client_id_seq", schemaName))
Column.ofNotNull(ctx.enrichWithSchema("bad_accounts"), "real_client_id"), String.format(Locale.ROOT, "%s.bad_accounts_real_client_id_seq", schemaName))
));
}

Expand All @@ -59,7 +61,7 @@ void shouldIgnoreDroppedColumns(final String schemaName) {
.hasSize(1)
.containsExactly(
ColumnWithSerialType.ofBigSerial(
Column.ofNotNull(ctx.enrichWithSchema("bad_accounts"), "real_client_id"), String.format("%s.bad_accounts_real_client_id_seq", schemaName))
Column.ofNotNull(ctx.enrichWithSchema("bad_accounts"), "real_client_id"), String.format(Locale.ROOT, "%s.bad_accounts_real_client_id_seq", schemaName))
));
}

Expand All @@ -81,7 +83,7 @@ void shouldDetectSerialColumnsWithUniqueConstraints(final String schemaName) {
.hasSize(1)
.containsExactly(
ColumnWithSerialType.ofBigSerial(
Column.ofNotNull(ctx.enrichWithSchema("one_more_table"), "id"), String.format("%s.one_more_table_id_seq", schemaName))
Column.ofNotNull(ctx.enrichWithSchema("one_more_table"), "id"), String.format(Locale.ROOT, "%s.one_more_table_id_seq", schemaName))
));
}

Expand All @@ -94,11 +96,11 @@ void shouldDetectPrimaryKeysThatAreForeignKeysAsWell(final String schemaName) {
.hasSize(3)
.containsExactly(
ColumnWithSerialType.ofBigSerial(
Column.ofNotNull(ctx.enrichWithSchema("one_more_table"), "id"), String.format("%s.one_more_table_id_seq", schemaName)),
Column.ofNotNull(ctx.enrichWithSchema("one_more_table"), "id"), String.format(Locale.ROOT, "%s.one_more_table_id_seq", schemaName)),
ColumnWithSerialType.ofBigSerial(
Column.ofNotNull(ctx.enrichWithSchema("test_table"), "id"), String.format("%s.test_table_id_seq", schemaName)),
Column.ofNotNull(ctx.enrichWithSchema("test_table"), "id"), String.format(Locale.ROOT, "%s.test_table_id_seq", schemaName)),
ColumnWithSerialType.ofBigSerial(
Column.ofNotNull(ctx.enrichWithSchema("test_table"), "num"), String.format("%s.test_table_num_seq", schemaName))
Column.ofNotNull(ctx.enrichWithSchema("test_table"), "num"), String.format(Locale.ROOT, "%s.test_table_num_seq", schemaName))
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.junit.jupiter.params.provider.ValueSource;

import java.util.List;
import java.util.Locale;

import static io.github.mfvanek.pg.support.AbstractCheckOnHostAssert.assertThat;

Expand Down Expand Up @@ -51,7 +52,7 @@ void onDatabaseWithThem(final String schemaName) {

ExecuteUtils.executeOnDatabase(getDataSource(), statement -> {
for (final Constraint constraint : notValidConstraints) {
statement.execute(String.format("alter table %s validate constraint %s;",
statement.execute(String.format(Locale.ROOT, "alter table %s validate constraint %s;",
constraint.getTableName(), constraint.getConstraintName()));
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.Locale;

import static io.github.mfvanek.pg.support.AbstractCheckOnHostAssert.assertThat;

class PrimaryKeysWithSerialTypesCheckOnHostTest extends DatabaseAwareTestBase {
Expand All @@ -43,7 +45,7 @@ void onDatabaseWithThem(final String schemaName) {
.hasSize(1)
.containsExactlyInAnyOrder(
ColumnWithSerialType.of(
Column.ofNotNull(ctx.enrichWithSchema("bad_accounts"), "id"), SerialType.BIG_SERIAL, String.format("%s.bad_accounts_id_seq", schemaName)
Column.ofNotNull(ctx.enrichWithSchema("bad_accounts"), "id"), SerialType.BIG_SERIAL, String.format(Locale.ROOT, "%s.bad_accounts_id_seq", schemaName)
)));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
Expand Down Expand Up @@ -304,7 +305,7 @@ public void populate() {
private void createInvalidIndex() {
try (Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()) {
statement.execute(String.format("create unique index concurrently if not exists " +
statement.execute(String.format(Locale.ROOT, "create unique index concurrently if not exists " +
"i_clients_last_name_first_name on %s.clients (last_name, first_name)", schemaName));
} catch (SQLException ignored) {
// do nothing, just skip error
Expand All @@ -313,6 +314,6 @@ private void createInvalidIndex() {

@Override
public void close() {
ExecuteUtils.executeOnDatabase(dataSource, statement -> statement.execute(String.format("drop schema if exists %s cascade", schemaName)));
ExecuteUtils.executeOnDatabase(dataSource, statement -> statement.execute(String.format(Locale.ROOT, "drop schema if exists %s cascade", schemaName)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Locale;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -64,7 +65,7 @@ protected void tryToFindAccountByClientId(@Nonnull final String schemaName) {
try (Connection connection = getDataSource().getConnection();
Statement statement = connection.createStatement()) {
for (int counter = 0; counter < AMOUNT_OF_TRIES; ++counter) {
statement.execute(String.format("select count(*) from %s.accounts where client_id = 1::bigint", schemaName));
statement.execute(String.format(Locale.ROOT, "select count(*) from %s.accounts where client_id = 1::bigint", schemaName));
}
} catch (SQLException e) {
throw new PgSqlException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nonnull;

public abstract class AbstractDbStatement implements DbStatement {
Expand All @@ -25,7 +26,7 @@ protected void throwExceptionIfTableDoesNotExist(
@Nonnull final String tableName,
@Nonnull final String schemaName
) throws SQLException {
final String checkQuery = String.format("select exists (%n" +
final String checkQuery = String.format(Locale.ROOT, "select exists (%n" +
" select 1 %n" +
" from pg_catalog.pg_class c%n" +
" join pg_catalog.pg_namespace n on n.oid = c.relnamespace%n" +
Expand All @@ -40,7 +41,7 @@ protected void throwExceptionIfTableDoesNotExist(
return;
}
}
throw new IllegalStateException(String.format("Table with name '%s' in schema '%s' wasn't created", tableName, schemaName));
throw new IllegalStateException(String.format(Locale.ROOT, "Table with name '%s' in schema '%s' wasn't created", tableName, schemaName));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nonnull;

public class CreateCustomCollationStatement extends AbstractDbStatement {
Expand All @@ -40,7 +41,7 @@ public void execute(@Nonnull final Statement statement) throws SQLException {

private boolean isCollationExist(@Nonnull final Statement statement, @Nonnull final String collation) {
final String sqlQuery = "select exists(select 1 from pg_catalog.pg_collation as pgc where pgc.collname = '%s'::text)";
try (ResultSet rs = statement.executeQuery(String.format(sqlQuery, collation))) {
try (ResultSet rs = statement.executeQuery(String.format(Locale.ROOT, sqlQuery, collation))) {
rs.next();
return rs.getBoolean(1);
} catch (SQLException e) {
Expand All @@ -51,9 +52,9 @@ private boolean isCollationExist(@Nonnull final Statement statement, @Nonnull fi
private void createCustomCollation(@Nonnull final Statement statement,
@Nonnull final String customCollation) throws SQLException {
if (!isCollationExist(statement, ICU_COLLATION)) {
throw new IllegalStateException(String.format("System collation '%s' not found", ICU_COLLATION));
throw new IllegalStateException(String.format(Locale.ROOT, "System collation '%s' not found", ICU_COLLATION));
}
final String query = "create collation %s.\"%s\" from \"%s\";";
statement.execute(String.format(query, SchemaNameHolder.getSchemaName(), customCollation, ICU_COLLATION));
statement.execute(String.format(Locale.ROOT, query, SchemaNameHolder.getSchemaName(), customCollation, ICU_COLLATION));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nonnull;

public class CreateSchemaStatement extends AbstractDbStatement {
Expand All @@ -27,7 +28,7 @@ protected List<String> getSqlToExecute() {
@Override
public void postExecute(@Nonnull final Statement statement, @Nonnull final String schemaName) throws SQLException {
final String checkQuery = String.format(
"select exists(select 1 from information_schema.schemata where schema_name = '%s')", schemaName);
Locale.ROOT, "select exists(select 1 from information_schema.schemata where schema_name = '%s')", schemaName);
try (ResultSet rs = statement.executeQuery(checkQuery)) {
if (rs.next()) {
final boolean schemaExists = rs.getBoolean(1);
Expand Down
Loading