Skip to content

Commit

Permalink
[UqrhpreJ] CypherInitializer Cypher 25 support (#684)
Browse files Browse the repository at this point in the history
  • Loading branch information
loveleif authored Nov 11, 2024
1 parent f0c8172 commit fb158a2
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 108 deletions.
28 changes: 18 additions & 10 deletions common/src/main/java/apoc/util/LogsUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,34 @@
*/
package apoc.util;

import org.neo4j.configuration.Config;
import org.neo4j.cypher.internal.PreParser;
import org.neo4j.cypher.internal.ast.Statement;
import org.neo4j.cypher.internal.ast.factory.neo4j.JavaCCParser;
import org.neo4j.cypher.internal.ast.prettifier.DefaultExpressionStringifier;
import org.neo4j.cypher.internal.ast.prettifier.ExpressionStringifier;
import org.neo4j.cypher.internal.ast.prettifier.ExpressionStringifier$;
import org.neo4j.cypher.internal.ast.prettifier.Prettifier;
import org.neo4j.cypher.internal.config.CypherConfiguration;
import org.neo4j.cypher.internal.parser.AstParserFactory$;
import org.neo4j.cypher.internal.rewriting.rewriters.sensitiveLiteralReplacement;
import org.neo4j.cypher.internal.util.OpenCypherExceptionFactory;
import org.neo4j.cypher.internal.util.RecordingNotificationLogger;
import scala.Option;

public class LogsUtil {
private static OpenCypherExceptionFactory exceptionFactory = new OpenCypherExceptionFactory(scala.Option.empty());
private static ExpressionStringifier.Extension extension =
ExpressionStringifier.Extension$.MODULE$.simple((ExpressionStringifier$.MODULE$.failingExtender()));
private static ExpressionStringifier stringifier =
new DefaultExpressionStringifier(extension, false, false, false, false);
private static Prettifier prettifier = new Prettifier(stringifier, Prettifier.EmptyExtension$.MODULE$, true);

public static String sanitizeQuery(String query) {
public static String sanitizeQuery(Config config, String query) {
try {
var statement = JavaCCParser.parse(query, exceptionFactory, null);
final var exceptionFactory = new OpenCypherExceptionFactory(scala.Option.empty());
final var extension =
ExpressionStringifier.Extension$.MODULE$.simple((ExpressionStringifier$.MODULE$.failingExtender()));
final var stringifier = new DefaultExpressionStringifier(extension, false, false, false, false);
final var prettifier = new Prettifier(stringifier, Prettifier.EmptyExtension$.MODULE$, true);
var notifications = new RecordingNotificationLogger();
final var preParsed = new PreParser(CypherConfiguration.fromConfig(config)).preParse(query, notifications);
final var statement = AstParserFactory$.MODULE$
.apply(preParsed.options().queryOptions().cypherVersion().actualVersion())
.apply(preParsed.statement(), exceptionFactory, Option.apply(null))
.singleStatement();
var rewriter = sensitiveLiteralReplacement.apply(statement)._1;
var res = (Statement) rewriter.apply(statement);

Expand Down
35 changes: 0 additions & 35 deletions common/src/main/java/apoc/util/QueryUtil.java

This file was deleted.

29 changes: 13 additions & 16 deletions core/src/main/java/apoc/cypher/CypherInitializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import apoc.ApocConfig;
import apoc.SystemLabels;
import apoc.util.LogsUtil;
import apoc.util.QueryUtil;
import apoc.util.Util;
import apoc.util.collection.Iterators;
import apoc.version.Version;
Expand All @@ -34,6 +33,7 @@
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.neo4j.common.DependencyResolver;
import org.neo4j.configuration.Config;
import org.neo4j.dbms.api.DatabaseManagementService;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
Expand Down Expand Up @@ -105,21 +105,18 @@ public void available() {
Configuration config = dependencyResolver
.resolveDependency(ApocConfig.class)
.getConfig();
for (String query : collectInitializers(config)) {
if (QueryUtil.isValidQuery(query)) {
String sanitizedQuery = LogsUtil.sanitizeQuery(query);
try {
// we need to apply a retry strategy here since in systemdb we potentially conflict
// with
// creating constraints which could cause our query to fail with a transient error.
Util.retryInTx(
userLog, db, tx -> Iterators.count(tx.execute(query)), 0, 5, retries -> {});
userLog.info("successfully initialized: " + sanitizedQuery);
} catch (Exception e) {
userLog.error("error upon initialization, running: " + sanitizedQuery, e);
}
} else {
userLog.error("error upon initialization, invalid query: " + query);
for (final var query : collectInitializers(config)) {
final var sanitizedQuery =
LogsUtil.sanitizeQuery(dependencyResolver.resolveDependency(Config.class), query);
try {
// we need to apply a retry strategy here since in systemdb we potentially conflict
// with
// creating constraints which could cause our query to fail with a transient error.
Util.retryInTx(
userLog, db, tx -> Iterators.count(tx.execute(query)), 0, 5, retries -> {});
userLog.info("successfully initialized: " + sanitizedQuery);
} catch (Exception e) {
userLog.error("error upon initialization, running: " + sanitizedQuery, e);
}
}
} catch (Exception e) {
Expand Down
8 changes: 5 additions & 3 deletions core/src/test/java/apoc/util/LogsUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,29 @@
import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.neo4j.configuration.Config;

public class LogsUtilTest {

@Test
public void shouldRedactPasswords() {
String sanitized =
LogsUtil.sanitizeQuery("CREATE USER dummy IF NOT EXISTS SET PASSWORD 'pass12345' CHANGE NOT REQUIRED");
String sanitized = LogsUtil.sanitizeQuery(
Config.defaults(), "CREATE USER dummy IF NOT EXISTS SET PASSWORD 'pass12345' CHANGE NOT REQUIRED");
assertEquals(sanitized, "CREATE USER dummy IF NOT EXISTS SET PASSWORD '******' CHANGE NOT REQUIRED");
}

@Test
public void shouldReturnInputIfInvalidQuery() {
String invalidQuery = "MATCH USER dummy IF NOT EXISTS SET PASSWORD 'pass12345' CHANGE NOT REQUIRED";
String sanitized = LogsUtil.sanitizeQuery(invalidQuery);
String sanitized = LogsUtil.sanitizeQuery(Config.defaults(), invalidQuery);

assertEquals(sanitized, invalidQuery);
}

@Test
public void whitespaceDeprecationSucceedsSanitization() {
String sanitized = LogsUtil.sanitizeQuery(
Config.defaults(),
"CREATE USER dum\u0085my IF NOT EXISTS SET PASSWORD 'pass12345' CHANGE NOT REQUIRED");
assertEquals(sanitized, "CREATE USER `dum\u0085my` IF NOT EXISTS SET PASSWORD '******' CHANGE NOT REQUIRED");
}
Expand Down
44 changes: 0 additions & 44 deletions core/src/test/java/apoc/util/QueryUtilTest.java

This file was deleted.

0 comments on commit fb158a2

Please sign in to comment.