Skip to content

Commit

Permalink
[D2VH2D8O] Only create trigger listeners on system db. (#391)
Browse files Browse the repository at this point in the history
Adding listeners to each database can cause nodes from user databases to be removed, as well as cause issues with concurrent drop database commands.
  • Loading branch information
Lojjs authored May 4, 2023
1 parent 9498f9a commit a8df1a1
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
4 changes: 1 addition & 3 deletions core/src/main/java/apoc/cypher/CypherInitializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,9 @@ public void available() {
"The two first numbers of both versions needs to be the same.",
apocVersion, neo4jVersion );
}
databaseEventListeners.registerDatabaseEventListener(new SystemFunctionalityListener());
}

// create listener for each database
databaseEventListeners.registerDatabaseEventListener(new SystemFunctionalityListener());

Configuration config = dependencyResolver.resolveDependency(ApocConfig.class).getConfig();
for (String query : collectInitializers(config)) {
try {
Expand Down
34 changes: 34 additions & 0 deletions it/src/test/java/apoc/it/core/TriggerEnterpriseFeaturesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* limitations under the License.
*/
package apoc.it.core;
import apoc.SystemLabels;
import apoc.util.Neo4jContainerExtension;
import apoc.util.TestContainerUtil;
import org.junit.After;
Expand All @@ -38,6 +39,7 @@

import static apoc.ApocConfig.APOC_CONFIG_INITIALIZER;
import static apoc.ApocConfig.APOC_TRIGGER_ENABLED;
import static apoc.SystemPropertyKeys.database;
import static apoc.trigger.TriggerHandler.TRIGGER_REFRESH;
import static apoc.trigger.TriggerTestUtil.TIMEOUT;
import static apoc.trigger.TriggerTestUtil.TRIGGER_DEFAULT_REFRESH;
Expand Down Expand Up @@ -221,6 +223,38 @@ private static void testDeleteTriggerAfterDropDb(String dbToDelete, Session sysS
);
}

@Test
public void testNotDeleteUserDbTriggerNodeAfterDatabaseDeletion() {
final String dbToDelete = "todelete";

// create a node in the Neo4j db that looks like a trigger
try (Session defaultSession = neo4jContainer.getDriver().session(forDatabase(DEFAULT_DATABASE_NAME))) {
defaultSession.writeTransaction(tx -> tx.run(String.format("CREATE (:%s {%s:'%s'})", SystemLabels.ApocTrigger, database.name(), dbToDelete)));
}

try (Session sysSession = neo4jContainer.getDriver().session(forDatabase(SYSTEM_DATABASE_NAME)))
{
// create database with name `todelete`
sysSession.writeTransaction( tx -> tx.run( String.format( "CREATE DATABASE %s WAIT;", dbToDelete ) ) );

// install a trigger for the database
final String defaultTriggerName = UUID.randomUUID().toString();
testCall( sysSession, "CALL apoc.trigger.install($dbName, $name, 'return 1', {})", Map.of( "dbName", dbToDelete, "name", defaultTriggerName ),
r -> assertEquals( defaultTriggerName, r.get( "name" ) ) );

// drop database
sysSession.writeTransaction( tx -> tx.run( String.format( "DROP DATABASE %s WAIT;", dbToDelete ) ) );
}

// check that the node in Neo4j database is still there
try (Session defaultSession = neo4jContainer.getDriver().session(forDatabase(DEFAULT_DATABASE_NAME))) {
testCall(defaultSession, String.format("MATCH (n:%s) RETURN n.%s AS result", SystemLabels.ApocTrigger, database.name()),
Map.of(),
r -> assertEquals(dbToDelete, r.get("result"))
);
}
}

@Test
public void testTriggersAllowedOnlyWithAdmin() {

Expand Down

0 comments on commit a8df1a1

Please sign in to comment.