#
tokens: 47715/50000 24/140 files (page 2/7)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 2 of 7. Use http://codebase.md/chillbruhhh/crawl4ai-mcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .dockerignore
├── .env.example
├── .gitattributes
├── .gitignore
├── crawled_pages.sql
├── Dockerfile
├── knowledge_graphs
│   ├── ai_hallucination_detector.py
│   ├── ai_script_analyzer.py
│   ├── hallucination_reporter.py
│   ├── knowledge_graph_validator.py
│   ├── parse_repo_into_neo4j.py
│   ├── query_knowledge_graph.py
│   └── test_script.py
├── LICENSE
├── neo4j
│   └── docker-neo4j
│       ├── .github
│       │   └── ISSUE_TEMPLATE
│       │       └── bug_report.md
│       ├── .gitignore
│       ├── build-docker-image.sh
│       ├── build-utils-common-functions.sh
│       ├── COPYRIGHT
│       ├── DEVELOPMENT.md
│       ├── devenv
│       ├── devenv.local.template
│       ├── docker-image-src
│       │   ├── 2.3
│       │   │   ├── docker-entrypoint.sh
│       │   │   └── Dockerfile
│       │   ├── 3.0
│       │   │   ├── docker-entrypoint.sh
│       │   │   └── Dockerfile
│       │   ├── 3.1
│       │   │   ├── docker-entrypoint.sh
│       │   │   └── Dockerfile
│       │   ├── 3.2
│       │   │   ├── docker-entrypoint.sh
│       │   │   └── Dockerfile
│       │   ├── 3.3
│       │   │   ├── docker-entrypoint.sh
│       │   │   └── Dockerfile
│       │   ├── 3.4
│       │   │   ├── docker-entrypoint.sh
│       │   │   └── Dockerfile
│       │   ├── 3.5
│       │   │   ├── coredb
│       │   │   │   ├── docker-entrypoint.sh
│       │   │   │   ├── Dockerfile
│       │   │   │   └── neo4j-plugins.json
│       │   │   └── neo4j-admin
│       │   │       ├── docker-entrypoint.sh
│       │   │       └── Dockerfile
│       │   ├── 4.0
│       │   │   ├── coredb
│       │   │   │   ├── docker-entrypoint.sh
│       │   │   │   └── Dockerfile
│       │   │   └── neo4j-admin
│       │   │       ├── docker-entrypoint.sh
│       │   │       └── Dockerfile
│       │   ├── 4.1
│       │   │   ├── coredb
│       │   │   │   ├── docker-entrypoint.sh
│       │   │   │   └── Dockerfile
│       │   │   └── neo4j-admin
│       │   │       ├── docker-entrypoint.sh
│       │   │       └── Dockerfile
│       │   ├── 4.2
│       │   │   ├── coredb
│       │   │   │   ├── docker-entrypoint.sh
│       │   │   │   ├── Dockerfile
│       │   │   │   └── neo4j-plugins.json
│       │   │   └── neo4j-admin
│       │   │       ├── docker-entrypoint.sh
│       │   │       └── Dockerfile
│       │   ├── 4.3
│       │   │   ├── coredb
│       │   │   │   ├── docker-entrypoint.sh
│       │   │   │   ├── Dockerfile
│       │   │   │   └── neo4j-plugins.json
│       │   │   └── neo4j-admin
│       │   │       ├── docker-entrypoint.sh
│       │   │       └── Dockerfile
│       │   ├── 4.4
│       │   │   ├── coredb
│       │   │   │   ├── docker-entrypoint.sh
│       │   │   │   ├── Dockerfile-debian
│       │   │   │   ├── Dockerfile-ubi9
│       │   │   │   ├── neo4j-admin-report.sh
│       │   │   │   └── neo4j-plugins.json
│       │   │   └── neo4j-admin
│       │   │       ├── docker-entrypoint.sh
│       │   │       ├── Dockerfile-debian
│       │   │       └── Dockerfile-ubi9
│       │   ├── 5
│       │   │   ├── coredb
│       │   │   │   ├── docker-entrypoint.sh
│       │   │   │   ├── Dockerfile-debian
│       │   │   │   ├── Dockerfile-ubi8
│       │   │   │   ├── Dockerfile-ubi9
│       │   │   │   ├── neo4j-admin-report.sh
│       │   │   │   └── neo4j-plugins.json
│       │   │   └── neo4j-admin
│       │   │       ├── docker-entrypoint.sh
│       │   │       ├── Dockerfile-debian
│       │   │       ├── Dockerfile-ubi8
│       │   │       └── Dockerfile-ubi9
│       │   ├── calver
│       │   │   ├── coredb
│       │   │   │   ├── docker-entrypoint.sh
│       │   │   │   ├── Dockerfile-debian
│       │   │   │   ├── Dockerfile-ubi9
│       │   │   │   ├── neo4j-admin-report.sh
│       │   │   │   └── neo4j-plugins.json
│       │   │   └── neo4j-admin
│       │   │       ├── docker-entrypoint.sh
│       │   │       ├── Dockerfile-debian
│       │   │       └── Dockerfile-ubi9
│       │   └── common
│       │       ├── semver.jq
│       │       └── utilities.sh
│       ├── generate-stub-plugin
│       │   ├── build.gradle.kts
│       │   ├── Dockerfile
│       │   ├── ExampleNeo4jPlugin.java
│       │   ├── Makefile
│       │   ├── README.md
│       │   └── settings.gradle.kts
│       ├── LICENSE
│       ├── Makefile
│       ├── pom.xml
│       ├── publish-neo4j-admin-image.sh
│       ├── publish-neo4j-admin-images.sh
│       ├── README.md
│       └── src
│           ├── main
│           │   └── resources
│           │       └── log4j.properties
│           └── test
│               ├── java
│               │   └── com
│               │       └── neo4j
│               │           └── docker
│               │               ├── coredb
│               │               │   ├── configurations
│               │               │   │   ├── Configuration.java
│               │               │   │   ├── Setting.java
│               │               │   │   ├── TestConfSettings.java
│               │               │   │   ├── TestExtendedConf.java
│               │               │   │   └── TestJVMAdditionalConfig.java
│               │               │   ├── plugins
│               │               │   │   ├── Neo4jPluginEnv.java
│               │               │   │   ├── StubPluginHelper.java
│               │               │   │   ├── TestBundledPluginInstallation.java
│               │               │   │   ├── TestPluginInstallation.java
│               │               │   │   └── TestSemVerPluginMatching.java
│               │               │   ├── TestAdminReport.java
│               │               │   ├── TestAuthentication.java
│               │               │   ├── TestBasic.java
│               │               │   ├── TestCausalCluster.java
│               │               │   ├── TestMounting.java
│               │               │   └── TestUpgrade.java
│               │               ├── neo4jadmin
│               │               │   ├── TestAdminBasic.java
│               │               │   ├── TestBackupRestore.java
│               │               │   ├── TestBackupRestore44.java
│               │               │   ├── TestDumpLoad.java
│               │               │   ├── TestDumpLoad44.java
│               │               │   └── TestReport.java
│               │               ├── TestDeprecationWarning.java
│               │               ├── TestDockerComposeSecrets.java
│               │               └── utils
│               │                   ├── DatabaseIO.java
│               │                   ├── HostFileHttpHandler.java
│               │                   ├── HttpServerTestExtension.java
│               │                   ├── Neo4jVersion.java
│               │                   ├── Neo4jVersionTest.java
│               │                   ├── Network.java
│               │                   ├── SetContainerUser.java
│               │                   ├── TemporaryFolderManager.java
│               │                   ├── TemporaryFolderManagerTest.java
│               │                   ├── TestSettings.java
│               │                   └── WaitStrategies.java
│               └── resources
│                   ├── causal-cluster-compose.yml
│                   ├── confs
│                   │   ├── before50
│                   │   │   ├── ConfsNotOverridden.conf
│                   │   │   ├── ConfsReplaced.conf
│                   │   │   ├── EnterpriseOnlyNotOverwritten.conf
│                   │   │   ├── EnvVarsOverride.conf
│                   │   │   ├── ExtendedConf.conf
│                   │   │   ├── InvalidExtendedConf.conf
│                   │   │   ├── JvmAdditionalNotOverridden.conf
│                   │   │   ├── NoNewline.conf
│                   │   │   └── ReadConf.conf
│                   │   ├── ConfsNotOverridden.conf
│                   │   ├── ConfsReplaced.conf
│                   │   ├── EnterpriseOnlyNotOverwritten.conf
│                   │   ├── EnvVarsOverride.conf
│                   │   ├── ExtendedConf.conf
│                   │   ├── InvalidExtendedConf.conf
│                   │   ├── JvmAdditionalNotOverridden.conf
│                   │   ├── NoNewline.conf
│                   │   └── ReadConf.conf
│                   ├── dockersecrets
│                   │   ├── container-compose-with-incorrect-secrets.yml
│                   │   ├── container-compose-with-secrets-override.yml
│                   │   ├── container-compose-with-secrets.yml
│                   │   ├── simple-container-compose-with-external-file-var.yml
│                   │   └── simple-container-compose.yml
│                   ├── ha-cluster-compose.yml
│                   └── stubplugin
│                       └── myPlugin.jar
├── pyproject.toml
├── README.md
├── src
│   ├── crawl4ai_mcp.py
│   └── utils.py
└── uv.lock
```

# Files

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/docker-image-src/4.0/neo4j-admin/docker-entrypoint.sh:
--------------------------------------------------------------------------------

```bash
  1 | #!/bin/bash -eu
  2 | 
  3 | function running_as_root
  4 | {
  5 |     test "$(id -u)" = "0"
  6 | }
  7 | 
  8 | function is_writable
  9 | {
 10 |     gosu "${userid}":"${groupid}" test -w "${1}"
 11 | }
 12 | 
 13 | function print_permissions_advice_and_fail
 14 | {
 15 |     local _directory=${1}
 16 |     echo >&2 "
 17 | Folder ${_directory} is not accessible for user: ${userid} or group ${groupid} or groups ${groups[@]}, this is commonly a file permissions issue on the mounted folder.
 18 | 
 19 | Hints to solve the issue:
 20 | 1) Make sure the folder exists before mounting it. Docker will create the folder using root permissions before starting the Neo4j container. The root permissions disallow Neo4j from writing to the mounted folder.
 21 | 2) Pass the folder owner's user ID and group ID to docker run, so that docker runs as that user.
 22 | If the folder is owned by the current user, this can be done by adding this flag to your docker run command:
 23 |   --user=\$(id -u):\$(id -g)
 24 |        "
 25 |     exit 1
 26 | }
 27 | 
 28 | 
 29 | function check_mounted_folder_writable_with_chown
 30 | {
 31 |     local mountFolder=${1}
 32 |     if running_as_root; then
 33 |         # check folder permissions
 34 |         if ! is_writable "${mountFolder}" ;  then
 35 |             # warn that we're about to chown the folder and then chown it
 36 |             echo "Warning: Folder mounted to \"${mountFolder}\" is not writable from inside container. Changing folder owner to ${userid}."
 37 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 38 |         # check permissions on files in the folder
 39 |         elif [ $(gosu "${userid}":"${groupid}" find "${mountFolder}" -not -writable | wc -l) -gt 0 ]; then
 40 |             echo "Warning: Some files inside \"${mountFolder}\" are not writable from inside container. Changing folder owner to ${userid}."
 41 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 42 |         fi
 43 |     else
 44 |         if [[ ! -w "${mountFolder}" ]]  && [[ "$(stat -c %U ${mountFolder})" != "neo4j" ]]; then
 45 |             print_permissions_advice_and_fail "${mountFolder}"
 46 |         fi
 47 |     fi
 48 | }
 49 | 
 50 | # ==== SETUP WHICH USER TO RUN AS ====
 51 | 
 52 | if running_as_root; then
 53 |   userid="neo4j"
 54 |   groupid="neo4j"
 55 |   groups=($(id -G neo4j))
 56 |   exec_cmd="exec gosu neo4j:neo4j"
 57 | else
 58 |   userid="$(id -u)"
 59 |   groupid="$(id -g)"
 60 |   groups=($(id -G))
 61 |   exec_cmd="exec"
 62 | fi
 63 | 
 64 | 
 65 | # ==== CHECK LICENSE AGREEMENT ====
 66 | 
 67 | if [ "${NEO4J_EDITION}" == "enterprise" ]; then
 68 |     if [ "${NEO4J_ACCEPT_LICENSE_AGREEMENT:=no}" != "yes" ]; then
 69 |       echo >&2 "
 70 | In order to use Neo4j Enterprise Edition you must accept the license agreement.
 71 | 
 72 | (c) Neo4j Sweden AB. 2021.  All Rights Reserved.
 73 | Use of this Software without a proper commercial license with Neo4j,
 74 | Inc. or its affiliates is prohibited.
 75 | 
 76 | Email inquiries can be directed to: [email protected]
 77 | 
 78 | More information is also available at: https://neo4j.com/licensing/
 79 | 
 80 | 
 81 | To accept the license agreement set the environment variable
 82 | NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
 83 | 
 84 | To do this you can use the following docker argument:
 85 | 
 86 |     --env=NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
 87 | "
 88 |       exit 1
 89 |     fi
 90 | fi
 91 | 
 92 | # ==== ENSURE MOUNT FOLDER READ/WRITABILITY ====
 93 | 
 94 | if [ -d /data ]; then
 95 |     check_mounted_folder_writable_with_chown "/data"
 96 |     if [ -d /data/databases ]; then
 97 |         check_mounted_folder_writable_with_chown "/data/databases"
 98 |     fi
 99 |     if [ -d /data/dbms ]; then
100 |         check_mounted_folder_writable_with_chown "/data/dbms"
101 |     fi
102 |     if [ -d /data/transactions ]; then
103 |         check_mounted_folder_writable_with_chown "/data/transactions"
104 |     fi
105 | fi
106 | if [ -d /backups ]; then
107 |     check_mounted_folder_writable_with_chown "/backups"
108 | fi
109 | 
110 | # ==== MAKE SURE NEO4J CANNOT BE RUN FROM THIS CONTAINER ====
111 | 
112 | rm ${NEO4J_HOME}/bin/neo4j
113 | 
114 | if [[ "${1}" == "neo4j" ]]; then
115 |     correct_image="neo4j:"$(neo4j-admin --version)"-${NEO4J_EDITION}"
116 |     echo >&2 "
117 | This is a neo4j-admin only image, and usage of Neo4j server is not supported from here.
118 | If you wish to start a Neo4j database, use:
119 | 
120 | docker run ${correct_image}
121 |     "
122 |     exit 1
123 | fi
124 | 
125 | # ==== START NEO4J-ADMIN COMMAND ====
126 | 
127 | ${exec_cmd} "${@}"
128 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/docker-image-src/4.1/neo4j-admin/docker-entrypoint.sh:
--------------------------------------------------------------------------------

```bash
  1 | #!/bin/bash -eu
  2 | 
  3 | function running_as_root
  4 | {
  5 |     test "$(id -u)" = "0"
  6 | }
  7 | 
  8 | function is_writable
  9 | {
 10 |     gosu "${userid}":"${groupid}" test -w "${1}"
 11 | }
 12 | 
 13 | function print_permissions_advice_and_fail
 14 | {
 15 |     local _directory=${1}
 16 |     echo >&2 "
 17 | Folder ${_directory} is not accessible for user: ${userid} or group ${groupid} or groups ${groups[@]}, this is commonly a file permissions issue on the mounted folder.
 18 | 
 19 | Hints to solve the issue:
 20 | 1) Make sure the folder exists before mounting it. Docker will create the folder using root permissions before starting the Neo4j container. The root permissions disallow Neo4j from writing to the mounted folder.
 21 | 2) Pass the folder owner's user ID and group ID to docker run, so that docker runs as that user.
 22 | If the folder is owned by the current user, this can be done by adding this flag to your docker run command:
 23 |   --user=\$(id -u):\$(id -g)
 24 |        "
 25 |     exit 1
 26 | }
 27 | 
 28 | 
 29 | function check_mounted_folder_writable_with_chown
 30 | {
 31 |     local mountFolder=${1}
 32 |     if running_as_root; then
 33 |         # check folder permissions
 34 |         if ! is_writable "${mountFolder}" ;  then
 35 |             # warn that we're about to chown the folder and then chown it
 36 |             echo "Warning: Folder mounted to \"${mountFolder}\" is not writable from inside container. Changing folder owner to ${userid}."
 37 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 38 |         # check permissions on files in the folder
 39 |         elif [ $(gosu "${userid}":"${groupid}" find "${mountFolder}" -not -writable | wc -l) -gt 0 ]; then
 40 |             echo "Warning: Some files inside \"${mountFolder}\" are not writable from inside container. Changing folder owner to ${userid}."
 41 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 42 |         fi
 43 |     else
 44 |         if [[ ! -w "${mountFolder}" ]]  && [[ "$(stat -c %U ${mountFolder})" != "neo4j" ]]; then
 45 |             print_permissions_advice_and_fail "${mountFolder}"
 46 |         fi
 47 |     fi
 48 | }
 49 | 
 50 | # ==== SETUP WHICH USER TO RUN AS ====
 51 | 
 52 | if running_as_root; then
 53 |   userid="neo4j"
 54 |   groupid="neo4j"
 55 |   groups=($(id -G neo4j))
 56 |   exec_cmd="exec gosu neo4j:neo4j"
 57 | else
 58 |   userid="$(id -u)"
 59 |   groupid="$(id -g)"
 60 |   groups=($(id -G))
 61 |   exec_cmd="exec"
 62 | fi
 63 | 
 64 | 
 65 | # ==== CHECK LICENSE AGREEMENT ====
 66 | 
 67 | if [ "${NEO4J_EDITION}" == "enterprise" ]; then
 68 |     if [ "${NEO4J_ACCEPT_LICENSE_AGREEMENT:=no}" != "yes" ]; then
 69 |       echo >&2 "
 70 | In order to use Neo4j Enterprise Edition you must accept the license agreement.
 71 | 
 72 | (c) Neo4j Sweden AB. 2021.  All Rights Reserved.
 73 | Use of this Software without a proper commercial license with Neo4j,
 74 | Inc. or its affiliates is prohibited.
 75 | 
 76 | Email inquiries can be directed to: [email protected]
 77 | 
 78 | More information is also available at: https://neo4j.com/licensing/
 79 | 
 80 | 
 81 | To accept the license agreement set the environment variable
 82 | NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
 83 | 
 84 | To do this you can use the following docker argument:
 85 | 
 86 |     --env=NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
 87 | "
 88 |       exit 1
 89 |     fi
 90 | fi
 91 | 
 92 | # ==== ENSURE MOUNT FOLDER READ/WRITABILITY ====
 93 | 
 94 | if [ -d /data ]; then
 95 |     check_mounted_folder_writable_with_chown "/data"
 96 |     if [ -d /data/databases ]; then
 97 |         check_mounted_folder_writable_with_chown "/data/databases"
 98 |     fi
 99 |     if [ -d /data/dbms ]; then
100 |         check_mounted_folder_writable_with_chown "/data/dbms"
101 |     fi
102 |     if [ -d /data/transactions ]; then
103 |         check_mounted_folder_writable_with_chown "/data/transactions"
104 |     fi
105 | fi
106 | if [ -d /backups ]; then
107 |     check_mounted_folder_writable_with_chown "/backups"
108 | fi
109 | 
110 | # ==== MAKE SURE NEO4J CANNOT BE RUN FROM THIS CONTAINER ====
111 | 
112 | rm ${NEO4J_HOME}/bin/neo4j
113 | 
114 | if [[ "${1}" == "neo4j" ]]; then
115 |     correct_image="neo4j:"$(neo4j-admin --version)"-${NEO4J_EDITION}"
116 |     echo >&2 "
117 | This is a neo4j-admin only image, and usage of Neo4j server is not supported from here.
118 | If you wish to start a Neo4j database, use:
119 | 
120 | docker run ${correct_image}
121 |     "
122 |     exit 1
123 | fi
124 | 
125 | # ==== START NEO4J-ADMIN COMMAND ====
126 | 
127 | ${exec_cmd} "${@}"
128 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/docker-image-src/4.2/neo4j-admin/docker-entrypoint.sh:
--------------------------------------------------------------------------------

```bash
  1 | #!/bin/bash -eu
  2 | 
  3 | function running_as_root
  4 | {
  5 |     test "$(id -u)" = "0"
  6 | }
  7 | 
  8 | function is_writable
  9 | {
 10 |     gosu "${userid}":"${groupid}" test -w "${1}"
 11 | }
 12 | 
 13 | function print_permissions_advice_and_fail
 14 | {
 15 |     local _directory=${1}
 16 |     echo >&2 "
 17 | Folder ${_directory} is not accessible for user: ${userid} or group ${groupid} or groups ${groups[@]}, this is commonly a file permissions issue on the mounted folder.
 18 | 
 19 | Hints to solve the issue:
 20 | 1) Make sure the folder exists before mounting it. Docker will create the folder using root permissions before starting the Neo4j container. The root permissions disallow Neo4j from writing to the mounted folder.
 21 | 2) Pass the folder owner's user ID and group ID to docker run, so that docker runs as that user.
 22 | If the folder is owned by the current user, this can be done by adding this flag to your docker run command:
 23 |   --user=\$(id -u):\$(id -g)
 24 |        "
 25 |     exit 1
 26 | }
 27 | 
 28 | 
 29 | function check_mounted_folder_writable_with_chown
 30 | {
 31 |     local mountFolder=${1}
 32 |     if running_as_root; then
 33 |         # check folder permissions
 34 |         if ! is_writable "${mountFolder}" ;  then
 35 |             # warn that we're about to chown the folder and then chown it
 36 |             echo "Warning: Folder mounted to \"${mountFolder}\" is not writable from inside container. Changing folder owner to ${userid}."
 37 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 38 |         # check permissions on files in the folder
 39 |         elif [ $(gosu "${userid}":"${groupid}" find "${mountFolder}" -not -writable | wc -l) -gt 0 ]; then
 40 |             echo "Warning: Some files inside \"${mountFolder}\" are not writable from inside container. Changing folder owner to ${userid}."
 41 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 42 |         fi
 43 |     else
 44 |         if [[ ! -w "${mountFolder}" ]]  && [[ "$(stat -c %U ${mountFolder})" != "neo4j" ]]; then
 45 |             print_permissions_advice_and_fail "${mountFolder}"
 46 |         fi
 47 |     fi
 48 | }
 49 | 
 50 | # ==== SETUP WHICH USER TO RUN AS ====
 51 | 
 52 | if running_as_root; then
 53 |   userid="neo4j"
 54 |   groupid="neo4j"
 55 |   groups=($(id -G neo4j))
 56 |   exec_cmd="exec gosu neo4j:neo4j"
 57 | else
 58 |   userid="$(id -u)"
 59 |   groupid="$(id -g)"
 60 |   groups=($(id -G))
 61 |   exec_cmd="exec"
 62 | fi
 63 | 
 64 | 
 65 | # ==== CHECK LICENSE AGREEMENT ====
 66 | 
 67 | if [ "${NEO4J_EDITION}" == "enterprise" ]; then
 68 |     if [ "${NEO4J_ACCEPT_LICENSE_AGREEMENT:=no}" != "yes" ]; then
 69 |       echo >&2 "
 70 | In order to use Neo4j Enterprise Edition you must accept the license agreement.
 71 | 
 72 | (c) Neo4j Sweden AB. 2021.  All Rights Reserved.
 73 | Use of this Software without a proper commercial license with Neo4j,
 74 | Inc. or its affiliates is prohibited.
 75 | 
 76 | Email inquiries can be directed to: [email protected]
 77 | 
 78 | More information is also available at: https://neo4j.com/licensing/
 79 | 
 80 | 
 81 | To accept the license agreement set the environment variable
 82 | NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
 83 | 
 84 | To do this you can use the following docker argument:
 85 | 
 86 |     --env=NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
 87 | "
 88 |       exit 1
 89 |     fi
 90 | fi
 91 | 
 92 | # ==== ENSURE MOUNT FOLDER READ/WRITABILITY ====
 93 | 
 94 | if [ -d /data ]; then
 95 |     check_mounted_folder_writable_with_chown "/data"
 96 |     if [ -d /data/databases ]; then
 97 |         check_mounted_folder_writable_with_chown "/data/databases"
 98 |     fi
 99 |     if [ -d /data/dbms ]; then
100 |         check_mounted_folder_writable_with_chown "/data/dbms"
101 |     fi
102 |     if [ -d /data/transactions ]; then
103 |         check_mounted_folder_writable_with_chown "/data/transactions"
104 |     fi
105 | fi
106 | if [ -d /backups ]; then
107 |     check_mounted_folder_writable_with_chown "/backups"
108 | fi
109 | 
110 | # ==== MAKE SURE NEO4J CANNOT BE RUN FROM THIS CONTAINER ====
111 | 
112 | rm ${NEO4J_HOME}/bin/neo4j
113 | 
114 | if [[ "${1}" == "neo4j" ]]; then
115 |     correct_image="neo4j:"$(neo4j-admin --version)"-${NEO4J_EDITION}"
116 |     echo >&2 "
117 | This is a neo4j-admin only image, and usage of Neo4j server is not supported from here.
118 | If you wish to start a Neo4j database, use:
119 | 
120 | docker run ${correct_image}
121 |     "
122 |     exit 1
123 | fi
124 | 
125 | # ==== START NEO4J-ADMIN COMMAND ====
126 | 
127 | ${exec_cmd} "${@}"
128 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/publish-neo4j-admin-image.sh:
--------------------------------------------------------------------------------

```bash
 1 | #!/bin/bash
 2 | set -eu -o pipefail
 3 | 
 4 | EDITIONS=("community" "enterprise")
 5 | 
 6 | ROOT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
 7 | source "$ROOT_DIR/build-utils-common-functions.sh"
 8 | BUILD_DIR=${ROOT_DIR}/build
 9 | SRC_DIR=${ROOT_DIR}/docker-image-src
10 | # shellcheck disable=SC2034  # Used in docker-common-functions.sh
11 | TAR_CACHE=${ROOT_DIR}/in
12 | 
13 | function usage
14 | {
15 |     echo >&2 "USAGE: $0 <version> <edition> <operating system> <repository>
16 |     For example:
17 |         $0 4.4.10 community debian neo/neo4j-admin
18 |         $0 5.10.0 enterprise ubi9 neo/neo4j-admin
19 |     Version and operating system can also be set in the environment.
20 |     For example:
21 |         NEO4JVERSION=4.4.10 NEO4JEDITION=community IMAGE_OS=debian REPOSITORY=neo/neo4j-admin $0
22 |         NEO4JVERSION=5.10.0 NEO4JEDITION=enterprise IMAGE_OS=ubi9 REPOSITORY=neo/neo4j-admin $0
23 |     "
24 |     exit 1
25 | }
26 | 
27 | ## ==========================================
28 | ## get and sanitise script inputs
29 | 
30 | if [[ $# -eq 4 ]]; then
31 |     NEO4JVERSION=${1}
32 |     NEO4JEDITION=${2}
33 |     IMAGE_OS=${3}
34 |     REPOSITORY=${4}
35 | elif [[ -z ${NEO4JVERSION:-""} ]]; then
36 |     echo >&2 "NEO4JVERSION is unset. Either set it in the environment or pass as argument to this script."
37 |     usage
38 | elif [[ -z ${NEO4JEDITION:-""} ]]; then
39 |     echo >&2 "NEO4JEDITION is unset. Either set it in the environment or pass as argument to this script."
40 |     usage
41 | elif [[ -z ${IMAGE_OS:-""} ]]; then
42 |     echo >&2 "IMAGE_OS is unset. Either set it in the environment or pass as argument to this script."
43 |     usage
44 | elif [[ -z ${REPOSITORY:-""} ]]; then
45 |     echo >&2 "REPOSITORY is unset. Either set it in the environment or pass as argument to this script."
46 |     usage
47 | fi
48 | # verify edition
49 | if ! contains_element "${NEO4JEDITION}" "${EDITIONS[@]}"; then
50 |     echo >&2 "${NEO4JEDITION} is not a supported edition."
51 |     usage
52 | fi
53 | # verify compatible neo4j version
54 | if [[ ! "${NEO4JVERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+.*$  ]]; then
55 |     echo "\"${NEO4JVERSION}\" is not a valid version number."
56 |     usage
57 | fi
58 | # get source files
59 | BRANCH=$(get_branch_from_version ${NEO4JVERSION})
60 | DOCKERFILE_NAME=$(get_compatible_dockerfile_for_os_or_error "${BRANCH}" "${IMAGE_OS}")
61 | 
62 | echo "Building local context for docker build"
63 | ADMIN_LOCALCXT_DIR=${BUILD_DIR}/${IMAGE_OS}/neo4j-admin/${NEO4JEDITION}
64 | mkdir -p ${ADMIN_LOCALCXT_DIR}
65 | 
66 | # copy neo4j-admin sources
67 | mkdir -p ${ADMIN_LOCALCXT_DIR}/local-package
68 | cp ${SRC_DIR}/common/* ${ADMIN_LOCALCXT_DIR}/local-package
69 | cp "$(cached_tarball "${NEO4JVERSION}" "${NEO4JEDITION}")" ${ADMIN_LOCALCXT_DIR}/local-package/
70 | cp ${SRC_DIR}/${BRANCH}/neo4j-admin/*.sh ${ADMIN_LOCALCXT_DIR}/local-package
71 | 
72 | # create neo4j-admin Dockerfile
73 | cp "${SRC_DIR}/${BRANCH}/neo4j-admin/${DOCKERFILE_NAME}" "${ADMIN_LOCALCXT_DIR}/Dockerfile"
74 | coredb_sha=$(shasum --algorithm=256 "$(cached_tarball "${NEO4JVERSION}" "${NEO4JEDITION}")" | cut -d' ' -f1)
75 | sed -i -e "s|%%NEO4J_SHA%%|${coredb_sha}|" "${ADMIN_LOCALCXT_DIR}/Dockerfile"
76 | sed -i -e "s|%%NEO4J_TARBALL%%|$(tarball_name ${NEO4JVERSION} ${NEO4JEDITION})|" "${ADMIN_LOCALCXT_DIR}/Dockerfile"
77 | sed -i -e "s|%%NEO4J_EDITION%%|${NEO4JEDITION}|" "${ADMIN_LOCALCXT_DIR}/Dockerfile"
78 | 
79 | # build and push neo4j-admin
80 | MAJOR=$(get_major_from_version "${NEO4JVERSION}")
81 | full_version_admin_image_tag="${REPOSITORY}:${NEO4JVERSION}-${NEO4JEDITION}-${IMAGE_OS}"
82 | major_minor_admin_image_tag="${REPOSITORY}:${NEO4JVERSION%.*}-${NEO4JEDITION}-${IMAGE_OS}"
83 | major_admin_image_tag="${REPOSITORY}:${MAJOR}-${NEO4JEDITION}-${IMAGE_OS}"
84 | echo "Building neo4j-admin docker image for neo4j-admin-${NEO4JVERSION} ${NEO4JEDITION} on ${IMAGE_OS}."
85 | echo "With tags: ${full_version_admin_image_tag},${major_minor_admin_image_tag},${major_admin_image_tag}"
86 | 
87 | docker buildx build --tag="${full_version_admin_image_tag}" --tag="${major_minor_admin_image_tag}" --tag="${major_admin_image_tag}" \
88 |     --build-arg="NEO4J_URI=file:///startup/$(tarball_name "${NEO4JVERSION}" "${NEO4JEDITION}")" \
89 |     "${ADMIN_LOCALCXT_DIR}" --platform linux/amd64,linux/arm64 --push
90 | 
91 | 
92 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/pom.xml:
--------------------------------------------------------------------------------

```
  1 | <?xml version="1.0" encoding="UTF-8"?>
  2 | <project xmlns="http://maven.apache.org/POM/4.0.0"
  3 | 		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 | 		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 | 	<modelVersion>4.0.0</modelVersion>
  6 | 
  7 | 	<groupId>com.neo4j</groupId>
  8 | 	<artifactId>docker-neo4j-tests</artifactId>
  9 | 	<version>1.0-SNAPSHOT</version>
 10 | 	<packaging>jar</packaging>
 11 | 
 12 | 	<properties>
 13 |         <java.version>17</java.version>
 14 |         <junit.version>5.11.0</junit.version>
 15 |         <neo4j.driver.version>5.24.0</neo4j.driver.version>
 16 |         <surefire.version>3.1.2</surefire.version>
 17 |         <testcontainers.version>1.20.1</testcontainers.version>
 18 |     </properties>
 19 | 
 20 |     <profiles>
 21 |         <profile>
 22 |             <!-- This sets what test groups will run by default if you don't specify any maven profiles when running mvn test -->
 23 |             <id>default</id>
 24 |             <activation>
 25 |                 <activeByDefault>true</activeByDefault>
 26 |             </activation>
 27 |             <properties>
 28 |                 <profile.include></profile.include>
 29 |                 <profile.exclude>BundleTest</profile.exclude>
 30 |             </properties>
 31 |         </profile>
 32 |         <profile>
 33 |             <id>bundle</id>
 34 |             <properties>
 35 |                 <profile.include>BundleTest</profile.include>
 36 |             </properties>
 37 |         </profile>
 38 |     </profiles>
 39 | 
 40 | 	<build>
 41 | 		<plugins>
 42 | 			<plugin>
 43 | 				<groupId>org.apache.maven.plugins</groupId>
 44 | 				<artifactId>maven-compiler-plugin</artifactId>
 45 | 				<version>3.7.0</version>
 46 | 				<configuration>
 47 | 					<source>${java.version}</source>
 48 | 					<target>${java.version}</target>
 49 | 				</configuration>
 50 | 			</plugin>
 51 | 			<plugin>
 52 |                 <groupId>org.apache.maven.plugins</groupId>
 53 | 				<artifactId>maven-surefire-plugin</artifactId>
 54 | 				<version>${surefire.version}</version>
 55 |                 <configuration>
 56 |                     <groups>${profile.include}</groups>
 57 |                     <excludedGroups>${profile.exclude}</excludedGroups>
 58 |                 </configuration>
 59 |             </plugin>
 60 | 		</plugins>
 61 | 	</build>
 62 | 
 63 | 	<dependencies>
 64 | 		<dependency>
 65 | 			<!-- logging library -->
 66 | 			<groupId>org.slf4j</groupId>
 67 | 			<artifactId>slf4j-api</artifactId>
 68 | 			<version>1.7.32</version>
 69 | 		</dependency>
 70 | 		<dependency>
 71 | 			<groupId>org.slf4j</groupId>
 72 | 			<artifactId>slf4j-log4j12</artifactId>
 73 | 			<version>1.7.32</version>
 74 | 		</dependency>
 75 | 		<dependency>
 76 | 			<groupId>org.junit.jupiter</groupId>
 77 | 			<artifactId>junit-jupiter-api</artifactId>
 78 | 			<version>${junit.version}</version>
 79 | 			<scope>test</scope>
 80 | 		</dependency>
 81 | 		<dependency>
 82 | 			<groupId>org.junit.jupiter</groupId>
 83 | 			<artifactId>junit-jupiter-engine</artifactId>
 84 | 			<version>${junit.version}</version>
 85 | 			<scope>test</scope>
 86 | 		</dependency>
 87 | 		<dependency>
 88 | 			<groupId>org.junit.jupiter</groupId>
 89 | 			<artifactId>junit-jupiter-params</artifactId>
 90 | 			<version>${junit.version}</version>
 91 | 			<scope>test</scope>
 92 | 		</dependency>
 93 | 		<dependency>
 94 | 			<groupId>org.testcontainers</groupId>
 95 | 			<artifactId>junit-jupiter</artifactId>
 96 | 			<version>${testcontainers.version}</version>
 97 | 			<scope>test</scope>
 98 | 		</dependency>
 99 | 		<dependency>
100 | 			<groupId>org.testcontainers</groupId>
101 | 			<artifactId>testcontainers</artifactId>
102 | 			<version>${testcontainers.version}</version>
103 | 			<scope>test</scope>
104 | 		</dependency>
105 |         <dependency>
106 |             <groupId>org.neo4j.driver</groupId>
107 |             <artifactId>neo4j-java-driver</artifactId>
108 |             <version>${neo4j.driver.version}</version>
109 |             <scope>test</scope>
110 |         </dependency>
111 |         <!--  Gson: Java to Json conversion -->
112 |         <dependency>
113 |             <groupId>com.google.code.gson</groupId>
114 |             <artifactId>gson</artifactId>
115 |             <version>2.8.9</version>
116 |             <scope>test</scope>
117 |         </dependency>
118 |         <!--  For creating archives of test data -->
119 |         <dependency>
120 |             <groupId>org.apache.commons</groupId>
121 |             <artifactId>commons-compress</artifactId>
122 |             <version>1.24.0</version>
123 |             <scope>test</scope>
124 |         </dependency>
125 |         <dependency>
126 |             <groupId>commons-io</groupId>
127 |             <artifactId>commons-io</artifactId>
128 |             <version>2.11.0</version>
129 |             <scope>test</scope>
130 |         </dependency>
131 |     </dependencies>
132 | 
133 | </project>
134 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/docker-image-src/4.4/neo4j-admin/docker-entrypoint.sh:
--------------------------------------------------------------------------------

```bash
  1 | #!/bin/bash -eu
  2 | 
  3 | # load useful utility functions
  4 | . /startup/utilities.sh
  5 | 
  6 | function check_mounted_folder_writable_with_chown
  7 | {
  8 |     local mountFolder=${1}
  9 |     debug_msg "checking ${mountFolder} is writable"
 10 |     if running_as_root; then
 11 |         # check folder permissions
 12 |         if ! is_writable "${mountFolder}" ;  then
 13 |             # warn that we're about to chown the folder and then chown it
 14 |             echo "Warning: Folder mounted to \"${mountFolder}\" is not writable from inside container. Changing folder owner to ${userid}."
 15 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 16 |         # check permissions on files in the folder
 17 |         elif [ $(${exec_cmd} find "${mountFolder}" -not -writable | wc -l) -gt 0 ]; then
 18 |             echo "Warning: Some files inside \"${mountFolder}\" are not writable from inside container. Changing folder owner to ${userid}."
 19 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 20 |         fi
 21 |     else
 22 |         if [[ ! -w "${mountFolder}" ]]  && [[ "$(stat -c %U ${mountFolder})" != "neo4j" ]]; then
 23 |             print_permissions_advice_and_fail "${mountFolder}"
 24 |         fi
 25 |     fi
 26 | }
 27 | 
 28 | # ==== SETUP WHICH USER TO RUN AS ====
 29 | debug_msg "DEBUGGING ENABLED"
 30 | 
 31 | if running_as_root; then
 32 |   userid="neo4j"
 33 |   groupid="neo4j"
 34 |   groups=($(id -G neo4j))
 35 |   exec_cmd="runuser -p -u neo4j -g neo4j --"
 36 |   debug_msg "Running as root user inside neo4j-admin image"
 37 | else
 38 |   userid="$(id -u)"
 39 |   groupid="$(id -g)"
 40 |   groups=($(id -G))
 41 |   exec_cmd="exec"
 42 |   debug_msg "Running as user ${userid} inside neo4j-admin image"
 43 | fi
 44 | 
 45 | # ==== MAKE SURE NEO4J CANNOT BE RUN FROM THIS CONTAINER ====
 46 | debug_msg "checking neo4j was not requested"
 47 | if [[ "${1}" == "neo4j" ]]; then
 48 |     correct_image="neo4j:"$(neo4j-admin --version)"-${NEO4J_EDITION}"
 49 |     echo >&2 "
 50 | This is a neo4j-admin only image, and usage of Neo4j server is not supported from here.
 51 | If you wish to start a Neo4j database, use:
 52 | 
 53 | docker run ${correct_image}
 54 |     "
 55 |     exit 1
 56 | fi
 57 | 
 58 | # ==== MAKE SURE NEO4J-ADMIN REPORT CANNOT BE RUN FROM THIS CONTAINER ====
 59 | debug_msg "checking neo4j-admin report was not requested"
 60 | # maybe make sure the command is neo4j-admin server report rather than just anything mentioning reports?
 61 | if containsElement "report" "${@}"; then
 62 |     echo >&2 \
 63 | "neo4j-admin report must be run in the same container as neo4j
 64 | otherwise the report tool cannot access relevant files and processes required for generating the report.
 65 | 
 66 | To run the report tool inside a neo4j container, do:
 67 | 
 68 | docker exec <CONTAINER NAME> neo4j-admin-report
 69 | 
 70 | "
 71 |     exit 1
 72 | fi
 73 | 
 74 | 
 75 | # ==== CHECK LICENSE AGREEMENT ====
 76 | 
 77 | debug_msg "checking license"
 78 | if [ "${NEO4J_EDITION}" == "enterprise" ]; then
 79 |     if [ "${NEO4J_ACCEPT_LICENSE_AGREEMENT:=no}" != "yes" ]; then
 80 |       echo >&2 "
 81 | In order to use Neo4j Enterprise Edition you must accept the license agreement.
 82 | 
 83 | The license agreement is available at https://neo4j.com/terms/licensing/
 84 | If you have a support contract the following terms apply https://neo4j.com/terms/support-terms/
 85 | 
 86 | (c) Neo4j Sweden AB. All Rights Reserved.
 87 | Use of this Software without a proper commercial license
 88 | with Neo4j, Inc. or its affiliates is prohibited.
 89 | Neo4j has the right to terminate your usage if you are not compliant.
 90 | 
 91 | More information is also available at: https://neo4j.com/licensing/
 92 | If you have further inquiries about licensing, please contact us via https://neo4j.com/contact-us/
 93 | 
 94 | To accept the commercial license agreement set the environment variable
 95 | NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
 96 | 
 97 | To do this you can use the following docker argument:
 98 | 
 99 |     --env=NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
100 | "
101 |       exit 1
102 |     fi
103 | fi
104 | 
105 | # ==== ENSURE MOUNT FOLDER READ/WRITABILITY ====
106 | debug_msg "Checking for mounted folder writability"
107 | 
108 | if [ -d /data ]; then
109 |     check_mounted_folder_writable_with_chown "/data"
110 |     if [ -d /data/databases ]; then
111 |         check_mounted_folder_writable_with_chown "/data/databases"
112 |     fi
113 |     if [ -d /data/dbms ]; then
114 |         check_mounted_folder_writable_with_chown "/data/dbms"
115 |     fi
116 |     if [ -d /data/transactions ]; then
117 |         check_mounted_folder_writable_with_chown "/data/transactions"
118 |     fi
119 | fi
120 | if [ -d /backups ]; then
121 |     check_mounted_folder_writable_with_chown "/backups"
122 | fi
123 | 
124 | # ==== START NEO4J-ADMIN COMMAND ====
125 | if debugging_enabled; then
126 |     echo ${exec_cmd} "${@}" --verbose
127 |     ${exec_cmd} "${@}" --verbose
128 | else
129 |     ${exec_cmd} "${@}"
130 | fi
131 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/coredb/TestCausalCluster.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker.coredb;
  2 | 
  3 | import com.neo4j.docker.utils.SetContainerUser;
  4 | import com.neo4j.docker.utils.TemporaryFolderManager;
  5 | import com.neo4j.docker.utils.TestSettings;
  6 | import org.junit.jupiter.api.Assertions;
  7 | import org.junit.jupiter.api.Assumptions;
  8 | import org.junit.jupiter.api.Disabled;
  9 | import org.junit.jupiter.api.Test;
 10 | import org.neo4j.driver.*;
 11 | 
 12 | import org.junit.jupiter.api.extension.RegisterExtension;
 13 | import org.testcontainers.containers.DockerComposeContainer;
 14 | import org.testcontainers.containers.wait.strategy.*;
 15 | 
 16 | import java.io.DataOutputStream;
 17 | import java.io.File;
 18 | import java.io.FileOutputStream;
 19 | import java.io.InputStream;
 20 | import java.nio.file.Files;
 21 | import java.nio.file.Path;
 22 | import java.nio.file.Paths;
 23 | import java.time.Duration;
 24 | 
 25 | @Disabled
 26 | public class TestCausalCluster
 27 | {
 28 |     private static final int DEFAULT_BOLT_PORT = 7687;
 29 |     @RegisterExtension
 30 |     public static TemporaryFolderManager temporaryFolderManager = new TemporaryFolderManager();
 31 | 
 32 |     @Disabled
 33 |     @Test
 34 |     void testCausalClusteringBasic() throws Exception
 35 |     {
 36 |         Assumptions.assumeTrue(TestSettings.EDITION == TestSettings.Edition.ENTERPRISE,
 37 |                                "No causal clustering for community edition");
 38 | 
 39 |         Path tmpDir = temporaryFolderManager.createFolder( "CC_cluster_" );
 40 | 
 41 |         File compose_file =  new File(tmpDir.toString(), "causal-cluster-compose.yml");
 42 |         Files.copy(getResource("causal-cluster-compose.yml"), Paths.get(compose_file.getPath()));
 43 | 
 44 |         Files.createDirectories( tmpDir.resolve( "core1" ) );
 45 |         Files.createDirectories( tmpDir.resolve( "core2" ) );
 46 |         Files.createDirectories( tmpDir.resolve( "core3" ) );
 47 |         Files.createDirectories( tmpDir.resolve( "readreplica1" ) );
 48 | 
 49 |         String content = new String(Files.readAllBytes(Paths.get(compose_file.getPath())));
 50 |         String[] contentLines = content.split(System.getProperty("line.separator"));
 51 |         String[] editedLines = new String[contentLines.length];
 52 |         int i = 0;
 53 | 
 54 |         for (String line : contentLines) {
 55 |             editedLines[i] = line.replaceAll("%%IMAGE%%", TestSettings.IMAGE_ID.asCanonicalNameString());
 56 |             editedLines[i] = editedLines[i].replaceAll("%%LOGS_DIR%%", tmpDir.toAbsolutePath().toString());
 57 |             editedLines[i] = editedLines[i].replaceAll("%%USERIDGROUPID%%", SetContainerUser.getNonRootUserString());
 58 |             i++;
 59 |         }
 60 | 
 61 |         String editedContent = String.join("\n", editedLines);
 62 | 
 63 |         DataOutputStream outstream = new DataOutputStream(new FileOutputStream(compose_file,false));
 64 |         outstream.write(editedContent.getBytes());
 65 |         outstream.close();
 66 |         System.out.println("logs: " + compose_file.getName() + " and " + tmpDir.toString());
 67 | 
 68 |         DockerComposeContainer clusteringContainer = new DockerComposeContainer(compose_file)
 69 |                 .withLocalCompose(true)
 70 |                 .withExposedService("core1", DEFAULT_BOLT_PORT )
 71 |                 .withExposedService("core1", 7474,
 72 | 									Wait.forHttp( "/" )
 73 | 										.forPort( 7474 )
 74 | 										.forStatusCode( 200 )
 75 | 										.withStartupTimeout( Duration.ofSeconds( 300 ) ))
 76 |                 .withExposedService("readreplica1", DEFAULT_BOLT_PORT);
 77 | 
 78 |         clusteringContainer.start();
 79 | 
 80 |         String core1Uri = "bolt://" + clusteringContainer.getServiceHost("core1", DEFAULT_BOLT_PORT)
 81 |                           + ":" +
 82 |                           clusteringContainer.getServicePort("core1", DEFAULT_BOLT_PORT);
 83 |         String rrUri = "bolt://" + clusteringContainer.getServiceHost("readreplica1", DEFAULT_BOLT_PORT)
 84 |                 + ":" +
 85 |                 clusteringContainer.getServicePort("readreplica1", DEFAULT_BOLT_PORT);
 86 | 
 87 |         try ( Driver coreDriver = GraphDatabase.driver( core1Uri, AuthTokens.basic( "neo4j", "neo")))
 88 |         {
 89 |             Session session = coreDriver.session();
 90 |             Result rs = session.run( "CREATE (arne:dog {name:'Arne'})-[:SNIFFS]->(bosse:dog {name:'Bosse'}) RETURN arne.name");
 91 |             Assertions.assertEquals( "Arne", rs.single().get( 0 ).asString(), "did not receive expected result from cypher CREATE query" );
 92 |         }
 93 |         catch (Exception e)
 94 |         {
 95 |             clusteringContainer.stop();
 96 |             return;
 97 |         }
 98 | 
 99 |         try ( Driver rrDriver = GraphDatabase.driver(rrUri, AuthTokens.basic("neo4j", "neo")))
100 |         {
101 |             Session session = rrDriver.session();
102 |             Result rs = session.run( "MATCH (a:dog)-[:SNIFFS]->(b:dog) RETURN a.name");
103 |             Assertions.assertEquals( "Arne", rs.single().get( 0 ).asString(), "did not receive expected result from cypher MATCH query" );
104 |         }
105 |         catch (Exception e)
106 |         {
107 |             clusteringContainer.stop();
108 |             return;
109 |         }
110 | 
111 |         clusteringContainer.stop();
112 | 
113 |     }
114 | 
115 |     private InputStream getResource(String path) {
116 |         InputStream resource = getClass().getClassLoader().getResourceAsStream(path);
117 |         return resource;
118 |     }
119 | }
120 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/docker-image-src/5/neo4j-admin/docker-entrypoint.sh:
--------------------------------------------------------------------------------

```bash
  1 | #!/bin/bash -eu
  2 | 
  3 | # load useful utility functions
  4 | . /startup/utilities.sh
  5 | 
  6 | function check_mounted_folder_writable_with_chown
  7 | {
  8 |     local mountFolder=${1}
  9 |     debug_msg "checking ${mountFolder} is writable"
 10 |     if running_as_root; then
 11 |         # check folder permissions
 12 |         if ! is_writable "${mountFolder}" ;  then
 13 |             # warn that we're about to chown the folder and then chown it
 14 |             echo "Warning: Folder mounted to \"${mountFolder}\" is not writable from inside container. Changing folder owner to ${userid}."
 15 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 16 |         # check permissions on files in the folder
 17 |         elif [ $(${exec_cmd} find "${mountFolder}" -not -writable | wc -l) -gt 0 ]; then
 18 |             echo "Warning: Some files inside \"${mountFolder}\" are not writable from inside container. Changing folder owner to ${userid}."
 19 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 20 |         fi
 21 |     else
 22 |         if [[ ! -w "${mountFolder}" ]]  && [[ "$(stat -c %U ${mountFolder})" != "neo4j" ]]; then
 23 |             print_permissions_advice_and_fail "${mountFolder}" "${userid}" "${groupid}"
 24 |         fi
 25 |     fi
 26 | }
 27 | 
 28 | # ==== SETUP WHICH USER TO RUN AS ====
 29 | debug_msg "DEBUGGING ENABLED"
 30 | 
 31 | if running_as_root; then
 32 |   userid="neo4j"
 33 |   groupid="neo4j"
 34 |   groups=($(id -G neo4j))
 35 |   exec_cmd="runuser -p -u neo4j -g neo4j --"
 36 |   debug_msg "Running as root user inside neo4j-admin image"
 37 | else
 38 |   userid="$(id -u)"
 39 |   groupid="$(id -g)"
 40 |   groups=($(id -G))
 41 |   exec_cmd="exec"
 42 |   debug_msg "Running as user ${userid} inside neo4j-admin image"
 43 | fi
 44 | 
 45 | #%%DEPRECATION_WARNING_PLACEHOLDER%%
 46 | 
 47 | # ==== MAKE SURE NEO4J CANNOT BE RUN FROM THIS CONTAINER ====
 48 | debug_msg "checking neo4j was not requested"
 49 | if [[ "${1}" == "neo4j" ]]; then
 50 |     correct_image="neo4j:"$(neo4j-admin --version)"-${NEO4J_EDITION}"
 51 |     echo >&2 "
 52 | This is a neo4j-admin only image, and usage of Neo4j server is not supported from here.
 53 | If you wish to start a Neo4j database, use:
 54 | 
 55 | docker run ${correct_image}
 56 |     "
 57 |     exit 1
 58 | fi
 59 | 
 60 | # ==== MAKE SURE NEO4J-ADMIN REPORT CANNOT BE RUN FROM THIS CONTAINER ====
 61 | debug_msg "checking neo4j-admin report was not requested"
 62 | # maybe make sure the command is neo4j-admin server report rather than just anything mentioning reports?
 63 | if containsElement "report" "${@}"; then
 64 |     echo >&2 \
 65 | "neo4j-admin report must be run in the same container as neo4j
 66 | otherwise the report tool cannot access relevant files and processes required for generating the report.
 67 | 
 68 | To run the report tool inside a neo4j container, do:
 69 | 
 70 | docker exec <CONTAINER NAME> neo4j-admin-report
 71 | 
 72 | "
 73 |     exit 1
 74 | fi
 75 | 
 76 | 
 77 | # ==== CHECK LICENSE AGREEMENT ====
 78 | 
 79 | debug_msg "checking license"
 80 | # Only prompt for license agreement if command contains "neo4j" in it
 81 | if [[ "${1}" == *"neo4j"* ]]; then
 82 |     if [ "${NEO4J_EDITION}" == "enterprise" ]; then
 83 |         : ${NEO4J_ACCEPT_LICENSE_AGREEMENT:="not accepted"}
 84 |         if [[ "$NEO4J_ACCEPT_LICENSE_AGREEMENT" != "yes" && "$NEO4J_ACCEPT_LICENSE_AGREEMENT" != "eval" ]]; then
 85 |             echo >&2 "
 86 | In order to use Neo4j Enterprise Edition you must accept the license agreement.
 87 | 
 88 | The license agreement is available at https://neo4j.com/terms/licensing/
 89 | If you have a support contract the following terms apply https://neo4j.com/terms/support-terms/
 90 | 
 91 | If you do not have a commercial license and want to evaluate the Software
 92 | please read the terms of the evaluation agreement before you accept.
 93 | https://neo4j.com/terms/enterprise_us/
 94 | 
 95 | (c) Neo4j Sweden AB. All Rights Reserved.
 96 | Use of this Software without a proper commercial license, or evaluation license
 97 | with Neo4j, Inc. or its affiliates is prohibited.
 98 | Neo4j has the right to terminate your usage if you are not compliant.
 99 | 
100 | More information is also available at: https://neo4j.com/licensing/
101 | If you have further inquiries about licensing, please contact us via https://neo4j.com/contact-us/
102 | 
103 | To accept the commercial license agreement set the environment variable
104 | NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
105 | 
106 | To accept the terms of the evaluation agreement set the environment variable
107 | NEO4J_ACCEPT_LICENSE_AGREEMENT=eval
108 | 
109 | To do this you can use the following docker argument:
110 | 
111 |         --env=NEO4J_ACCEPT_LICENSE_AGREEMENT=<yes|eval>
112 | "
113 |             exit 1
114 |         fi
115 |     fi
116 | fi
117 | 
118 | # ==== ENSURE MOUNT FOLDER READ/WRITABILITY ====
119 | debug_msg "Checking for mounted folder writability"
120 | 
121 | if [ -d /data ]; then
122 |     check_mounted_folder_writable_with_chown "/data"
123 |     if [ -d /data/databases ]; then
124 |         check_mounted_folder_writable_with_chown "/data/databases"
125 |     fi
126 |     if [ -d /data/dbms ]; then
127 |         check_mounted_folder_writable_with_chown "/data/dbms"
128 |     fi
129 |     if [ -d /data/transactions ]; then
130 |         check_mounted_folder_writable_with_chown "/data/transactions"
131 |     fi
132 | fi
133 | if [ -d /backups ]; then
134 |     check_mounted_folder_writable_with_chown "/backups"
135 | fi
136 | 
137 | # ==== START NEO4J-ADMIN COMMAND ====
138 | if debugging_enabled; then
139 |     echo ${exec_cmd} "${@}" --verbose
140 |     ${exec_cmd} "${@}" --verbose
141 | else
142 |     ${exec_cmd} "${@}"
143 | fi
144 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/docker-image-src/calver/neo4j-admin/docker-entrypoint.sh:
--------------------------------------------------------------------------------

```bash
  1 | #!/bin/bash -eu
  2 | 
  3 | # load useful utility functions
  4 | . /startup/utilities.sh
  5 | 
  6 | function check_mounted_folder_writable_with_chown
  7 | {
  8 |     local mountFolder=${1}
  9 |     debug_msg "checking ${mountFolder} is writable"
 10 |     if running_as_root; then
 11 |         # check folder permissions
 12 |         if ! is_writable "${mountFolder}" ;  then
 13 |             # warn that we're about to chown the folder and then chown it
 14 |             echo "Warning: Folder mounted to \"${mountFolder}\" is not writable from inside container. Changing folder owner to ${userid}."
 15 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 16 |         # check permissions on files in the folder
 17 |         elif [ $(${exec_cmd} find "${mountFolder}" -not -writable | wc -l) -gt 0 ]; then
 18 |             echo "Warning: Some files inside \"${mountFolder}\" are not writable from inside container. Changing folder owner to ${userid}."
 19 |             chown -R "${userid}":"${groupid}" "${mountFolder}"
 20 |         fi
 21 |     else
 22 |         if [[ ! -w "${mountFolder}" ]]  && [[ "$(stat -c %U ${mountFolder})" != "neo4j" ]]; then
 23 |             print_permissions_advice_and_fail "${mountFolder}" "${userid}" "${groupid}"
 24 |         fi
 25 |     fi
 26 | }
 27 | 
 28 | # ==== SETUP WHICH USER TO RUN AS ====
 29 | debug_msg "DEBUGGING ENABLED"
 30 | 
 31 | if running_as_root; then
 32 |   userid="neo4j"
 33 |   groupid="neo4j"
 34 |   groups=($(id -G neo4j))
 35 |   exec_cmd="runuser -p -u neo4j -g neo4j --"
 36 |   debug_msg "Running as root user inside neo4j-admin image"
 37 | else
 38 |   userid="$(id -u)"
 39 |   groupid="$(id -g)"
 40 |   groups=($(id -G))
 41 |   exec_cmd="exec"
 42 |   debug_msg "Running as user ${userid} inside neo4j-admin image"
 43 | fi
 44 | 
 45 | #%%DEPRECATION_WARNING_PLACEHOLDER%%
 46 | 
 47 | # ==== MAKE SURE NEO4J CANNOT BE RUN FROM THIS CONTAINER ====
 48 | debug_msg "checking neo4j was not requested"
 49 | if [[ "${1}" == "neo4j" ]]; then
 50 |     correct_image="neo4j:"$(neo4j-admin --version)"-${NEO4J_EDITION}"
 51 |     echo >&2 "
 52 | This is a neo4j-admin only image, and usage of Neo4j server is not supported from here.
 53 | If you wish to start a Neo4j database, use:
 54 | 
 55 | docker run ${correct_image}
 56 |     "
 57 |     exit 1
 58 | fi
 59 | 
 60 | # ==== MAKE SURE NEO4J-ADMIN REPORT CANNOT BE RUN FROM THIS CONTAINER ====
 61 | debug_msg "checking neo4j-admin report was not requested"
 62 | # maybe make sure the command is neo4j-admin server report rather than just anything mentioning reports?
 63 | if containsElement "report" "${@}"; then
 64 |     echo >&2 \
 65 | "neo4j-admin report must be run in the same container as neo4j
 66 | otherwise the report tool cannot access relevant files and processes required for generating the report.
 67 | 
 68 | To run the report tool inside a neo4j container, do:
 69 | 
 70 | docker exec <CONTAINER NAME> neo4j-admin-report
 71 | 
 72 | "
 73 |     exit 1
 74 | fi
 75 | 
 76 | 
 77 | # ==== CHECK LICENSE AGREEMENT ====
 78 | 
 79 | debug_msg "checking license"
 80 | # Only prompt for license agreement if command contains "neo4j" in it
 81 | if [[ "${1}" == *"neo4j"* ]]; then
 82 |     if [ "${NEO4J_EDITION}" == "enterprise" ]; then
 83 |         : ${NEO4J_ACCEPT_LICENSE_AGREEMENT:="not accepted"}
 84 |         if [[ "$NEO4J_ACCEPT_LICENSE_AGREEMENT" != "yes" && "$NEO4J_ACCEPT_LICENSE_AGREEMENT" != "eval" ]]; then
 85 |             echo >&2 "
 86 | In order to use Neo4j Enterprise Edition you must accept the license agreement.
 87 | 
 88 | The license agreement is available at https://neo4j.com/terms/licensing/
 89 | If you have a support contract the following terms apply https://neo4j.com/terms/support-terms/
 90 | 
 91 | If you do not have a commercial license and want to evaluate the Software
 92 | please read the terms of the evaluation agreement before you accept.
 93 | https://neo4j.com/terms/enterprise_us/
 94 | 
 95 | (c) Neo4j Sweden AB. All Rights Reserved.
 96 | Use of this Software without a proper commercial license, or evaluation license
 97 | with Neo4j, Inc. or its affiliates is prohibited.
 98 | Neo4j has the right to terminate your usage if you are not compliant.
 99 | 
100 | More information is also available at: https://neo4j.com/licensing/
101 | If you have further inquiries about licensing, please contact us via https://neo4j.com/contact-us/
102 | 
103 | To accept the commercial license agreement set the environment variable
104 | NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
105 | 
106 | To accept the terms of the evaluation agreement set the environment variable
107 | NEO4J_ACCEPT_LICENSE_AGREEMENT=eval
108 | 
109 | To do this you can use the following docker argument:
110 | 
111 |         --env=NEO4J_ACCEPT_LICENSE_AGREEMENT=<yes|eval>
112 | "
113 |             exit 1
114 |         fi
115 |     fi
116 | fi
117 | 
118 | # ==== ENSURE MOUNT FOLDER READ/WRITABILITY ====
119 | debug_msg "Checking for mounted folder writability"
120 | 
121 | if [ -d /data ]; then
122 |     check_mounted_folder_writable_with_chown "/data"
123 |     if [ -d /data/databases ]; then
124 |         check_mounted_folder_writable_with_chown "/data/databases"
125 |     fi
126 |     if [ -d /data/dbms ]; then
127 |         check_mounted_folder_writable_with_chown "/data/dbms"
128 |     fi
129 |     if [ -d /data/transactions ]; then
130 |         check_mounted_folder_writable_with_chown "/data/transactions"
131 |     fi
132 | fi
133 | if [ -d /backups ]; then
134 |     check_mounted_folder_writable_with_chown "/backups"
135 | fi
136 | 
137 | # ==== START NEO4J-ADMIN COMMAND ====
138 | if debugging_enabled; then
139 |     echo ${exec_cmd} "${@}" --verbose
140 |     ${exec_cmd} "${@}" --verbose
141 | else
142 |     ${exec_cmd} "${@}"
143 | fi
144 | 
```

--------------------------------------------------------------------------------
/crawled_pages.sql:
--------------------------------------------------------------------------------

```sql
  1 | -- Enable the pgvector extension
  2 | create extension if not exists vector;
  3 | 
  4 | -- Drop tables if they exist (to allow rerunning the script)
  5 | drop table if exists crawled_pages;
  6 | drop table if exists code_examples;
  7 | drop table if exists sources;
  8 | 
  9 | -- Create the sources table
 10 | create table sources (
 11 |     source_id text primary key,
 12 |     summary text,
 13 |     total_word_count integer default 0,
 14 |     created_at timestamp with time zone default timezone('utc'::text, now()) not null,
 15 |     updated_at timestamp with time zone default timezone('utc'::text, now()) not null
 16 | );
 17 | 
 18 | -- Create the documentation chunks table
 19 | create table crawled_pages (
 20 |     id bigserial primary key,
 21 |     url varchar not null,
 22 |     chunk_number integer not null,
 23 |     content text not null,
 24 |     metadata jsonb not null default '{}'::jsonb,
 25 |     source_id text not null,
 26 |     embedding vector(1536),  -- OpenAI embeddings are 1536 dimensions
 27 |     created_at timestamp with time zone default timezone('utc'::text, now()) not null,
 28 |     
 29 |     -- Add a unique constraint to prevent duplicate chunks for the same URL
 30 |     unique(url, chunk_number),
 31 |     
 32 |     -- Add foreign key constraint to sources table
 33 |     foreign key (source_id) references sources(source_id)
 34 | );
 35 | 
 36 | -- Create an index for better vector similarity search performance
 37 | create index on crawled_pages using ivfflat (embedding vector_cosine_ops);
 38 | 
 39 | -- Create an index on metadata for faster filtering
 40 | create index idx_crawled_pages_metadata on crawled_pages using gin (metadata);
 41 | 
 42 | -- Create an index on source_id for faster filtering
 43 | CREATE INDEX idx_crawled_pages_source_id ON crawled_pages (source_id);
 44 | 
 45 | -- Create a function to search for documentation chunks
 46 | create or replace function match_crawled_pages (
 47 |   query_embedding vector(1536),
 48 |   match_count int default 10,
 49 |   filter jsonb DEFAULT '{}'::jsonb,
 50 |   source_filter text DEFAULT NULL
 51 | ) returns table (
 52 |   id bigint,
 53 |   url varchar,
 54 |   chunk_number integer,
 55 |   content text,
 56 |   metadata jsonb,
 57 |   source_id text,
 58 |   similarity float
 59 | )
 60 | language plpgsql
 61 | as $$
 62 | #variable_conflict use_column
 63 | begin
 64 |   return query
 65 |   select
 66 |     id,
 67 |     url,
 68 |     chunk_number,
 69 |     content,
 70 |     metadata,
 71 |     source_id,
 72 |     1 - (crawled_pages.embedding <=> query_embedding) as similarity
 73 |   from crawled_pages
 74 |   where metadata @> filter
 75 |     AND (source_filter IS NULL OR source_id = source_filter)
 76 |   order by crawled_pages.embedding <=> query_embedding
 77 |   limit match_count;
 78 | end;
 79 | $$;
 80 | 
 81 | -- Enable RLS on the crawled_pages table
 82 | alter table crawled_pages enable row level security;
 83 | 
 84 | -- Create a policy that allows anyone to read crawled_pages
 85 | create policy "Allow public read access to crawled_pages"
 86 |   on crawled_pages
 87 |   for select
 88 |   to public
 89 |   using (true);
 90 | 
 91 | -- Enable RLS on the sources table
 92 | alter table sources enable row level security;
 93 | 
 94 | -- Create a policy that allows anyone to read sources
 95 | create policy "Allow public read access to sources"
 96 |   on sources
 97 |   for select
 98 |   to public
 99 |   using (true);
100 | 
101 | -- Create the code_examples table
102 | create table code_examples (
103 |     id bigserial primary key,
104 |     url varchar not null,
105 |     chunk_number integer not null,
106 |     content text not null,  -- The code example content
107 |     summary text not null,  -- Summary of the code example
108 |     metadata jsonb not null default '{}'::jsonb,
109 |     source_id text not null,
110 |     embedding vector(1536),  -- OpenAI embeddings are 1536 dimensions
111 |     created_at timestamp with time zone default timezone('utc'::text, now()) not null,
112 |     
113 |     -- Add a unique constraint to prevent duplicate chunks for the same URL
114 |     unique(url, chunk_number),
115 |     
116 |     -- Add foreign key constraint to sources table
117 |     foreign key (source_id) references sources(source_id)
118 | );
119 | 
120 | -- Create an index for better vector similarity search performance
121 | create index on code_examples using ivfflat (embedding vector_cosine_ops);
122 | 
123 | -- Create an index on metadata for faster filtering
124 | create index idx_code_examples_metadata on code_examples using gin (metadata);
125 | 
126 | -- Create an index on source_id for faster filtering
127 | CREATE INDEX idx_code_examples_source_id ON code_examples (source_id);
128 | 
129 | -- Create a function to search for code examples
130 | create or replace function match_code_examples (
131 |   query_embedding vector(1536),
132 |   match_count int default 10,
133 |   filter jsonb DEFAULT '{}'::jsonb,
134 |   source_filter text DEFAULT NULL
135 | ) returns table (
136 |   id bigint,
137 |   url varchar,
138 |   chunk_number integer,
139 |   content text,
140 |   summary text,
141 |   metadata jsonb,
142 |   source_id text,
143 |   similarity float
144 | )
145 | language plpgsql
146 | as $$
147 | #variable_conflict use_column
148 | begin
149 |   return query
150 |   select
151 |     id,
152 |     url,
153 |     chunk_number,
154 |     content,
155 |     summary,
156 |     metadata,
157 |     source_id,
158 |     1 - (code_examples.embedding <=> query_embedding) as similarity
159 |   from code_examples
160 |   where metadata @> filter
161 |     AND (source_filter IS NULL OR source_id = source_filter)
162 |   order by code_examples.embedding <=> query_embedding
163 |   limit match_count;
164 | end;
165 | $$;
166 | 
167 | -- Enable RLS on the code_examples table
168 | alter table code_examples enable row level security;
169 | 
170 | -- Create a policy that allows anyone to read code_examples
171 | create policy "Allow public read access to code_examples"
172 |   on code_examples
173 |   for select
174 |   to public
175 |   using (true);
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/coredb/configurations/Configuration.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker.coredb.configurations;
  2 | 
  3 | import com.neo4j.docker.utils.Neo4jVersion;
  4 | import com.neo4j.docker.utils.TestSettings;
  5 | 
  6 | import java.nio.file.Path;
  7 | import java.nio.file.Paths;
  8 | import java.util.EnumMap;
  9 | import java.util.Map;
 10 | 
 11 | public class Configuration
 12 | {
 13 |     private static Map<Setting,Configuration> CONFIGURATIONS_5X = new EnumMap<Setting,Configuration>( Setting.class ) {{
 14 |         put( Setting.APOC_EXPORT_FILE_ENABLED, new Configuration( "apoc.export.file.enabled"));
 15 |         put( Setting.BACKUP_ENABLED, new Configuration("server.backup.enabled"));
 16 |         put( Setting.BACKUP_LISTEN_ADDRESS, new Configuration("server.backup.listen_address"));
 17 |         put( Setting.BROWSER_ALLOW_OUTGOING_CONNECTIONS, new Configuration("browser.allow_outgoing_connections"));
 18 |         put( Setting.CLUSTER_RAFT_ADDRESS, new Configuration("server.cluster.raft.advertised_address"));
 19 |         put( Setting.CLUSTER_ROUTING_ADDRESS, new Configuration("server.routing.advertised_address"));
 20 |         put( Setting.CLUSTER_TRANSACTION_ADDRESS, new Configuration("server.cluster.advertised_address"));
 21 |         put( Setting.DEFAULT_LISTEN_ADDRESS, new Configuration("server.default_listen_address"));
 22 |         put( Setting.DIRECTORIES_DATA, new Configuration("server.directories.data"));
 23 |         put( Setting.DIRECTORIES_LOGS, new Configuration("server.directories.logs"));
 24 |         put( Setting.DIRECTORIES_METRICS, new Configuration("server.directories.metrics"));
 25 |         put( Setting.JVM_ADDITIONAL, new Configuration("server.jvm.additional"));
 26 |         put( Setting.LOGS_GC_ROTATION_KEEPNUMBER, new Configuration( "server.logs.gc.rotation.keep_number"));
 27 |         put( Setting.MEMORY_HEAP_INITIALSIZE, new Configuration("server.memory.heap.initial_size"));
 28 |         put( Setting.MEMORY_HEAP_MAXSIZE, new Configuration( "server.memory.heap.max_size"));
 29 |         put( Setting.MEMORY_PAGECACHE_SIZE, new Configuration("server.memory.pagecache.size"));
 30 |         put( Setting.MINIMUM_PASSWORD_LENGTH, new Configuration("dbms.security.auth_minimum_password_length"));
 31 |         put( Setting.SECURITY_PROCEDURES_UNRESTRICTED, new Configuration("dbms.security.procedures.unrestricted"));
 32 |         put( Setting.TXLOG_RETENTION_POLICY, new Configuration("db.tx_log.rotation.retention_policy"));
 33 |     }};
 34 | 
 35 |     private static Map<Setting,Configuration> CONFIGURATIONS_4X = new EnumMap<Setting,Configuration>( Setting.class ) {{
 36 |         put( Setting.APOC_EXPORT_FILE_ENABLED, new Configuration( "apoc.export.file.enabled"));
 37 |         put( Setting.BACKUP_ENABLED, new Configuration("dbms.backup.enabled"));
 38 |         put( Setting.BACKUP_LISTEN_ADDRESS, new Configuration("dbms.backup.listen_address"));
 39 |         put( Setting.BROWSER_ALLOW_OUTGOING_CONNECTIONS, new Configuration("browser.allow_outgoing_connections"));
 40 |         put( Setting.CLUSTER_DISCOVERY_ADDRESS, new Configuration("causal_clustering.discovery_advertised_address"));
 41 |         put( Setting.CLUSTER_RAFT_ADDRESS, new Configuration("causal_clustering.raft_advertised_address"));
 42 |         put( Setting.CLUSTER_ROUTING_ADDRESS, new Configuration("dbms.routing.advertised_address"));
 43 |         put( Setting.CLUSTER_TRANSACTION_ADDRESS, new Configuration("causal_clustering.transaction_advertised_address"));
 44 |         put( Setting.DEFAULT_LISTEN_ADDRESS, new Configuration("dbms.default_listen_address"));
 45 |         put( Setting.DIRECTORIES_DATA, new Configuration("dbms.directories.data"));
 46 |         put( Setting.DIRECTORIES_LOGS, new Configuration("dbms.directories.logs"));
 47 |         put( Setting.DIRECTORIES_METRICS, new Configuration("dbms.directories.metrics"));
 48 |         put( Setting.JVM_ADDITIONAL, new Configuration("dbms.jvm.additional"));
 49 |         put( Setting.LOGS_GC_ROTATION_KEEPNUMBER, new Configuration( "dbms.logs.gc.rotation.keep_number"));
 50 |         put( Setting.MEMORY_HEAP_INITIALSIZE, new Configuration("dbms.memory.heap.initial_size"));
 51 |         put( Setting.MEMORY_HEAP_MAXSIZE, new Configuration("dbms.memory.heap.max_size"));
 52 |         put( Setting.MEMORY_PAGECACHE_SIZE, new Configuration("dbms.memory.pagecache.size"));
 53 |         put( Setting.SECURITY_PROCEDURES_UNRESTRICTED, new Configuration("dbms.security.procedures.unrestricted"));
 54 |         put( Setting.TXLOG_RETENTION_POLICY, new Configuration("dbms.tx_log.rotation.retention_policy"));
 55 |     }};
 56 |     public static Map<Setting,Configuration> getConfigurationNameMap()
 57 |     {
 58 |         return getConfigurationNameMap( TestSettings.NEO4J_VERSION );
 59 |     }
 60 | 
 61 |     public static Map<Setting,Configuration> getConfigurationNameMap( Neo4jVersion version )
 62 |     {
 63 |         switch ( version.major )
 64 |         {
 65 |         case 3:
 66 |             EnumMap<Setting,Configuration> out = new EnumMap<Setting,Configuration>( CONFIGURATIONS_4X );
 67 |             out.put( Setting.DEFAULT_LISTEN_ADDRESS, new Configuration( "dbms.connectors.default_listen_address" ) );
 68 |             return out;
 69 |         case 4:
 70 |             return CONFIGURATIONS_4X;
 71 |         default:
 72 |             return CONFIGURATIONS_5X;
 73 |         }
 74 |     }
 75 |     public static Path getConfigurationResourcesFolder()
 76 |     {
 77 |         return getConfigurationResourcesFolder(TestSettings.NEO4J_VERSION);
 78 |     }
 79 | 
 80 |     public static Path getConfigurationResourcesFolder( Neo4jVersion version )
 81 |     {
 82 |         if(version.isAtLeastVersion( Neo4jVersion.NEO4J_VERSION_500 ))
 83 |         {
 84 |         return Paths.get("src", "test", "resources", "confs");
 85 |         }
 86 |         else return Paths.get( "src", "test", "resources", "confs", "before50");
 87 |     }
 88 | 
 89 |     public String name;
 90 |     public String envName;
 91 | 
 92 |     private Configuration( String name )
 93 |     {
 94 |         this.name = name;
 95 |         this.envName = "NEO4J_" + name.replace( '_', '-' )
 96 |                                       .replace( '.', '_')
 97 |                                       .replace( "-", "__" );
 98 |     }
 99 | }
100 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/docker-image-src/3.0/docker-entrypoint.sh:
--------------------------------------------------------------------------------

```bash
  1 | #!/bin/bash -eu
  2 | 
  3 | setting() {
  4 |     setting="${1}"
  5 |     value="${2}"
  6 |     file="${3:-neo4j.conf}"
  7 | 
  8 |     if [ ! -f "conf/${file}" ]; then
  9 |         if [ -f "conf/neo4j.conf" ]; then
 10 |             file="neo4j.conf"
 11 |         fi
 12 |     fi
 13 | 
 14 |     # Don't allow settings with no value or settings that start with a number (neo4j converts settings to env variables and you cannot have an env variable that starts with a number)
 15 |     if [[ -n ${value} ]]; then
 16 |         if [[ ! "${setting}" =~ ^[0-9]+.*$ ]]; then
 17 |             if grep --quiet --fixed-strings "${setting}=" conf/"${file}"; then
 18 |                 sed --in-place "s|.*${setting}=.*|${setting}=${value}|" conf/"${file}"
 19 |             else
 20 |                 echo "${setting}=${value}" >>conf/"${file}"
 21 |             fi
 22 |         else
 23 |             echo >&2 "WARNING: ${setting} not written to conf file because settings that start with a number are not permitted"
 24 |         fi
 25 |     fi
 26 | }
 27 | 
 28 | cmd="$1"
 29 | 
 30 | if [ "${cmd}" == "dump-config" ]; then
 31 |     if [ -d /conf ]; then
 32 |         cp --recursive conf/* /conf
 33 |         exit 0
 34 |     else
 35 |         echo >&2 "You must provide a /conf volume"
 36 |         exit 1
 37 |     fi
 38 | fi
 39 | 
 40 | # Env variable naming convention:
 41 | # - prefix NEO4J_
 42 | # - double underscore char '__' instead of single underscore '_' char in the setting name
 43 | # - underscore char '_' instead of dot '.' char in the setting name
 44 | # Example:
 45 | # NEO4J_dbms_tx__log_rotation_retention__policy env variable to set
 46 | #       dbms.tx_log.rotation.retention_policy setting
 47 | 
 48 | # Backward compatibility - map old hardcoded env variables into new naming convention (if they aren't set already)
 49 | # Set some to default values if unset
 50 | : ${NEO4J_dbms_tx__log_rotation_retention__policy:=${NEO4J_dbms_txLog_rotation_retentionPolicy:-"100M size"}}
 51 | : ${NEO4J_wrapper_java_additional:=${NEO4J_UDC_SOURCE:-"-Dneo4j.ext.udc.source=docker"}}
 52 | : ${NEO4J_dbms_memory_heap_initial__size:=${NEO4J_dbms_memory_heap_maxSize:-"512"}}
 53 | : ${NEO4J_dbms_memory_heap_max__size:=${NEO4J_dbms_memory_heap_maxSize:-"512"}}
 54 | : ${NEO4J_dbms_unmanaged__extension__classes:=${NEO4J_dbms_unmanagedExtensionClasses:-}}
 55 | : ${NEO4J_dbms_allow__format__migration:=${NEO4J_dbms_allowFormatMigration:-}}
 56 | : ${NEO4J_ha_server__id:=${NEO4J_ha_serverId:-}}
 57 | : ${NEO4J_ha_initial__hosts:=${NEO4J_ha_initialHosts:-}}
 58 | 
 59 | : ${NEO4J_dbms_connector_http_address:="0.0.0.0:7474"}
 60 | : ${NEO4J_dbms_connector_https_address:="0.0.0.0:7473"}
 61 | : ${NEO4J_dbms_connector_bolt_address:="0.0.0.0:7687"}
 62 | : ${NEO4J_ha_host_coordination:="$(hostname):5001"}
 63 | : ${NEO4J_ha_host_data:="$(hostname):6001"}
 64 | 
 65 | # unset old hardcoded unsupported env variables
 66 | unset NEO4J_dbms_txLog_rotation_retentionPolicy NEO4J_UDC_SOURCE \
 67 |     NEO4J_dbms_memory_heap_maxSize NEO4J_dbms_memory_heap_maxSize \
 68 |     NEO4J_dbms_unmanagedExtensionClasses NEO4J_dbms_allowFormatMigration \
 69 |     NEO4J_ha_initialHosts
 70 | 
 71 | if [ -d /conf ]; then
 72 |     find /conf -type f -exec cp {} conf \;
 73 | fi
 74 | 
 75 | if [ -d /ssl ]; then
 76 |     NEO4J_dbms_directories_certificates="/ssl"
 77 | fi
 78 | 
 79 | if [ -d /plugins ]; then
 80 |     NEO4J_dbms_directories_plugins="/plugins"
 81 | fi
 82 | 
 83 | if [ -d /logs ]; then
 84 |     NEO4J_dbms_directories_logs="/logs"
 85 | fi
 86 | 
 87 | if [ -d /import ]; then
 88 |     NEO4J_dbms_directories_import="/import"
 89 | fi
 90 | 
 91 | if [ -d /metrics ]; then
 92 |     NEO4J_dbms_directories_metrics="/metrics"
 93 | fi
 94 | 
 95 | if [ "${cmd}" == "neo4j" ] ; then
 96 |     if [ "${NEO4J_AUTH:-}" == "none" ]; then
 97 |         NEO4J_dbms_security_auth__enabled=false
 98 |     elif [[ "${NEO4J_AUTH:-}" == neo4j/* ]]; then
 99 |         password="${NEO4J_AUTH#neo4j/}"
100 |         if [ "${password}" == "neo4j" ]; then
101 |             echo "Invalid value for password. It cannot be 'neo4j', which is the default."
102 |             exit 1
103 |         fi
104 | 
105 |         setting "dbms.connector.http.address" "127.0.0.1:7474"
106 |         setting "dbms.connector.https.address" "127.0.0.1:7473"
107 |         setting "dbms.connector.bolt.address" "127.0.0.1:7687"
108 |         bin/neo4j start || \
109 |             (cat logs/neo4j.log && echo "Neo4j failed to start for password change" && exit 1)
110 | 
111 |         end="$((SECONDS+100))"
112 |         while true; do
113 |             http_code="$(curl --silent --write-out %{http_code} --user "neo4j:${password}" --output /dev/null http://localhost:7474/db/data/ || true)"
114 | 
115 |             if [[ "${http_code}" = "200" ]]; then
116 |                 break;
117 |             fi
118 | 
119 |             if [[ "${http_code}" = "401" ]]; then
120 |                 curl --fail --silent --show-error --user neo4j:neo4j \
121 |                      --data '{"password": "'"${password}"'"}' \
122 |                      --header 'Content-Type: application/json' \
123 |                      http://localhost:7474/user/neo4j/password
124 |                 break;
125 |             fi
126 | 
127 |             if [[ "${SECONDS}" -ge "${end}" ]]; then
128 |                 (cat logs/neo4j.log && echo "Neo4j failed to start" && exit 1)
129 |             fi
130 | 
131 |             sleep 1
132 |         done
133 | 
134 |         bin/neo4j stop
135 |     elif [ -n "${NEO4J_AUTH:-}" ]; then
136 |         echo "Invalid value for NEO4J_AUTH: '${NEO4J_AUTH}'"
137 |         exit 1
138 |     fi
139 | fi
140 | 
141 | # list env variables with prefix NEO4J_ and create settings from them
142 | unset NEO4J_AUTH NEO4J_SHA256 NEO4J_TARBALL
143 | for i in $( set | grep ^NEO4J_ | awk -F'=' '{print $1}' | sort -rn ); do
144 |     setting=$(echo ${i} | sed 's|^NEO4J_||' | sed 's|_|.|g' | sed 's|\.\.|_|g')
145 |     value=$(echo ${!i})
146 |     if [[ -n ${value} ]]; then
147 |         if [[ ! "${setting}" =~ ^[0-9]+.*$ ]]; then
148 |             if grep -q -F "${setting}=" conf/neo4j.conf; then
149 |                 # Remove any lines containing the setting already
150 |                 sed --in-place "/^${setting}=.*/d" conf/neo4j.conf
151 |             fi
152 |             # Then always append setting to file
153 |             echo "${setting}=${value}" >> conf/neo4j.conf
154 |         else
155 |             echo >&2 "WARNING: ${setting} not written to conf file because settings that start with a number are not permitted"
156 |         fi
157 |     fi
158 | done
159 | 
160 | [ -f "${EXTENSION_SCRIPT:-}" ] && . ${EXTENSION_SCRIPT}
161 | 
162 | if [ "${cmd}" == "neo4j" ] ; then
163 |     exec bin/neo4j console
164 | else
165 |     exec "$@"
166 | fi
167 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/neo4jadmin/TestDumpLoad.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker.neo4jadmin;
  2 | 
  3 | import com.neo4j.docker.utils.DatabaseIO;
  4 | import com.neo4j.docker.utils.Neo4jVersion;
  5 | import com.neo4j.docker.utils.SetContainerUser;
  6 | import com.neo4j.docker.utils.WaitStrategies;
  7 | import com.neo4j.docker.utils.TemporaryFolderManager;
  8 | import com.neo4j.docker.utils.TestSettings;
  9 | import org.junit.jupiter.api.Assertions;
 10 | import org.junit.jupiter.api.Assumptions;
 11 | import org.junit.jupiter.api.BeforeAll;
 12 | import org.junit.jupiter.api.Test;
 13 | import org.junit.jupiter.api.extension.RegisterExtension;
 14 | import org.slf4j.Logger;
 15 | import org.slf4j.LoggerFactory;
 16 | import org.testcontainers.containers.GenericContainer;
 17 | import org.testcontainers.containers.output.Slf4jLogConsumer;
 18 | import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy;
 19 | import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
 20 | 
 21 | import java.nio.file.Path;
 22 | import java.time.Duration;
 23 | 
 24 | public class TestDumpLoad
 25 | {
 26 |     private static Logger log = LoggerFactory.getLogger( TestDumpLoad.class );
 27 |     @RegisterExtension
 28 |     public static TemporaryFolderManager temporaryFolderManager = new TemporaryFolderManager();
 29 | 
 30 |     @BeforeAll
 31 |     static void beforeAll()
 32 |     {
 33 |         Assumptions.assumeTrue( TestSettings.NEO4J_VERSION.isAtLeastVersion( Neo4jVersion.NEO4J_VERSION_500 ),
 34 |                                 "These tests only apply to neo4j-admin images of 5.0 and greater");
 35 |     }
 36 | 
 37 |     private GenericContainer createDBContainer( boolean asDefaultUser, String password )
 38 |     {
 39 |         String auth = "none";
 40 |         if(!password.equalsIgnoreCase("none"))
 41 |         {
 42 |             auth = "neo4j/"+password;
 43 |         }
 44 | 
 45 |         GenericContainer container = new GenericContainer( TestSettings.IMAGE_ID );
 46 |         container.withEnv( "NEO4J_AUTH", auth )
 47 |                  .withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 48 |                  .withExposedPorts( 7474, 7687 )
 49 |                  .withLogConsumer( new Slf4jLogConsumer( log ) )
 50 |                  .waitingFor( WaitStrategies.waitForNeo4jReady( password) );
 51 |         if(!asDefaultUser)
 52 |         {
 53 |             SetContainerUser.nonRootUser( container );
 54 |         }
 55 |         return container;
 56 |     }
 57 | 
 58 |     private GenericContainer createAdminContainer( boolean asDefaultUser )
 59 |     {
 60 |         GenericContainer container = new GenericContainer( TestSettings.ADMIN_IMAGE_ID );
 61 |         container.withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 62 |                  .withExposedPorts( 7474, 7687 )
 63 |                  .withLogConsumer( new Slf4jLogConsumer( log ) )
 64 |                  .waitingFor( new LogMessageWaitStrategy().withRegEx( "^Done: \\d+ files, [\\d\\.,]+[KMGi]*B processed.*" ) )
 65 | //                 .waitingFor( new LogMessageWaitStrategy().withRegEx( "^Done: .*" ) )
 66 |                  .withStartupCheckStrategy( new OneShotStartupCheckStrategy().withTimeout( Duration.ofSeconds( 90 ) ) );
 67 |         if(!asDefaultUser)
 68 |         {
 69 |             SetContainerUser.nonRootUser( container );
 70 |         }
 71 |         return container;
 72 |     }
 73 | 
 74 |     @Test
 75 |     void shouldDumpAndLoad_defaultUser_noAuth() throws Exception
 76 |     {
 77 |         shouldCreateDumpAndLoadDump( true, "none" );
 78 |     }
 79 | 
 80 |     @Test
 81 |     void shouldDumpAndLoad_nonDefaultUser_noAuth() throws Exception
 82 |     {
 83 |         shouldCreateDumpAndLoadDump( false, "none" );
 84 |     }
 85 | 
 86 |     @Test
 87 |     void shouldDumpAndLoad_defaultUser_withAuth() throws Exception
 88 |     {
 89 |         shouldCreateDumpAndLoadDump( true, "verysecretpassword" );
 90 |     }
 91 | 
 92 |     @Test
 93 |     void shouldDumpAndLoad_nonDefaultUser_withAuth() throws Exception
 94 |     {
 95 |         shouldCreateDumpAndLoadDump( false, "verysecretpassword" );
 96 |     }
 97 | 
 98 |     private void shouldCreateDumpAndLoadDump( boolean asDefaultUser, String password ) throws Exception
 99 |     {
100 |         Path firstDataDir;
101 |         Path secondDataDir;
102 |         Path backupDir;
103 | 
104 |         // start a database and populate it
105 |         try(GenericContainer container = createDBContainer( asDefaultUser, password ))
106 |         {
107 |             firstDataDir = temporaryFolderManager.createNamedFolderAndMountAsVolume(container,"data1", "/data");
108 |             container.start();
109 |             DatabaseIO dbio = new DatabaseIO( container );
110 |             dbio.putInitialDataIntoContainer( "neo4j", password );
111 |             container.getDockerClient().stopContainerCmd( container.getContainerId() ).withTimeout(30).exec();
112 |         }
113 | 
114 |         // use admin container to create dump
115 |         try(GenericContainer admin = createAdminContainer( asDefaultUser ))
116 |         {
117 |             temporaryFolderManager.mountHostFolderAsVolume( admin, firstDataDir, "/data" );
118 |             backupDir = temporaryFolderManager.createFolderAndMountAsVolume(admin, "/backups");
119 |             admin.withCommand( "neo4j-admin", "database", "dump", "neo4j", "--to-path=/backups" );
120 |             admin.start();
121 |         }
122 |         Assertions.assertTrue( backupDir.resolve( "neo4j.dump" ).toFile().exists(), "dump file not created");
123 | 
124 |         // dump file exists. Now try to load it into a new database.
125 |         // use admin container to create dump
126 |         try(GenericContainer admin = createAdminContainer( asDefaultUser ))
127 |         {
128 |             secondDataDir = temporaryFolderManager.createNamedFolderAndMountAsVolume(admin, "data2", "/data");
129 |             temporaryFolderManager.mountHostFolderAsVolume( admin, backupDir, "/backups" );
130 |             admin.withCommand( "neo4j-admin", "database", "load", "neo4j", "--from-path=/backups" );
131 |             admin.start();
132 |         }
133 | 
134 |         // verify data in 2nd data directory by starting a database and verifying data we populated earlier
135 |         try(GenericContainer container = createDBContainer( asDefaultUser, password ))
136 |         {
137 |             temporaryFolderManager.mountHostFolderAsVolume( container, secondDataDir, "/data" );
138 |             container.start();
139 |             DatabaseIO dbio = new DatabaseIO( container );
140 |             dbio.verifyInitialDataInContainer( "neo4j", password );
141 |         }
142 |     }
143 | }
144 | 
```

--------------------------------------------------------------------------------
/knowledge_graphs/test_script.py:
--------------------------------------------------------------------------------

```python
  1 | from __future__ import annotations
  2 | from typing import Dict, List, Optional
  3 | from dataclasses import dataclass
  4 | from pydantic import BaseModel, Field
  5 | from dotenv import load_dotenv
  6 | from rich.markdown import Markdown
  7 | from rich.console import Console
  8 | from rich.live import Live
  9 | import asyncio
 10 | import os
 11 | 
 12 | from pydantic_ai.providers.openai import OpenAIProvider
 13 | from pydantic_ai.models.openai import OpenAIModel
 14 | from pydantic_ai import Agent, RunContext
 15 | from graphiti_core import Graphiti
 16 | 
 17 | load_dotenv()
 18 | 
 19 | # ========== Define dependencies ==========
 20 | @dataclass
 21 | class GraphitiDependencies:
 22 |     """Dependencies for the Graphiti agent."""
 23 |     graphiti_client: Graphiti
 24 | 
 25 | # ========== Helper function to get model configuration ==========
 26 | def get_model():
 27 |     """Configure and return the LLM model to use."""
 28 |     model_choice = os.getenv('MODEL_CHOICE', 'gpt-4.1-mini')
 29 |     api_key = os.getenv('OPENAI_API_KEY', 'no-api-key-provided')
 30 | 
 31 |     return OpenAIModel(model_choice, provider=OpenAIProvider(api_key=api_key))
 32 | 
 33 | # ========== Create the Graphiti agent ==========
 34 | graphiti_agent = Agent(
 35 |     get_model(),
 36 |     system_prompt="""You are a helpful assistant with access to a knowledge graph filled with temporal data about LLMs.
 37 |     When the user asks you a question, use your search tool to query the knowledge graph and then answer honestly.
 38 |     Be willing to admit when you didn't find the information necessary to answer the question.""",
 39 |     deps_type=GraphitiDependencies
 40 | )
 41 | 
 42 | # ========== Define a result model for Graphiti search ==========
 43 | class GraphitiSearchResult(BaseModel):
 44 |     """Model representing a search result from Graphiti."""
 45 |     uuid: str = Field(description="The unique identifier for this fact")
 46 |     fact: str = Field(description="The factual statement retrieved from the knowledge graph")
 47 |     valid_at: Optional[str] = Field(None, description="When this fact became valid (if known)")
 48 |     invalid_at: Optional[str] = Field(None, description="When this fact became invalid (if known)")
 49 |     source_node_uuid: Optional[str] = Field(None, description="UUID of the source node")
 50 | 
 51 | # ========== Graphiti search tool ==========
 52 | @graphiti_agent.tool
 53 | async def search_graphiti(ctx: RunContext[GraphitiDependencies], query: str) -> List[GraphitiSearchResult]:
 54 |     """Search the Graphiti knowledge graph with the given query.
 55 |     
 56 |     Args:
 57 |         ctx: The run context containing dependencies
 58 |         query: The search query to find information in the knowledge graph
 59 |         
 60 |     Returns:
 61 |         A list of search results containing facts that match the query
 62 |     """
 63 |     # Access the Graphiti client from dependencies
 64 |     graphiti = ctx.deps.graphiti_client
 65 |     
 66 |     try:
 67 |         # Perform the search
 68 |         results = await graphiti.search(query)
 69 |         
 70 |         # Format the results
 71 |         formatted_results = []
 72 |         for result in results:
 73 |             formatted_result = GraphitiSearchResult(
 74 |                 uuid=result.uuid,
 75 |                 fact=result.fact,
 76 |                 source_node_uuid=result.source_node_uuid if hasattr(result, 'source_node_uuid') else None
 77 |             )
 78 |             
 79 |             # Add temporal information if available
 80 |             if hasattr(result, 'valid_at') and result.valid_at:
 81 |                 formatted_result.valid_at = str(result.valid_at)
 82 |             if hasattr(result, 'invalid_at') and result.invalid_at:
 83 |                 formatted_result.invalid_at = str(result.invalid_at)
 84 |             
 85 |             formatted_results.append(formatted_result)
 86 |         
 87 |         return formatted_results
 88 |     except Exception as e:
 89 |         # Log the error but don't close the connection since it's managed by the dependency
 90 |         print(f"Error searching Graphiti: {str(e)}")
 91 |         raise
 92 | 
 93 | # ========== Main execution function ==========
 94 | async def main():
 95 |     """Run the Graphiti agent with user queries."""
 96 |     print("Graphiti Agent - Powered by Pydantic AI, Graphiti, and Neo4j")
 97 |     print("Enter 'exit' to quit the program.")
 98 | 
 99 |     # Neo4j connection parameters
100 |     neo4j_uri = os.environ.get('NEO4J_URI', 'bolt://localhost:7687')
101 |     neo4j_user = os.environ.get('NEO4J_USER', 'neo4j')
102 |     neo4j_password = os.environ.get('NEO4J_PASSWORD', 'password')
103 |     
104 |     # Initialize Graphiti with Neo4j connection
105 |     graphiti_client = Graphiti(neo4j_uri, neo4j_user, neo4j_password)
106 |     
107 |     # Initialize the graph database with graphiti's indices if needed
108 |     try:
109 |         await graphiti_client.build_indices_and_constraints()
110 |         print("Graphiti indices built successfully.")
111 |     except Exception as e:
112 |         print(f"Note: {str(e)}")
113 |         print("Continuing with existing indices...")
114 | 
115 |     console = Console()
116 |     messages = []
117 |     
118 |     try:
119 |         while True:
120 |             # Get user input
121 |             user_input = input("\n[You] ")
122 |             
123 |             # Check if user wants to exit
124 |             if user_input.lower() in ['exit', 'quit', 'bye', 'goodbye']:
125 |                 print("Goodbye!")
126 |                 break
127 |             
128 |             try:
129 |                 # Process the user input and output the response
130 |                 print("\n[Assistant]")
131 |                 with Live('', console=console, vertical_overflow='visible') as live:
132 |                     # Pass the Graphiti client as a dependency
133 |                     deps = GraphitiDependencies(graphiti_client=graphiti_client)
134 |                     
135 |                     async with graphiti_agent.run_a_stream(
136 |                         user_input, message_history=messages, deps=deps
137 |                     ) as result:
138 |                         curr_message = ""
139 |                         async for message in result.stream_text(delta=True):
140 |                             curr_message += message
141 |                             live.update(Markdown(curr_message))
142 |                     
143 |                     # Add the new messages to the chat history
144 |                     messages.extend(result.all_messages())
145 |                 
146 |             except Exception as e:
147 |                 print(f"\n[Error] An error occurred: {str(e)}")
148 |     finally:
149 |         # Close the Graphiti connection when done
150 |         await graphiti_client.close()
151 |         print("\nGraphiti connection closed.")
152 | 
153 | if __name__ == "__main__":
154 |     try:
155 |         asyncio.run(main())
156 |     except KeyboardInterrupt:
157 |         print("\nProgram terminated by user.")
158 |     except Exception as e:
159 |         print(f"\nUnexpected error: {str(e)}")
160 |         raise
161 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/TestDeprecationWarning.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker;
  2 | 
  3 | import com.neo4j.docker.utils.TestSettings;
  4 | import com.neo4j.docker.utils.WaitStrategies;
  5 | import org.junit.jupiter.api.Assertions;
  6 | import org.junit.jupiter.api.Assumptions;
  7 | import org.junit.jupiter.api.Test;
  8 | import org.slf4j.Logger;
  9 | import org.slf4j.LoggerFactory;
 10 | import org.testcontainers.containers.GenericContainer;
 11 | import org.testcontainers.containers.output.OutputFrame;
 12 | import org.testcontainers.containers.output.Slf4jLogConsumer;
 13 | 
 14 | import java.time.Duration;
 15 | 
 16 | public class TestDeprecationWarning
 17 | {
 18 |     private final Logger log = LoggerFactory.getLogger( TestDeprecationWarning.class );
 19 |     private static final String DEPRECATION_WARN_STRING = "Neo4j Red Hat UBI8 images are deprecated in favour of Red Hat UBI9";
 20 |     private static final String DEPRECATION_WARN_SUPPRESS_FLAG = "NEO4J_DEPRECATION_WARNING";
 21 | 
 22 |     // The opposite test to make sure there are no deprecation warnings in non-ubi8 images already exists at
 23 |     // com.neo4j.docker.coredb.TestBasic.testNoUnexpectedErrors
 24 |     @Test
 25 |     void shouldWarnIfUsingDeprecatedBaseOS_coreDB() throws Exception
 26 |     {
 27 |         Assumptions.assumeTrue( TestSettings.BASE_OS == TestSettings.BaseOS.UBI8,
 28 |                                 "Deprecation warning should only exist in UBI8 images");
 29 |         try(GenericContainer container = new GenericContainer(TestSettings.IMAGE_ID))
 30 |         {
 31 |             container.withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 32 |                      .withExposedPorts( 7474, 7687 )
 33 |                      .withLogConsumer( new Slf4jLogConsumer( log ))
 34 |                      .waitingFor( WaitStrategies.waitForBoltReady() );
 35 |             container.start();
 36 |             // container should successfully start
 37 |             String logs = container.getLogs( OutputFrame.OutputType.STDERR );
 38 |             Assertions.assertTrue( logs.contains( DEPRECATION_WARN_STRING ),
 39 |                                    "Container did not warn about ubi8 deprecation. Actual error logs:\n"+logs);
 40 |         }
 41 |     }
 42 | 
 43 |     @Test
 44 |     void shouldWarnIfUsingDeprecatedBaseOS_admin()
 45 |     {
 46 |         Assumptions.assumeTrue( TestSettings.BASE_OS == TestSettings.BaseOS.UBI8,
 47 |                                 "Deprecation warning should only exist in UBI8 images");
 48 |         try(GenericContainer container = new GenericContainer(TestSettings.ADMIN_IMAGE_ID))
 49 |         {
 50 |             container.withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 51 |                      .withExposedPorts( 7474, 7687 )
 52 |                      .withLogConsumer( new Slf4jLogConsumer( log ))
 53 |                      .withCommand( "neo4j-admin", "--help" );
 54 |             WaitStrategies.waitUntilContainerFinished( container, Duration.ofSeconds( 30 ));
 55 |             container.start();
 56 |             // container should successfully start
 57 |             String logs = container.getLogs( OutputFrame.OutputType.STDERR );
 58 |             Assertions.assertTrue( logs.contains( DEPRECATION_WARN_STRING ),
 59 |                                    "Container did not warn about ubi8 deprecation. Actual error logs:\n"+logs);
 60 |         }
 61 |     }
 62 | 
 63 |     // this is a requirement for docker official images, so doesn't need testing for neo4j-admin
 64 |     @Test
 65 |     void shouldOnlyWarnWhenRunningNeo4jCommands() throws Exception
 66 |     {
 67 |         Assumptions.assumeTrue( TestSettings.BASE_OS == TestSettings.BaseOS.UBI8,
 68 |                                 "Deprecation warning should only exist in UBI8 images");
 69 |         try(GenericContainer container = new GenericContainer(TestSettings.IMAGE_ID))
 70 |         {
 71 |             container.withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 72 |                      .withExposedPorts( 7474, 7687 )
 73 |                      .withLogConsumer( new Slf4jLogConsumer( log ))
 74 |                      .withCommand( "cat", "/etc/os-release" );
 75 |             WaitStrategies.waitUntilContainerFinished( container, Duration.ofSeconds( 30 ) );
 76 |             container.start();
 77 |             // container should successfully start
 78 |             String logs = container.getLogs( OutputFrame.OutputType.STDERR );
 79 |             Assertions.assertFalse( logs.contains( DEPRECATION_WARN_STRING ),
 80 |                                    "Container should not have warned about ubi8 deprecation. Actual error logs:\n"+logs);
 81 |         }
 82 |     }
 83 | 
 84 |     @Test
 85 |     void shouldIgnoreDeprecationSuppression_coreDB() throws Exception
 86 |     {
 87 |         Assumptions.assumeTrue( TestSettings.BASE_OS == TestSettings.BaseOS.UBI8,
 88 |                                 "Deprecation warning should only exist in UBI8 images");
 89 |         try(GenericContainer container = new GenericContainer(TestSettings.IMAGE_ID))
 90 |         {
 91 |             container.withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 92 |                      .withEnv( DEPRECATION_WARN_SUPPRESS_FLAG, "suppress" )
 93 |                      .withExposedPorts( 7474, 7687 )
 94 |                      .withLogConsumer( new Slf4jLogConsumer( log ))
 95 |                      .waitingFor( WaitStrategies.waitForBoltReady() );
 96 |             container.start();
 97 |             // container should successfully start
 98 |             String logs = container.getLogs( OutputFrame.OutputType.STDERR );
 99 |             Assertions.assertTrue( logs.contains( DEPRECATION_WARN_STRING ),
100 |                     "Container did not warn about ubi8 deprecation. Actual error logs:\n"+logs);
101 |         }
102 |     }
103 | 
104 |     @Test
105 |     void shouldIgnoreDeprecationSuppressed_admin()
106 |     {
107 |         Assumptions.assumeTrue( TestSettings.BASE_OS == TestSettings.BaseOS.UBI8,
108 |                                 "Deprecation warning should only exist in UBI8 images");
109 |         try(GenericContainer container = new GenericContainer(TestSettings.ADMIN_IMAGE_ID))
110 |         {
111 |             container.withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
112 |                      .withEnv( DEPRECATION_WARN_SUPPRESS_FLAG, "suppress" )
113 |                      .withExposedPorts( 7474, 7687 )
114 |                      .withLogConsumer( new Slf4jLogConsumer( log ))
115 |                      .withCommand( "neo4j-admin", "--help" );
116 |             WaitStrategies.waitUntilContainerFinished( container, Duration.ofSeconds( 30 ));
117 |             container.start();
118 |             // container should successfully start
119 |             String logs = container.getLogs( OutputFrame.OutputType.STDERR );
120 |             Assertions.assertTrue( logs.contains( DEPRECATION_WARN_STRING ),
121 |                     "Container did not warn about ubi8 deprecation. Actual error logs:\n"+logs);
122 |         }
123 |     }
124 | }
125 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/neo4jadmin/TestBackupRestore44.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker.neo4jadmin;
  2 | 
  3 | import com.neo4j.docker.coredb.configurations.Configuration;
  4 | import com.neo4j.docker.coredb.configurations.Setting;
  5 | import com.neo4j.docker.utils.DatabaseIO;
  6 | import com.neo4j.docker.utils.Neo4jVersion;
  7 | import com.neo4j.docker.utils.SetContainerUser;
  8 | import com.neo4j.docker.utils.WaitStrategies;
  9 | import com.neo4j.docker.utils.TemporaryFolderManager;
 10 | import com.neo4j.docker.utils.TestSettings;
 11 | import org.junit.jupiter.api.Assertions;
 12 | import org.junit.jupiter.api.Assumptions;
 13 | import org.junit.jupiter.api.BeforeAll;
 14 | import org.junit.jupiter.api.Test;
 15 | import org.junit.jupiter.api.extension.RegisterExtension;
 16 | import org.slf4j.Logger;
 17 | import org.slf4j.LoggerFactory;
 18 | import org.testcontainers.containers.GenericContainer;
 19 | import org.testcontainers.containers.output.Slf4jLogConsumer;
 20 | import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
 21 | 
 22 | import java.nio.file.Path;
 23 | import java.time.Duration;
 24 | import java.util.Map;
 25 | 
 26 | public class TestBackupRestore44
 27 | {
 28 |     // with authentication
 29 |     // with non-default user
 30 |     private final Logger log = LoggerFactory.getLogger( TestBackupRestore44.class );
 31 |     @RegisterExtension
 32 |     public static TemporaryFolderManager temporaryFolderManager = new TemporaryFolderManager();
 33 | 
 34 |     @BeforeAll
 35 |     static void beforeAll()
 36 |     {
 37 |         Assumptions.assumeTrue( TestSettings.NEO4J_VERSION.isAtLeastVersion( Neo4jVersion.NEO4J_VERSION_440),
 38 |                                 "Neo4j admin image not available before 4.4.0");
 39 |         Assumptions.assumeTrue( TestSettings.NEO4J_VERSION.isOlderThan( Neo4jVersion.NEO4J_VERSION_500 ),
 40 |                                 "These Neo4j admin tests are only for 4.4");
 41 |         Assumptions.assumeTrue( TestSettings.EDITION == TestSettings.Edition.ENTERPRISE,
 42 |                                 "backup and restore only available in Neo4j Enterprise" );
 43 |     }
 44 | 
 45 |     private GenericContainer createDBContainer( boolean asDefaultUser, String password )
 46 |     {
 47 |         String auth = "none";
 48 |         if(!password.equalsIgnoreCase("none"))
 49 |         {
 50 |             auth = "neo4j/"+password;
 51 |         }
 52 |         Map<Setting,Configuration> confNames = Configuration.getConfigurationNameMap();
 53 |         GenericContainer container = new GenericContainer( TestSettings.IMAGE_ID );
 54 |         container.withEnv( "NEO4J_AUTH", auth )
 55 |                  .withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 56 |                  .withEnv( confNames.get( Setting.BACKUP_ENABLED ).envName, "true" )
 57 |                  .withEnv( confNames.get( Setting.BACKUP_LISTEN_ADDRESS ).envName, "0.0.0.0:6362" )
 58 |                  .withExposedPorts( 7474, 7687, 6362 )
 59 |                  .withLogConsumer( new Slf4jLogConsumer( log ) )
 60 |                  .waitingFor(WaitStrategies.waitForNeo4jReady( password ));
 61 |         if(!asDefaultUser)
 62 |         {
 63 |             SetContainerUser.nonRootUser( container );
 64 |         }
 65 |         return container;
 66 |     }
 67 | 
 68 |     private GenericContainer createAdminContainer( boolean asDefaultUser )
 69 |     {
 70 |         GenericContainer container = new GenericContainer( TestSettings.ADMIN_IMAGE_ID );
 71 |         container.withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 72 |                  .withLogConsumer( new Slf4jLogConsumer( log ) );
 73 |         WaitStrategies.waitUntilContainerFinished( container, Duration.ofSeconds( 180) );
 74 |         if(!asDefaultUser)
 75 |         {
 76 |             SetContainerUser.nonRootUser( container );
 77 |         }
 78 |         return container;
 79 |     }
 80 | 
 81 |     @Test
 82 |     void shouldBackupAndRestore_defaultUser_noAuth() throws Exception
 83 |     {
 84 |         testCanBackupAndRestore( true, "none" );
 85 |     }
 86 |     @Test
 87 |     void shouldBackupAndRestore_nonDefaultUser_noAuth() throws Exception
 88 |     {
 89 |         testCanBackupAndRestore( false, "none" );
 90 |     }
 91 |     @Test
 92 |     void shouldBackupAndRestore_defaultUser_withAuth() throws Exception
 93 |     {
 94 |         testCanBackupAndRestore( true, "secretpassword" );
 95 |     }
 96 |     @Test
 97 |     void shouldBackupAndRestore_nonDefaultUser_withAuth() throws Exception
 98 |     {
 99 |         testCanBackupAndRestore( false, "secretpassword" );
100 |     }
101 | 
102 |     private void testCanBackupAndRestore(boolean asDefaultUser, String password) throws Exception
103 |     {
104 |         final String dbUser = "neo4j";
105 | 
106 |         // BACKUP
107 |         // start a database and populate data
108 |         GenericContainer neo4j = createDBContainer( asDefaultUser, password );
109 |         Path dataDir = temporaryFolderManager.createFolderAndMountAsVolume(neo4j, "/data");
110 |         neo4j.start();
111 |         DatabaseIO dbio = new DatabaseIO( neo4j );
112 |         dbio.putInitialDataIntoContainer( dbUser, password );
113 |         dbio.verifyInitialDataInContainer( dbUser, password );
114 | 
115 |         // start admin container to initiate backup
116 |         String neoDBAddress = neo4j.getHost()+":"+neo4j.getMappedPort( 6362 );
117 |         GenericContainer adminBackup = createAdminContainer( asDefaultUser )
118 |                 .withNetworkMode( "host" )
119 |                 .waitingFor( new LogMessageWaitStrategy().withRegEx( "^Backup complete successful.*" ) )
120 |                 .withCommand( "neo4j-admin", "backup", "--database=neo4j", "--backup-dir=/backups", "--from="+neoDBAddress);
121 | 
122 |         Path backupDir = temporaryFolderManager.createFolderAndMountAsVolume(adminBackup, "/backups");
123 |         adminBackup.start();
124 | 
125 |         Assertions.assertTrue( neo4j.isRunning(), "neo4j container should still be running" );
126 |         dbio.verifyInitialDataInContainer( dbUser, password );
127 |         adminBackup.stop();
128 | 
129 |         // RESTORE
130 | 
131 |         // write more stuff
132 |         dbio.putMoreDataIntoContainer( dbUser, password );
133 |         dbio.verifyMoreDataIntoContainer( dbUser, password, true );
134 | 
135 |         // do restore
136 |         dbio.runCypherQuery( dbUser, password, "STOP DATABASE neo4j", "system" );
137 |         GenericContainer adminRestore = createAdminContainer( asDefaultUser )
138 |                 .waitingFor( new LogMessageWaitStrategy().withRegEx( "^.*restoreStatus=successful.*" ) )
139 |                 .withCommand( "neo4j-admin", "restore", "--database=neo4j", "--from=/backups/neo4j", "--force");
140 |         temporaryFolderManager.mountHostFolderAsVolume( adminRestore, backupDir, "/backups" );
141 |         temporaryFolderManager.mountHostFolderAsVolume( adminRestore, dataDir, "/data" );
142 |         adminRestore.start();
143 |         dbio.runCypherQuery( dbUser, password, "START DATABASE neo4j", "system" );
144 | 
145 |         // verify new stuff is missing
146 |         dbio.verifyMoreDataIntoContainer( dbUser, password, false );
147 | 
148 |         // clean up
149 |         adminRestore.stop();
150 |         neo4j.stop();
151 |     }
152 | }
153 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/utils/DatabaseIO.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker.utils;
  2 | 
  3 | import com.neo4j.docker.coredb.configurations.Configuration;
  4 | import org.junit.jupiter.api.Assertions;
  5 | import org.neo4j.driver.AuthToken;
  6 | import org.neo4j.driver.AuthTokens;
  7 | import org.neo4j.driver.Config;
  8 | import org.neo4j.driver.Driver;
  9 | import org.neo4j.driver.GraphDatabase;
 10 | import org.neo4j.driver.Record;
 11 | import org.neo4j.driver.Result;
 12 | import org.neo4j.driver.Session;
 13 | import org.neo4j.driver.SessionConfig;
 14 | import org.slf4j.Logger;
 15 | import org.slf4j.LoggerFactory;
 16 | import org.testcontainers.containers.GenericContainer;
 17 | 
 18 | import java.util.List;
 19 | import java.util.stream.Collectors;
 20 | 
 21 | public class DatabaseIO
 22 | {
 23 | 	private static final Config DEFAULT_DRIVER_CONFIG = Config.builder().withoutEncryption().build();
 24 | 	private final Logger log = LoggerFactory.getLogger( DatabaseIO.class );
 25 | 
 26 | 	private GenericContainer container;
 27 | 	private String boltUri;
 28 | 
 29 | 	public DatabaseIO( GenericContainer container )
 30 | 	{
 31 | 		this.container = container;
 32 |         this.boltUri = "bolt://"+container.getHost()+":"+container.getMappedPort( 7687 );
 33 | 	}
 34 | 
 35 |     public DatabaseIO( String host, Integer boltPort )
 36 |     {
 37 |         this.boltUri = "bolt://" + host + ":" + boltPort;
 38 |     }
 39 | 
 40 | 	public void putInitialDataIntoContainer( String user, String password )
 41 | 	{
 42 | 		log.info( "Writing data into database" );
 43 |         List<Record> result = runCypherQuery( user, password,"CREATE (arne:dog {name:'Arne'})-[:SNIFFS]->(bosse:dog {name:'Bosse'}) RETURN arne.name" );
 44 |         Assertions.assertEquals( "Arne", result.get( 0 ).get( "arne.name" ).asString(), "did not receive expected result from cypher CREATE query" );
 45 | 	}
 46 | 
 47 | 	public void verifyInitialDataInContainer( String user, String password )
 48 | 	{
 49 | 		log.info( "verifying data is present in the database" );		
 50 | 		List<Record> result = runCypherQuery( user, password,"MATCH (a:dog)-[:SNIFFS]->(b:dog) RETURN a.name");
 51 |         Assertions.assertEquals( "Arne", result.get( 0 ).get("a.name").asString(), "did not receive expected result from cypher MATCH query" );
 52 | 	}
 53 | 
 54 | 	public void putMoreDataIntoContainer( String user, String password )
 55 | 	{
 56 | 		log.info( "Writing more data into database" );
 57 |         List<Record> result = runCypherQuery( user, password,
 58 |                       "MATCH (a:dog {name:'Arne'}) CREATE (armstrong:dog {name:'Armstrong'})-[:SNIFFS]->(a) return a.name, armstrong.name" );
 59 |         Assertions.assertEquals( "Arne", result.get( 0 ).get("a.name").asString(),
 60 |                                  "did not receive expected result from cypher MATCH query" );
 61 |         Assertions.assertEquals( "Armstrong", result.get( 0 ).get( "armstrong.name" ).asString(),
 62 |                                  "did not receive expected result from cypher CREATE query" );
 63 | 	}
 64 | 
 65 | 	public void verifyMoreDataIntoContainer( String user, String password, boolean extraDataShouldBeThere )
 66 | 	{
 67 | 		log.info( "Verifying extra data is {}in database", extraDataShouldBeThere? "":"not " );
 68 | 		List<Record> result = runCypherQuery( user, password,"MATCH (a:dog)-[:SNIFFS]->(b:dog) RETURN a.name");
 69 | 		String dogs = result.stream()
 70 |                             .map( record -> record.get( 0 ).asString() )
 71 |                             .sorted()
 72 |                             .collect( Collectors.joining(","));
 73 | 		// dogs should now be a String which is a comma delimited list of dog names
 74 | 
 75 | 		if(extraDataShouldBeThere)
 76 |         {
 77 |             Assertions.assertEquals( "Armstrong,Arne", dogs, "cypher query did not return correct data" );
 78 |         }
 79 | 		else
 80 |         {
 81 |             Assertions.assertEquals( "Arne", dogs, "cypher query did not return correct data" );
 82 |         }
 83 | 	}
 84 | 
 85 |     public String getConfigurationSettingAsString( String user, String password, Configuration conf)
 86 |     {
 87 |         List<Record> confRecord = runCypherQuery( user, password,
 88 |                                                   "CALL dbms.listConfig() YIELD name, value " +
 89 |                                                   "WHERE name='" + conf.name + "' " +
 90 |                                                   "RETURN value" );
 91 |         Assertions.assertEquals(1, confRecord.size(), "Configuration "+conf.name+" was not set." );
 92 |         return confRecord.get( 0 ).get( 0 ).asString();
 93 |     }
 94 | 
 95 |     public void verifyConfigurationSetting( String user, String password, Configuration conf, String expectedValue)
 96 |     {
 97 |         verifyConfigurationSetting(user, password, conf, expectedValue, "");
 98 |     }
 99 | 
100 |     public void verifyConfigurationSetting( String user, String password, Configuration conf, String expectedValue, String extraFailureMsg)
101 |     {
102 |         String actualConf = getConfigurationSettingAsString( user, password, conf );
103 |         Assertions.assertEquals(expectedValue, actualConf,
104 |                                 String.format("Expected %s to be %s but it was %s.%s",
105 |                                               conf.name, expectedValue, actualConf, extraFailureMsg));
106 |     }
107 | 
108 | 	public void changePassword(String user, String oldPassword, String newPassword)
109 | 	{
110 | 		if(TestSettings.NEO4J_VERSION.isAtLeastVersion( Neo4jVersion.NEO4J_VERSION_400 ))
111 | 		{
112 | 		    String cypher = "ALTER CURRENT USER SET PASSWORD FROM '"+oldPassword+"' TO '"+newPassword+"'";
113 | 		    runCypherQuery( user, oldPassword, cypher, "system" );
114 | 		}
115 | 		else
116 | 		{
117 | 		    runCypherQuery( user, oldPassword, "CALL dbms.changePassword('"+newPassword+"')" );
118 | 		}
119 | 	}
120 | 
121 | 	public List<Record> runCypherQuery( String user, String password, String cypher)
122 |     {
123 |         // we don't just do runCypherQuery( user, password, cypher, "neo4j")
124 |         // because it breaks the upgrade tests from 3.5.x
125 |         List<Record> records;
126 | 		Driver driver = GraphDatabase.driver( boltUri, getToken( user, password ), DEFAULT_DRIVER_CONFIG);
127 | 		try ( Session session = driver.session())
128 | 		{
129 | 			Result rs = session.run( cypher );
130 | 			records = rs.list();
131 | 		}
132 | 		driver.close();
133 | 		return records;
134 |     }
135 | 
136 | 	public List<Record> runCypherQuery( String user, String password, String cypher, String database)
137 |     {
138 |         List<Record> records;
139 | 		Driver driver = GraphDatabase.driver( boltUri, getToken( user, password ), DEFAULT_DRIVER_CONFIG);
140 | 		try ( Session session = driver.session(SessionConfig.forDatabase( database )))
141 | 		{
142 | 			Result rs = session.run( cypher );
143 | 			records = rs.list();
144 | 		}
145 | 		driver.close();
146 | 		return records;
147 |     }
148 | 
149 | 	public void verifyConnectivity( String user, String password )
150 | 	{
151 | 		GraphDatabase.driver( boltUri,
152 | 							  getToken( user, password ),
153 | 						DEFAULT_DRIVER_CONFIG)
154 | 					 .verifyConnectivity();
155 | 	}
156 | 
157 | 	private AuthToken getToken(String user, String password)
158 | 	{
159 | 		if(password.equals( "none" ))
160 | 		{
161 | 			return AuthTokens.none();
162 | 		}
163 | 		else
164 | 		{
165 | 			return AuthTokens.basic( user, password );
166 | 		}
167 | 	}
168 | }
169 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/coredb/configurations/TestJVMAdditionalConfig.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker.coredb.configurations;
  2 | 
  3 | import com.neo4j.docker.utils.DatabaseIO;
  4 | import com.neo4j.docker.utils.Neo4jVersion;
  5 | import com.neo4j.docker.utils.SetContainerUser;
  6 | import com.neo4j.docker.utils.TemporaryFolderManager;
  7 | import com.neo4j.docker.utils.TestSettings;
  8 | import com.neo4j.docker.utils.WaitStrategies;
  9 | import org.junit.jupiter.api.Assertions;
 10 | import org.junit.jupiter.api.Assumptions;
 11 | import org.junit.jupiter.api.BeforeAll;
 12 | import org.junit.jupiter.api.Test;
 13 | import org.junit.jupiter.api.extension.RegisterExtension;
 14 | import org.slf4j.Logger;
 15 | import org.slf4j.LoggerFactory;
 16 | import org.testcontainers.containers.GenericContainer;
 17 | import org.testcontainers.containers.output.Slf4jLogConsumer;
 18 | 
 19 | import java.nio.file.Files;
 20 | import java.nio.file.Path;
 21 | 
 22 | public class TestJVMAdditionalConfig
 23 | {
 24 |     private final Logger log = LoggerFactory.getLogger( TestJVMAdditionalConfig.class );
 25 |     private static final String PASSWORD = "SuperSecretPassword";
 26 |     private static final String AUTH = "neo4j/"+PASSWORD ;
 27 |     private static Path confFolder;
 28 |     private static final Configuration JVM_ADDITIONAL_CONFIG = Configuration.getConfigurationNameMap().get( Setting.JVM_ADDITIONAL );
 29 |     private static final String DEFAULT_JVM_CONF = "-XX:+UseG1GC";
 30 | 
 31 |     @RegisterExtension
 32 |     public static TemporaryFolderManager temporaryFolderManager = new TemporaryFolderManager();
 33 | 
 34 |     @BeforeAll
 35 |     static void getVersionSpecificConfigurationSettings()
 36 |     {
 37 |         confFolder = Configuration.getConfigurationResourcesFolder();
 38 |         Assumptions.assumeTrue( TestSettings.NEO4J_VERSION.isAtLeastVersion( Neo4jVersion.NEO4J_VERSION_440 ),
 39 |                                 "JVM Additional tests not applicable before 4.4.0");
 40 |     }
 41 | 
 42 |     private GenericContainer createContainer()
 43 |     {
 44 |         return new GenericContainer(TestSettings.IMAGE_ID)
 45 |                 .withEnv("NEO4J_AUTH", AUTH)
 46 |                 .withEnv("NEO4J_DEBUG", AUTH)
 47 |                 .withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes")
 48 |                 .withExposedPorts(7474, 7687)
 49 |                 .withLogConsumer(new Slf4jLogConsumer( log))
 50 |                 .waitingFor(WaitStrategies.waitForNeo4jReady(PASSWORD));
 51 |     }
 52 | 
 53 |     @Test
 54 |     void testJvmAdditionalNotOverridden_noEnv() throws Exception
 55 |     {
 56 |         String expectedJvmAdditional = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005";
 57 |         testJvmAdditionalNotOverridden(expectedJvmAdditional, "" );
 58 |     }
 59 | 
 60 |     @Test
 61 |     void testJvmAdditionalNotOverridden_withEnv() throws Exception
 62 |     {
 63 |         String jvmAdditionalFromEnv = "-XX:+HeapDumpOnOutOfMemoryError";
 64 |         String expectedJvmAdditional = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005\n"+jvmAdditionalFromEnv;
 65 |         testJvmAdditionalNotOverridden(expectedJvmAdditional, jvmAdditionalFromEnv );
 66 |     }
 67 | 
 68 |     void testJvmAdditionalNotOverridden( String expectedJvmAdditional, String jvmAdditionalEnv ) throws Exception
 69 |     {
 70 |         try( GenericContainer container = createContainer())
 71 |         {
 72 |             //Mount /conf
 73 |             Path confMount = temporaryFolderManager.createFolderAndMountAsVolume(container, "/conf");
 74 |             SetContainerUser.nonRootUser( container );
 75 |             container.withEnv( JVM_ADDITIONAL_CONFIG.envName, jvmAdditionalEnv );
 76 |             //Create JvmAdditionalNotOverridden.conf file
 77 |             Path confFile = confFolder.resolve( "JvmAdditionalNotOverridden.conf" );
 78 |             Files.copy( confFile, confMount.resolve( "neo4j.conf" ) );
 79 |             //Start the container
 80 |             container.start();
 81 |             // verify setting correctly loaded into neo4j
 82 |             DatabaseIO dbio = new DatabaseIO( container );
 83 |             dbio.verifyConfigurationSetting( "neo4j", PASSWORD, JVM_ADDITIONAL_CONFIG, expectedJvmAdditional);
 84 |         }
 85 |     }
 86 | 
 87 |     @Test
 88 |     void testJVMAdditionalDefaultsNotOverwrittenByEnv() throws Exception
 89 |     {
 90 |         String expectedJvmAdditional = "-XX:+HeapDumpOnOutOfMemoryError";
 91 |         try( GenericContainer container = createContainer())
 92 |         {
 93 |             container.withEnv( JVM_ADDITIONAL_CONFIG.envName, expectedJvmAdditional );
 94 |             verifyJvmAdditional( container, expectedJvmAdditional, DEFAULT_JVM_CONF );
 95 |         }
 96 |     }
 97 | 
 98 |     @Test
 99 |     void testSpecialCharInJvmAdditional_space_conf() throws Exception
100 |     {
101 |         testJvmAdditionalSpecialCharacters_conf("space", "-XX:OnOutOfMemoryError=\"/usr/bin/echo oh no oom\"");
102 |     }
103 | 
104 |     @Test
105 |     void testSpecialCharInJvmAdditional_space_env() throws Exception
106 |     {
107 |         testJvmAdditionalSpecialCharacters_env( "-XX:OnOutOfMemoryError=\"/usr/bin/echo oh no oom\"");
108 |     }
109 | 
110 |     @Test
111 |     void testSpecialCharInJvmAdditional_dollar_conf() throws Exception
112 |     {
113 |         testJvmAdditionalSpecialCharacters_conf("dollar",
114 |                                                 "-Dnot.a.real.parameter=\"beepbeep$boop1boop2\"" );
115 |     }
116 | 
117 |     @Test
118 |     void testSpecialCharInJvmAdditional_dollar_env() throws Exception {
119 |         testJvmAdditionalSpecialCharacters_env( "-Dnot.a.real.parameter=\"bleepblorp$bleep1blorp4\"");
120 |     }
121 | 
122 |     void testJvmAdditionalSpecialCharacters_conf(String charName, String expectedJvmAdditional) throws Exception
123 |     {
124 |         try(GenericContainer container = createContainer())
125 |         {
126 |             //Mount /conf
127 |             Path confMount = temporaryFolderManager.createFolderAndMountAsVolume(container, "/conf");
128 |             //copy test conf file
129 |             String confContent = JVM_ADDITIONAL_CONFIG.name + "=" + expectedJvmAdditional;
130 |             Files.write( confMount.resolve( "neo4j.conf" ), confContent.getBytes() );
131 |             //Start the container
132 |             verifyJvmAdditional( container, expectedJvmAdditional );
133 |         }
134 |     }
135 | 
136 |     void testJvmAdditionalSpecialCharacters_env( String expectedJvmAdditional ) throws Exception
137 |     {
138 |         try(GenericContainer container = createContainer())
139 |         {
140 |             container.withEnv( JVM_ADDITIONAL_CONFIG.envName, expectedJvmAdditional);
141 |             verifyJvmAdditional( container, expectedJvmAdditional, DEFAULT_JVM_CONF );
142 |         }
143 |     }
144 | 
145 |     void verifyJvmAdditional( GenericContainer container, String... expectedValues )
146 |     {
147 |         SetContainerUser.nonRootUser( container );
148 |         //Start the container
149 |         container.start();
150 |         // verify setting correctly loaded into neo4j
151 |         DatabaseIO dbio = new DatabaseIO( container );
152 |         String actualConfValue = dbio.getConfigurationSettingAsString( "neo4j", PASSWORD, JVM_ADDITIONAL_CONFIG );
153 |         
154 |         for(String expectedJvmAdditional : expectedValues)
155 |         {
156 |             Assertions.assertTrue( actualConfValue.contains( expectedJvmAdditional ) );
157 |         }
158 |     }
159 | }
160 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/coredb/plugins/StubPluginHelper.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker.coredb.plugins;
  2 | 
  3 | import com.google.gson.Gson;
  4 | import com.neo4j.docker.utils.DatabaseIO;
  5 | import com.neo4j.docker.utils.HostFileHttpHandler;
  6 | import com.neo4j.docker.utils.HttpServerTestExtension;
  7 | import com.neo4j.docker.utils.Neo4jVersion;
  8 | import org.junit.jupiter.api.Assertions;
  9 | import org.neo4j.driver.Record;
 10 | 
 11 | import java.io.File;
 12 | import java.io.IOException;
 13 | import java.net.URISyntaxException;
 14 | import java.nio.file.Path;
 15 | import java.util.Collections;
 16 | import java.util.List;
 17 | import java.util.Map;
 18 | import java.util.stream.Collectors;
 19 | 
 20 | import static com.neo4j.docker.utils.TestSettings.NEO4J_VERSION;
 21 | 
 22 | public class StubPluginHelper
 23 | {
 24 |     public static final String PLUGIN_FILENAME = "myPlugin.jar";
 25 |     public static final String PLUGIN_ENV_NAME = "_testing";
 26 |     private final HttpServerTestExtension httpServer;
 27 | 
 28 |     /**Data class for each <code>versions.json</code> entry so that the GSON tool can convert it to json.
 29 |      * */
 30 |     private class VersionsJsonEntry
 31 |     {
 32 |         String neo4j;
 33 |         String jar;
 34 |         String _testing;
 35 | 
 36 |         VersionsJsonEntry( String neo4j, String jar )
 37 |         {
 38 |             this.neo4j = neo4j;
 39 |             this._testing = "SNAPSHOT";
 40 |             this.jar = "http://host.testcontainers.internal:3000/" + jar;
 41 |         }
 42 |     }
 43 | 
 44 |     /**Does (most of) the complicated setup required to create a fake neo4j plugin and make it accessible inside the container.
 45 |      * @param httpServer a {@link HttpServerTestExtension} object.
 46 |      *                  It must have ALREADY been registered as a JUnit5 extension with {@link org.junit.jupiter.api.extension.RegisterExtension}
 47 |      * */
 48 |     public StubPluginHelper(HttpServerTestExtension httpServer)
 49 |     {
 50 |         this.httpServer = httpServer;
 51 |     }
 52 | 
 53 |     /**Creates a versions.json in the destination folder mapping between the given neo4j versions and jar filenames.
 54 |      * This is currently used to map between neo4j versions and jars that don't exist (for semver match testing).
 55 |      * @param destinationFolder folder to save versions.json to.
 56 |      * @param version a neo4j version, to map to the real testing jar.
 57 |      * @return File object of the versions.json file created.
 58 |      * */
 59 |     public File createStubPluginForVersion(Path destinationFolder, Neo4jVersion version) throws IOException
 60 |     {
 61 |         return createStubPluginsForVersionMapping(destinationFolder, Collections.singletonMap(version.toString(), PLUGIN_FILENAME));
 62 |     }
 63 | 
 64 |     /**Creates a versions.json in the destination folder mapping between the given neo4j versions and jar filenames.
 65 |      * This is currently used to map between neo4j versions and jars that don't exist (for semver match testing).
 66 |      * @param destinationFolder folder to save versions.json to.
 67 |      * @param version a neo4j version, as a string, to map to the real testing jar.
 68 |      * @return File object of the versions.json file created.
 69 |      * */
 70 |     public File createStubPluginForVersion(Path destinationFolder, String version) throws IOException
 71 |     {
 72 |         return createStubPluginsForVersionMapping(destinationFolder, Collections.singletonMap(version, PLUGIN_FILENAME));
 73 |     }
 74 | 
 75 |     /**Creates a versions.json in the destination folder mapping between the given neo4j versions and jar filenames.
 76 |      * This is currently used to map between neo4j versions and jars that don't exist (for semver match testing).
 77 |      * @param destinationFolder folder to save versions.json to.
 78 |      * @param versionAndJar map of neo4j version, as a string, to jar name. For example:
 79 |      *                      4.4.10 -> myPlugin.jar
 80 |      *                      4.4.*  -> pluginThatDoesNotExist.jar
 81 |      *                      5.0.x  -> anotherNonexistantPlugin.jar
 82 |      * @return File object of the versions.json file created.
 83 |      * */
 84 |     public File createStubPluginsForVersionMapping(Path destinationFolder, Map<String,String> versionAndJar ) throws IOException
 85 |     {
 86 |         File versionsJson = createVersionsJson(destinationFolder, versionAndJar);
 87 |         try {
 88 |             File myPluginJar = new File(getClass().getClassLoader().getResource("stubplugin/" + PLUGIN_FILENAME).toURI());
 89 | 
 90 |             httpServer.registerHandler(versionsJson.getName(), new HostFileHttpHandler(versionsJson, "application/json"));
 91 |             httpServer.registerHandler(PLUGIN_FILENAME, new HostFileHttpHandler(myPluginJar, "application/java-archive"));
 92 |         }
 93 |         catch (URISyntaxException e)
 94 |         {
 95 |             throw new IOException("Could not load test plugin from test resources file", e);
 96 |         }
 97 |         return versionsJson;
 98 |     }
 99 | 
100 |     private File createVersionsJson(Path destinationFolder, Map<String, String> versionAndJar) throws IOException
101 |     {
102 |         List<VersionsJsonEntry> jsonEntries = versionAndJar.keySet()
103 |                 .stream()
104 |                 .map(key -> new VersionsJsonEntry(key, versionAndJar.get(key)))
105 |                 .collect(Collectors.toList());
106 |         Gson jsonBuilder = new Gson();
107 |         String jsonStr = jsonBuilder.toJson(jsonEntries);
108 | 
109 |         File outputJsonFile = destinationFolder.resolve("versions.json").toFile();
110 |         java.nio.file.Files.writeString(outputJsonFile.toPath(), jsonStr);
111 |         return outputJsonFile;
112 |     }
113 | 
114 |     public void verifyStubPluginLoaded(DatabaseIO db, String user, String password )
115 |     {
116 |         // when we check the list of installed procedures...
117 |         String listProceduresCypherQuery = NEO4J_VERSION.isAtLeastVersion( new Neo4jVersion( 4, 3, 0 ) ) ?
118 |                                            "SHOW PROCEDURES YIELD name, signature RETURN name, signature" :
119 |                                            "CALL dbms.procedures() YIELD name, signature RETURN name, signature";
120 |         List<Record> procedures = db.runCypherQuery( user, password, listProceduresCypherQuery );
121 |         // Then the procedure from the test plugin should be listed
122 |         Assertions.assertTrue( procedures.stream()
123 |                                          .anyMatch( x -> x.get( "name" ).asString()
124 |                                                           .equals( "com.neo4j.docker.test.myplugin.defaultValues" ) ),
125 |                                "Missing procedure provided by our plugin" );
126 | 
127 |         // When we call the procedure from the plugin
128 |         List<Record> pluginResponse = db.runCypherQuery( user, password,
129 |                                                          "CALL com.neo4j.docker.test.myplugin.defaultValues" );
130 | 
131 |         // Then we get the response we expect
132 |         Assertions.assertEquals( 1, pluginResponse.size(), "Our procedure should only return a single result" );
133 |         Record record = pluginResponse.get( 0 );
134 | 
135 |         String message = "Result from calling our procedure doesnt match our expectations";
136 |         Assertions.assertEquals( "a string", record.get( "string" ).asString(), message );
137 |         Assertions.assertEquals( 42L, record.get( "integer" ).asInt(), message );
138 |         Assertions.assertEquals( 3.14d, record.get( "aFloat" ).asDouble(), 0.000001, message );
139 |         Assertions.assertTrue(record.get("aBoolean").asBoolean(), message);
140 |     }
141 | }
142 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/neo4jadmin/TestDumpLoad44.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker.neo4jadmin;
  2 | 
  3 | import com.github.dockerjava.api.command.CreateContainerCmd;
  4 | import com.neo4j.docker.utils.DatabaseIO;
  5 | import com.neo4j.docker.utils.Neo4jVersion;
  6 | import com.neo4j.docker.utils.SetContainerUser;
  7 | import com.neo4j.docker.utils.WaitStrategies;
  8 | import com.neo4j.docker.utils.TemporaryFolderManager;
  9 | import com.neo4j.docker.utils.TestSettings;
 10 | import org.junit.jupiter.api.Assertions;
 11 | import org.junit.jupiter.api.Assumptions;
 12 | import org.junit.jupiter.api.BeforeAll;
 13 | import org.junit.jupiter.api.Test;
 14 | import org.junit.jupiter.api.extension.RegisterExtension;
 15 | import org.slf4j.Logger;
 16 | import org.slf4j.LoggerFactory;
 17 | import org.testcontainers.containers.GenericContainer;
 18 | import org.testcontainers.containers.output.Slf4jLogConsumer;
 19 | import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy;
 20 | import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
 21 | 
 22 | import java.nio.file.Path;
 23 | import java.time.Duration;
 24 | import java.util.function.Consumer;
 25 | 
 26 | public class TestDumpLoad44
 27 | {
 28 |     private static Logger log = LoggerFactory.getLogger( TestDumpLoad44.class );
 29 |     @RegisterExtension
 30 |     public static TemporaryFolderManager temporaryFolderManager = new TemporaryFolderManager();
 31 | 
 32 |     @BeforeAll
 33 |     static void beforeAll()
 34 |     {
 35 |         Assumptions.assumeTrue( TestSettings.NEO4J_VERSION.isAtLeastVersion( new Neo4jVersion( 4, 4, 0 )),
 36 |                                 "Neo4j admin image not available before 4.4.0");
 37 |         Assumptions.assumeTrue( TestSettings.NEO4J_VERSION.isOlderThan( Neo4jVersion.NEO4J_VERSION_500 ),
 38 |                                 "These Neo4j admin tests are only for 4.4");
 39 |     }
 40 | 
 41 |     private GenericContainer createDBContainer( boolean asDefaultUser, String password )
 42 |     {
 43 |         String auth = "none";
 44 |         if(!password.equalsIgnoreCase("none"))
 45 |         {
 46 |             auth = "neo4j/"+password;
 47 |         }
 48 | 
 49 |         GenericContainer container = new GenericContainer( TestSettings.IMAGE_ID );
 50 |         container.withEnv( "NEO4J_AUTH", auth )
 51 |                  .withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 52 |                  .withExposedPorts( 7474, 7687 )
 53 |                  .withLogConsumer( new Slf4jLogConsumer( log ) )
 54 |                  .waitingFor( WaitStrategies.waitForNeo4jReady( password ) )
 55 |                  // the default testcontainer framework behaviour is to just stop the process entirely,
 56 |                  // preventing clean shutdown. This means we can run the stop command and
 57 |                  // it'll send a SIGTERM to initiate neo4j shutdown. See also stopContainer method.
 58 |                  .withCreateContainerCmdModifier(
 59 |                          (Consumer<CreateContainerCmd>) cmd -> cmd.withStopSignal( "SIGTERM" ).withStopTimeout( 20 ));
 60 |         if(!asDefaultUser)
 61 |         {
 62 |             SetContainerUser.nonRootUser( container );
 63 |         }
 64 |         return container;
 65 |     }
 66 | 
 67 |     private GenericContainer createAdminContainer( boolean asDefaultUser )
 68 |     {
 69 |         GenericContainer container = new GenericContainer( TestSettings.ADMIN_IMAGE_ID );
 70 |         container.withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 71 |                  .withExposedPorts( 7474, 7687 )
 72 |                  .withLogConsumer( new Slf4jLogConsumer( log ) )
 73 |                  .waitingFor( new LogMessageWaitStrategy().withRegEx( "^Done: \\d+ files, [\\d\\.,]+[KMGi]*B processed.*" ) )
 74 |                  .withStartupCheckStrategy( new OneShotStartupCheckStrategy().withTimeout( Duration.ofSeconds( 90 ) ) );
 75 |         if(!asDefaultUser)
 76 |         {
 77 |             SetContainerUser.nonRootUser( container );
 78 |         }
 79 |         return container;
 80 |     }
 81 | 
 82 |     @Test
 83 |     void shouldDumpAndLoad_defaultUser_noAuth() throws Exception
 84 |     {
 85 |         shouldCreateDumpAndLoadDump( true, "none" );
 86 |     }
 87 | 
 88 |     @Test
 89 |     void shouldDumpAndLoad_nonDefaultUser_noAuth() throws Exception
 90 |     {
 91 |         shouldCreateDumpAndLoadDump( false, "none" );
 92 |     }
 93 | 
 94 |     @Test
 95 |     void shouldDumpAndLoad_defaultUser_withAuth() throws Exception
 96 |     {
 97 |         shouldCreateDumpAndLoadDump( true, "verysecretpassword" );
 98 |     }
 99 | 
100 |     @Test
101 |     void shouldDumpAndLoad_nonDefaultUser_withAuth() throws Exception
102 |     {
103 |         shouldCreateDumpAndLoadDump( false, "verysecretpassword" );
104 |     }
105 | 
106 |     //container.stop() actually runs the killContainer Command, preventing clean shutdown.
107 |     // This runs the actual stop command. Which we set up in createDBContainer to send SIGTERM
108 |     private void stopContainer(GenericContainer container)
109 |     {
110 |         log.info( "issuing container stop command" );
111 |         container.getDockerClient().stopContainerCmd( container.getContainerId() ).exec();
112 |         log.info( "Container stopped" );
113 |     }
114 | 
115 |     private void shouldCreateDumpAndLoadDump( boolean asDefaultUser, String password ) throws Exception
116 |     {
117 |         Path firstDataDir;
118 |         Path secondDataDir;
119 |         Path backupDir;
120 | 
121 |         // start a database and populate it
122 |         try(GenericContainer container = createDBContainer( asDefaultUser, password ))
123 |         {
124 |             firstDataDir = temporaryFolderManager.createNamedFolderAndMountAsVolume( container,
125 |                                                                                      "data1",
126 |                                                                                      "/data" );
127 |             container.start();
128 |             DatabaseIO dbio = new DatabaseIO( container );
129 |             dbio.putInitialDataIntoContainer( "neo4j", password );
130 |             stopContainer( container );
131 |         }
132 | 
133 |         // use admin container to create dump
134 |         try(GenericContainer admin = createAdminContainer( asDefaultUser ))
135 |         {
136 |             temporaryFolderManager.mountHostFolderAsVolume( admin, firstDataDir, "/data" );
137 |             backupDir = temporaryFolderManager.createFolderAndMountAsVolume(admin, "/backups");
138 |             admin.withCommand( "neo4j-admin", "dump", "--database=neo4j", "--to=/backups/neo4j.dump" );
139 |             admin.start();
140 |         }
141 |         Assertions.assertTrue( backupDir.resolve( "neo4j.dump" ).toFile().exists(), "dump file not created");
142 | 
143 |         // dump file exists. Now try to load it into a new database.
144 |         // use admin container to create dump
145 |         try(GenericContainer admin = createAdminContainer( asDefaultUser ))
146 |         {
147 |             secondDataDir = temporaryFolderManager.createNamedFolderAndMountAsVolume( admin,
148 |                                                                                      "data2",
149 |                                                                                      "/data" );
150 |             temporaryFolderManager.mountHostFolderAsVolume( admin, backupDir, "/backups" );
151 |             admin.withCommand( "neo4j-admin", "load", "--database=neo4j", "--from=/backups/neo4j.dump" );
152 |             admin.start();
153 |         }
154 | 
155 |         // verify data in 2nd data directory by starting a database and verifying data we populated earlier
156 |         try(GenericContainer container = createDBContainer( asDefaultUser, password ))
157 |         {
158 |             temporaryFolderManager.mountHostFolderAsVolume( container, secondDataDir, "/data" );
159 |             container.start();
160 |             DatabaseIO dbio = new DatabaseIO( container );
161 |             dbio.verifyInitialDataInContainer( "neo4j", password );
162 |         }
163 |     }
164 | }
165 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/build-docker-image.sh:
--------------------------------------------------------------------------------

```bash
  1 | #!/bin/bash
  2 | set -eu -o pipefail
  3 | 
  4 | # SUPPORTED_IMAGE_OS=("debian" "ubi9")
  5 | EDITIONS=("community" "enterprise")
  6 | 
  7 | DISTRIBUTION_SITE="https://dist.neo4j.org"
  8 | ROOT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
  9 | source "$ROOT_DIR/build-utils-common-functions.sh"
 10 | BUILD_DIR=${ROOT_DIR}/build
 11 | SRC_DIR=${ROOT_DIR}/docker-image-src
 12 | # shellcheck disable=SC2034  # Used in docker-common-functions.sh
 13 | TAR_CACHE=${ROOT_DIR}/in
 14 | 
 15 | function usage
 16 | {
 17 |     echo >&2 "USAGE: $0 <version> <edition> <operating system>
 18 |     For example:
 19 |         $0 4.4.10 community debian
 20 |         $0 5.10.0 enterprise ubi9
 21 |     Version and operating system can also be set in the environment.
 22 |     For example:
 23 |         NEO4JVERSION=4.4.10 NEO4JEDITION=community IMAGE_OS=debian $0
 24 |         NEO4JVERSION=5.10.0 NEO4JEDITION=enterprise IMAGE_OS=ubi9 $0
 25 |     "
 26 |     exit 1
 27 | }
 28 | 
 29 | ## ==========================================
 30 | ## get and sanitise script inputs
 31 | 
 32 | if [[ $# -eq 3 ]]; then
 33 |     NEO4JVERSION=${1}
 34 |     NEO4JEDITION=${2}
 35 |     IMAGE_OS=${3}
 36 | elif [[ -z ${NEO4JVERSION:-""} ]]; then
 37 |     echo >&2 "NEO4JVERSION is unset. Either set it in the environment or pass as argument to this script."
 38 |     usage
 39 | elif [[ -z ${NEO4JEDITION:-""} ]]; then
 40 |     echo >&2 "NEO4JEDITION is unset. Either set it in the environment or pass as argument to this script."
 41 |     usage
 42 | elif [[ -z ${IMAGE_OS:-""} ]]; then
 43 |     echo >&2 "IMAGE_OS is unset. Either set it in the environment or pass as argument to this script."
 44 |     usage
 45 | fi
 46 | # verify edition
 47 | if ! contains_element "${NEO4JEDITION}" "${EDITIONS[@]}"; then
 48 |     echo >&2 "${NEO4JEDITION} is not a supported edition."
 49 |     usage
 50 | fi
 51 | # verify compatible neo4j version
 52 | if [[ ! "${NEO4JVERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+.*$  ]]; then
 53 |     echo "\"${NEO4JVERSION}\" is not a valid version number."
 54 |     usage
 55 | fi
 56 | 
 57 | # get source files
 58 | BRANCH=$(get_branch_from_version ${NEO4JVERSION})
 59 | DOCKERFILE_NAME=$(get_compatible_dockerfile_for_os_or_error "${BRANCH}" "${IMAGE_OS}")
 60 | 
 61 | echo "Building docker neo4j-${NEO4JEDITION}-${NEO4JVERSION} image based on ${IMAGE_OS}."
 62 | 
 63 | ## ==================================================================================
 64 | ## get neo4j source tar from distribution site. This is required for release artifacts
 65 | ## so that we can calculate the sha256, and for the local image build.
 66 | 
 67 | echo "Caching neo4j source tarball"
 68 | fetch_tarball "${NEO4JVERSION}" "${NEO4JEDITION}"
 69 | 
 70 | ## ==================================================================================
 71 | ## construct local build context. These are all the files required to build the
 72 | ## neo4j image locally.
 73 | 
 74 | echo "Building local context for docker build"
 75 | COREDB_LOCALCXT_DIR=${BUILD_DIR}/${IMAGE_OS}/coredb/${NEO4JEDITION}
 76 | ADMIN_LOCALCXT_DIR=${BUILD_DIR}/${IMAGE_OS}/neo4j-admin/${NEO4JEDITION}
 77 | mkdir -p ${COREDB_LOCALCXT_DIR}
 78 | mkdir -p ${ADMIN_LOCALCXT_DIR}
 79 | 
 80 | # copy coredb sources
 81 | mkdir -p ${COREDB_LOCALCXT_DIR}/local-package
 82 | cp ${SRC_DIR}/common/* ${COREDB_LOCALCXT_DIR}/local-package
 83 | cp ${SRC_DIR}/${BRANCH}/coredb/*.sh ${COREDB_LOCALCXT_DIR}/local-package
 84 | cp ${SRC_DIR}/${BRANCH}/coredb/*.json ${COREDB_LOCALCXT_DIR}/local-package
 85 | coredb_sha=$(sha256sum "$(cached_tarball "${NEO4JVERSION}" "${NEO4JEDITION}")" | cut -d' ' -f1)
 86 | cp "$(cached_tarball "${NEO4JVERSION}" "${NEO4JEDITION}")" ${COREDB_LOCALCXT_DIR}/local-package/
 87 | 
 88 | # create coredb Dockerfile
 89 | cp "${SRC_DIR}/${BRANCH}/coredb/${DOCKERFILE_NAME}" "${COREDB_LOCALCXT_DIR}/Dockerfile"
 90 | sed -i -e "s|%%NEO4J_SHA%%|${coredb_sha}|" "${COREDB_LOCALCXT_DIR}/Dockerfile"
 91 | sed -i -e "s|%%NEO4J_TARBALL%%|$(tarball_name "${NEO4JVERSION}" "${NEO4JEDITION}")|" "${COREDB_LOCALCXT_DIR}/Dockerfile"
 92 | sed -i -e "s|%%NEO4J_EDITION%%|${NEO4JEDITION}|" "${COREDB_LOCALCXT_DIR}/Dockerfile"
 93 | sed -i -e "s|%%NEO4J_DIST_SITE%%|${DISTRIBUTION_SITE}|" "${COREDB_LOCALCXT_DIR}/Dockerfile"
 94 | 
 95 | # copy neo4j-admin sources
 96 | mkdir -p ${ADMIN_LOCALCXT_DIR}/local-package
 97 | cp ${SRC_DIR}/common/* ${ADMIN_LOCALCXT_DIR}/local-package
 98 | cp "$(cached_tarball "${NEO4JVERSION}" "${NEO4JEDITION}")" ${ADMIN_LOCALCXT_DIR}/local-package/
 99 | cp ${SRC_DIR}/${BRANCH}/neo4j-admin/*.sh ${ADMIN_LOCALCXT_DIR}/local-package
100 | 
101 | # create neo4j-admin Dockerfile
102 | cp "${SRC_DIR}/${BRANCH}/neo4j-admin/${DOCKERFILE_NAME}" "${ADMIN_LOCALCXT_DIR}/Dockerfile"
103 | sed -i -e "s|%%NEO4J_SHA%%|${coredb_sha}|" "${ADMIN_LOCALCXT_DIR}/Dockerfile"
104 | sed -i -e "s|%%NEO4J_TARBALL%%|$(tarball_name ${NEO4JVERSION} ${NEO4JEDITION})|" "${ADMIN_LOCALCXT_DIR}/Dockerfile"
105 | sed -i -e "s|%%NEO4J_EDITION%%|${NEO4JEDITION}|" "${ADMIN_LOCALCXT_DIR}/Dockerfile"
106 | sed -i -e "s|%%NEO4J_DIST_SITE%%|${DISTRIBUTION_SITE}|" "${ADMIN_LOCALCXT_DIR}/Dockerfile"
107 | 
108 | # add deprecation warning if needed
109 | if [ "${IMAGE_OS}" = "ubi8" ]; then
110 |     dep_msg="echo \>\&2 \"\n=======================================================\n
111 | Neo4j Red Hat UBI8 images are deprecated in favour of Red Hat UBI9.\n
112 | Update your codebase to use Neo4j Docker image tags ending with -ubi9 instead of -ubi8.\n\n
113 | This is the last Neo4j image available on Red Hat UBI8.\n
114 | By continuing to use UBI8 tagged Neo4j images you will not get further updates, \n
115 | including new features and security fixes.\n\n
116 | This message can not be suppressed.\n
117 | =======================================================\n\"\n"
118 |     sed -i -e "s/#%%DEPRECATION_WARNING_PLACEHOLDER%%/$(echo ${dep_msg} | sed -z 's/\n/\\n/g')/" "${COREDB_LOCALCXT_DIR}/local-package/docker-entrypoint.sh"
119 |     sed -i -e "s/#%%DEPRECATION_WARNING_PLACEHOLDER%%/$(echo ${dep_msg} | sed -z 's/\n/\\n/g')/" "${ADMIN_LOCALCXT_DIR}/local-package/docker-entrypoint.sh"
120 | else
121 |     sed -i -e '/#%%DEPRECATION_WARNING_PLACEHOLDER%%/d' "${COREDB_LOCALCXT_DIR}/local-package/docker-entrypoint.sh"
122 |     sed -i -e '/#%%DEPRECATION_WARNING_PLACEHOLDER%%/d' "${ADMIN_LOCALCXT_DIR}/local-package/docker-entrypoint.sh"
123 | fi
124 | 
125 | ## ==================================================================================
126 | ## Finally we are ready to do a docker build...
127 | 
128 | # build coredb
129 | coredb_image_tag=neo4jtest:${RANDOM}
130 | echo "Building CoreDB docker image for neo4j-${NEO4JVERSION} ${NEO4JEDITION} on ${IMAGE_OS}."
131 | docker build --tag=${coredb_image_tag} \
132 |     --build-arg="NEO4J_URI=file:///startup/$(tarball_name "${NEO4JVERSION}" "${NEO4JEDITION}")" \
133 |     "${COREDB_LOCALCXT_DIR}"
134 | echo "Tagged CoreDB image ${coredb_image_tag}"
135 | echo -n "${coredb_image_tag}" > ${COREDB_LOCALCXT_DIR}/../.image-id-"${NEO4JEDITION}"
136 | 
137 | # build neo4j-admin
138 | admin_image_tag=neo4jadmintest:${RANDOM}
139 | echo "Building neo4j-admin docker image for neo4j-admin-${NEO4JVERSION} ${NEO4JEDITION} on ${IMAGE_OS}."
140 | docker build --tag=${admin_image_tag} \
141 |     --build-arg="NEO4J_URI=file:///startup/$(tarball_name "${NEO4JVERSION}" "${NEO4JEDITION}")" \
142 |     "${ADMIN_LOCALCXT_DIR}"
143 | echo "Tagged neo4j-admin image ${admin_image_tag}"
144 | echo -n "${admin_image_tag}" > ${ADMIN_LOCALCXT_DIR}/../.image-id-"${NEO4JEDITION}"
145 | 
146 | ## ==================================================================================
147 | # generate env files for local development
148 | {
149 |     echo "NEO4JVERSION=${NEO4JVERSION}"
150 |     echo "NEO4J_IMAGE=$(cat "${COREDB_LOCALCXT_DIR}"/../.image-id-"${NEO4JEDITION}")"
151 |     echo "NEO4JADMIN_IMAGE=$(cat "${ADMIN_LOCALCXT_DIR}"/../.image-id-"${NEO4JEDITION}")"
152 |     echo "NEO4J_EDITION=${NEO4JEDITION}"
153 |     echo "BASE_OS=${IMAGE_OS}"
154 |     echo "NEO4J_SKIP_MOUNTED_FOLDER_TARBALLING=true"
155 | } > ${BUILD_DIR}/${IMAGE_OS}/devenv-"${NEO4JEDITION}".env
156 | ln -f ${BUILD_DIR}/${IMAGE_OS}/devenv-"${NEO4JEDITION}".env ${BUILD_DIR}/devenv-"${NEO4JEDITION}".env
157 | 
158 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/neo4jadmin/TestBackupRestore.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker.neo4jadmin;
  2 | 
  3 | import com.neo4j.docker.coredb.configurations.Configuration;
  4 | import com.neo4j.docker.coredb.configurations.Setting;
  5 | import com.neo4j.docker.utils.DatabaseIO;
  6 | import com.neo4j.docker.utils.Neo4jVersion;
  7 | import com.neo4j.docker.utils.SetContainerUser;
  8 | import com.neo4j.docker.utils.WaitStrategies;
  9 | import com.neo4j.docker.utils.TemporaryFolderManager;
 10 | import com.neo4j.docker.utils.TestSettings;
 11 | import org.junit.jupiter.api.Assertions;
 12 | import org.junit.jupiter.api.Assumptions;
 13 | import org.junit.jupiter.api.BeforeAll;
 14 | import org.junit.jupiter.api.Test;
 15 | import org.junit.jupiter.api.extension.RegisterExtension;
 16 | import org.slf4j.Logger;
 17 | import org.slf4j.LoggerFactory;
 18 | import org.testcontainers.containers.GenericContainer;
 19 | import org.testcontainers.containers.output.Slf4jLogConsumer;
 20 | import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
 21 | import org.testcontainers.containers.wait.strategy.Wait;
 22 | 
 23 | import java.io.File;
 24 | import java.nio.file.Files;
 25 | import java.nio.file.Path;
 26 | import java.time.Duration;
 27 | import java.util.List;
 28 | import java.util.Map;
 29 | 
 30 | public class TestBackupRestore
 31 | {
 32 |     // with authentication
 33 |     // with non-default user
 34 |     private final Logger log = LoggerFactory.getLogger( TestBackupRestore.class );
 35 |     @RegisterExtension
 36 |     public static TemporaryFolderManager temporaryFolderManager = new TemporaryFolderManager();
 37 | 
 38 |     @BeforeAll
 39 |     static void beforeAll()
 40 |     {
 41 |         Assumptions.assumeTrue( TestSettings.NEO4J_VERSION.isAtLeastVersion( Neo4jVersion.NEO4J_VERSION_500 ),
 42 |                                 "These tests only apply to neo4j-admin images of 5.0 and greater");
 43 |         Assumptions.assumeTrue( TestSettings.EDITION == TestSettings.Edition.ENTERPRISE,
 44 |                                 "backup and restore only available in Neo4j Enterprise" );
 45 |     }
 46 | 
 47 |     private GenericContainer createDBContainer( boolean asDefaultUser, String password )
 48 |     {
 49 |         String auth = "none";
 50 |         if(!password.equalsIgnoreCase("none"))
 51 |         {
 52 |             auth = "neo4j/"+password;
 53 |         }
 54 |         Map<Setting,Configuration> confNames = Configuration.getConfigurationNameMap();
 55 |         GenericContainer container = new GenericContainer( TestSettings.IMAGE_ID );
 56 |         container.withEnv( "NEO4J_AUTH", auth )
 57 |                  .withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 58 |                  .withEnv( confNames.get( Setting.BACKUP_ENABLED ).envName, "true" )
 59 |                  .withEnv( confNames.get( Setting.BACKUP_LISTEN_ADDRESS ).envName, "0.0.0.0:6362" )
 60 |                  .withExposedPorts( 7474, 7687, 6362 )
 61 |                  .withLogConsumer( new Slf4jLogConsumer( log ) )
 62 |                  .waitingFor(WaitStrategies.waitForNeo4jReady( password ));
 63 |         if(!asDefaultUser)
 64 |         {
 65 |             SetContainerUser.nonRootUser( container );
 66 |         }
 67 |         return container;
 68 |     }
 69 | 
 70 |     private GenericContainer createAdminContainer( boolean asDefaultUser )
 71 |     {
 72 |         GenericContainer container = new GenericContainer( TestSettings.ADMIN_IMAGE_ID );
 73 |         container.withEnv( "NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes" )
 74 |                  .withLogConsumer( new Slf4jLogConsumer( log ) );
 75 |         WaitStrategies.waitUntilContainerFinished( container, Duration.ofSeconds( 180) );
 76 |         if(!asDefaultUser)
 77 |         {
 78 |             SetContainerUser.nonRootUser( container );
 79 |         }
 80 |         return container;
 81 |     }
 82 | 
 83 |     @Test
 84 |     void shouldBackupAndRestore_defaultUser_noAuth() throws Exception
 85 |     {
 86 |         testCanBackupAndRestore( true, "none" );
 87 |     }
 88 |     @Test
 89 |     void shouldBackupAndRestore_nonDefaultUser_noAuth() throws Exception
 90 |     {
 91 |         testCanBackupAndRestore( false, "none" );
 92 |     }
 93 |     @Test
 94 |     void shouldBackupAndRestore_defaultUser_withAuth() throws Exception
 95 |     {
 96 |         testCanBackupAndRestore( true, "secretpassword" );
 97 |     }
 98 |     @Test
 99 |     void shouldBackupAndRestore_nonDefaultUser_withAuth() throws Exception
100 |     {
101 |         testCanBackupAndRestore( false, "secretpassword" );
102 |     }
103 | 
104 |     private void testCanBackupAndRestore(boolean asDefaultUser, String password) throws Exception
105 |     {
106 |         final String dbUser = "neo4j";
107 |         Path backupDir;
108 | 
109 |         // BACKUP
110 |         // start a database and populate data
111 |         try(GenericContainer neo4j = createDBContainer( asDefaultUser, password ))
112 |         {
113 |             Path dataDir = temporaryFolderManager.createFolderAndMountAsVolume(neo4j, "/data");
114 |             neo4j.start();
115 |             DatabaseIO dbio = new DatabaseIO( neo4j );
116 |             dbio.putInitialDataIntoContainer( dbUser, password );
117 |             dbio.verifyInitialDataInContainer( dbUser, password );
118 | 
119 |             // start admin container to initiate backup
120 |             String neoDBAddress = neo4j.getHost() + ":" + neo4j.getMappedPort( 6362 );
121 |             try(GenericContainer adminBackup = createAdminContainer( asDefaultUser ))
122 |             {
123 |                 adminBackup.withNetworkMode( "host" )
124 |                            .waitingFor( new LogMessageWaitStrategy().withRegEx( "^Backup command completed.*" ) )
125 |                            .withCommand( "neo4j-admin",
126 |                                          "database",
127 |                                          "backup",
128 |                                          "--to-path=/backups",
129 |                                          "--include-metadata=all",
130 |                                          "--from=" + neoDBAddress,
131 |                                          "neo4j" );
132 | 
133 |                 backupDir = temporaryFolderManager.createFolderAndMountAsVolume(adminBackup, "/backups");
134 |                 adminBackup.start();
135 | 
136 |                 Assertions.assertTrue( neo4j.isRunning(), "neo4j container should still be running" );
137 |                 dbio.verifyInitialDataInContainer( dbUser, password );
138 |             } //adminBackup goes out of scope here
139 | 
140 |             // find backup file name and verify its existence.
141 |             List<Path> backupFolder = Files.list( backupDir )
142 |                                            .filter( p -> p.toFile().getName().startsWith( "neo4j" ) )
143 |                                            .toList();
144 |             Assertions.assertEquals( 1, backupFolder.size(), "No backup file was created" );
145 |             File backupFile = backupFolder.get( 0 ).toFile();
146 | 
147 | 
148 |             // RESTORE
149 | 
150 |             // write more stuff
151 |             dbio.putMoreDataIntoContainer( dbUser, password );
152 |             dbio.verifyMoreDataIntoContainer( dbUser, password, true );
153 |             // stop database in preparation for restore
154 |             dbio.runCypherQuery( dbUser, password, "STOP DATABASE neo4j", "system" );
155 | 
156 |             // do restore
157 |             try(GenericContainer adminRestore = createAdminContainer( asDefaultUser ))
158 |             {
159 |                 adminRestore.waitingFor( Wait.forLogMessage( ".*Restore of database .* completed successfully.*", 1 )
160 |                                              .withStartupTimeout( Duration.ofSeconds( 180 ) ) )
161 |                             .withCommand( "neo4j-admin",
162 |                                           "database",
163 |                                           "restore",
164 |                                           "--overwrite-destination=true",
165 |                                           "--from-path=/backups/" + backupFile.getName(),
166 |                                           "neo4j" );
167 |                 temporaryFolderManager.mountHostFolderAsVolume( adminRestore, backupDir, "/backups" );
168 |                 temporaryFolderManager.mountHostFolderAsVolume( adminRestore, dataDir, "/data" );
169 |                 adminRestore.start();
170 |                 dbio.runCypherQuery( dbUser, password, "START DATABASE neo4j", "system" );
171 | 
172 |                 // verify new stuff is missing
173 |                 dbio.verifyMoreDataIntoContainer( dbUser, password, false );
174 |             } //adminRestore out of scope here
175 |         } // neo4j container goes out of scope here
176 |     }
177 | }
178 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/src/test/java/com/neo4j/docker/utils/Neo4jVersionTest.java:
--------------------------------------------------------------------------------

```java
  1 | package com.neo4j.docker.utils;
  2 | 
  3 | import org.junit.jupiter.api.Assertions;
  4 | import org.junit.jupiter.api.Test;
  5 | 
  6 | public class Neo4jVersionTest {
  7 | 
  8 |     @Test
  9 |     public void testIsOlderThan_majorDifferent()
 10 |     {
 11 |         Neo4jVersion newer = new Neo4jVersion( 3, 5, 1 );
 12 |         Neo4jVersion older = new Neo4jVersion( 2, 0, 0 );
 13 |         testOlderVsNewer( newer, older );
 14 |     }
 15 | 
 16 |     @Test
 17 |     public void testIsOlderThan_minorDifferent()
 18 |     {
 19 |         Neo4jVersion newer = new Neo4jVersion( 3, 5, 1 );
 20 |         Neo4jVersion older = new Neo4jVersion( 3, 0, 0 );
 21 |         testOlderVsNewer( newer, older );
 22 |     }
 23 | 
 24 |     @Test
 25 |     public void testIsOlderThan_patchDifferent()
 26 |     {
 27 |         Neo4jVersion newer = new Neo4jVersion( 3, 5, 1 );
 28 |         Neo4jVersion older = new Neo4jVersion( 3, 5, 0 );
 29 |         testOlderVsNewer( newer, older );
 30 |     }
 31 | 
 32 |     @Test
 33 |     public void testIsOlderThan_majorLessMinorMore()
 34 |     {
 35 |         Neo4jVersion newer = new Neo4jVersion( 3, 5, 1 );
 36 |         Neo4jVersion older = new Neo4jVersion( 2, 7, 0 );
 37 |         testOlderVsNewer( newer, older );
 38 |     }
 39 | 
 40 |     @Test
 41 |     public void testIsOlderThan_minorLessPatchMore()
 42 |     {
 43 |         Neo4jVersion newer = new Neo4jVersion( 3, 5, 0 );
 44 |         Neo4jVersion older = new Neo4jVersion( 3, 2, 12 );
 45 |         testOlderVsNewer( newer, older );
 46 |     }
 47 | 
 48 |     @Test
 49 |     public void testSamePatch_isEqualAndAtLeast()
 50 |     {
 51 |         Neo4jVersion newer = new Neo4jVersion( 3, 5, 0 );
 52 |         Neo4jVersion older = new Neo4jVersion( 3, 5, 0 );
 53 | 
 54 |         Assertions.assertFalse( newer.isOlderThan( older ) ,
 55 |                                 String.format( "Didn't detect that %s is newer than %s using isOlderThan", newer, older ) );
 56 |         Assertions.assertFalse( older.isNewerThan( newer ) ,
 57 |                      String.format( "Didn't detect that %s is older than %s using isNewerThan", older, newer ) );
 58 |         Assertions.assertTrue( newer.isAtLeastVersion( older ),
 59 |                     String.format( "Didn't detect that %s is at least %s using isAtLeastVersion", newer, older ) );
 60 |         Assertions.assertTrue( newer.isEqual(older),
 61 |                     String.format( "Didn't detect that %s is equal to %s using isEqual", newer, older ) );
 62 |     }
 63 | 
 64 |     @Test
 65 |     public void testSamePatch_isEqualAndAtLeast_differentBuild()
 66 |     {
 67 |         Neo4jVersion newer = new Neo4jVersion( 3, 5, 0, "-11" );
 68 |         Neo4jVersion older = new Neo4jVersion( 3, 5, 0, "-10" );
 69 | 
 70 |         Assertions.assertFalse( newer.isOlderThan( older ) ,
 71 |                      String.format( "Didn't detect that %s is newer than %s using isOlderThan", newer, older ) );
 72 |         Assertions.assertFalse( older.isNewerThan( newer ) ,
 73 |                      String.format( "Didn't detect that %s is older than %s using isNewerThan", older, newer ) );
 74 |         Assertions.assertTrue( newer.isAtLeastVersion( older ),
 75 |                     String.format( "Didn't detect that %s is at least %s using isAtLeastVersion", newer, older ) );
 76 |         Assertions.assertTrue( newer.isEqual(older),
 77 |                     String.format( "Didn't detect that %s is equal to %s using isEqual", newer, older ) );
 78 |     }
 79 | 
 80 |     private void testOlderVsNewer( Neo4jVersion newer, Neo4jVersion older )
 81 |     {
 82 |         // isOlderThan
 83 |         Assertions.assertTrue( older.isOlderThan( newer ) ,
 84 |                     String.format( "Didn't detect that %s is older than %s using isOlderThan", older, newer ) );
 85 |         Assertions.assertFalse( newer.isOlderThan( older ) ,
 86 |                      String.format( "Didn't detect that %s is newer than %s using isOlderThan", newer, older ) );
 87 | 
 88 |         // isNewerThan
 89 |         Assertions.assertTrue( newer.isNewerThan( older ),
 90 |                     String.format( "Didn't detect that %s is newer than %s using isNewerThan", newer, older ) );
 91 |         Assertions.assertFalse( older.isNewerThan( newer ) ,
 92 |                      String.format( "Didn't detect that %s is older than %s using isNewerThan", older, newer ) );
 93 | 
 94 |         // isAtLeastVersion
 95 |         Assertions.assertTrue( newer.isAtLeastVersion( older ),
 96 |                     String.format( "Didn't detect that %s is newer than %s using isAtLeastVersion", newer, older ) );
 97 |         Assertions.assertFalse( older.isAtLeastVersion( newer ) ,
 98 |                      String.format( "Didn't detect that %s is older than %s using isAtLeastVersion", older, newer ) );
 99 | 
100 |         Assertions.assertFalse( newer.isEqual(older),
101 |                                 String.format( "%s incorrectly is equal to %s", newer, older ) );
102 |         Assertions.assertNotEquals( newer, older, String.format( "%s incorrectly is equal to %s", newer, older ) );
103 |     }
104 | 
105 |     @Test
106 |     public void testIsOlderThan_sameReleaseReturnsFalse()
107 |     {
108 |         Neo4jVersion version = new Neo4jVersion( 3, 5, 1 );
109 | 
110 |         Assertions.assertFalse( version.isOlderThan( version ) ,
111 |                      "A release should not be older than itself" );
112 |         Assertions.assertFalse( version.isNewerThan( version ) ,
113 |                      "A release should not be newer than itself" );
114 |     }
115 | 
116 |     @Test
117 |     public void testFromVersionString_releaseFormat()
118 |     {
119 |         Neo4jVersion version = Neo4jVersion.fromVersionString( "4.4.7" );
120 |         Assertions.assertEquals( 4, version.major, "Did not parse major number from " + version );
121 |         Assertions.assertEquals( 4, version.minor, "Did not parse minor number from " + version );
122 |         Assertions.assertEquals( 7, version.patch, "Did not parse patch number from " + version );
123 |     }
124 | 
125 |     @Test
126 |     public void testFromVersionString_BSPFormat()
127 |     {
128 |         Neo4jVersion version = Neo4jVersion.fromVersionString( "4.4.7-12345" );
129 |         Assertions.assertEquals( 4, version.major, "Did not parse major number from " + version );
130 |         Assertions.assertEquals( 4, version.minor, "Did not parse minor number from " + version );
131 |         Assertions.assertEquals( 7, version.patch, "Did not parse patch number from " + version );
132 |         Assertions.assertEquals( "-12345", version.label, "Did not build number from " + version );
133 |     }
134 | 
135 |     @Test
136 |     public void testFromVersionString_calver_releaseFormat()
137 |     {
138 |         Neo4jVersion version = Neo4jVersion.fromVersionString( "2024.10.0" );
139 |         Assertions.assertEquals( 2024, version.major, "Did not parse major number from " + version );
140 |         Assertions.assertEquals( 10, version.minor, "Did not parse minor number from " + version );
141 |         Assertions.assertEquals( 0, version.patch, "Did not parse patch number from " + version );
142 |     }
143 | 
144 |     @Test
145 |     public void testFromVersionString_calver_BSPFormat()
146 |     {
147 |         Neo4jVersion version = Neo4jVersion.fromVersionString( "2024.10.0-1234" );
148 |         Assertions.assertEquals( 2024, version.major, "Did not parse major number from " + version );
149 |         Assertions.assertEquals( 10, version.minor, "Did not parse minor number from " + version );
150 |         Assertions.assertEquals( 0, version.patch, "Did not parse patch number from " + version );
151 |         Assertions.assertEquals( "-1234", version.label, "Did not build number from " + version );
152 |     }
153 | 
154 |     @Test
155 |     public void testFromVersionString_calver_OneMonthDigit()
156 |     {
157 |         // an incorrect format, but would be useful if it was handled correctly
158 |         Neo4jVersion version = Neo4jVersion.fromVersionString( "2027.1.5-99" );
159 |         Assertions.assertEquals( 2027, version.major, "Did not parse major number from " + version );
160 |         Assertions.assertEquals( 1, version.minor, "Did not parse minor number from " + version );
161 |         Assertions.assertEquals( 5, version.patch, "Did not parse patch number from " + version );
162 |         Assertions.assertEquals( "-99", version.label, "Did not build number from " + version );
163 |     }
164 | 
165 |     @Test
166 |     void testToStringCalVer()
167 |     {
168 |         Neo4jVersion version = Neo4jVersion.fromVersionString( "2025.2.0-1234" );
169 |         String outStr = version.toString();
170 |         Assertions.assertEquals( "2025.02.0-1234", outStr );
171 |     }
172 | }
173 | 
```

--------------------------------------------------------------------------------
/neo4j/docker-neo4j/docker-image-src/3.1/docker-entrypoint.sh:
--------------------------------------------------------------------------------

```bash
  1 | #!/bin/bash -eu
  2 | 
  3 | cmd="$1"
  4 | 
  5 | function running_as_root
  6 | {
  7 |     test "$(id -u)" = "0"
  8 | }
  9 | 
 10 | # If we're running as root, then run as the neo4j user. Otherwise
 11 | # docker is running with --user and we simply use that user.  Note
 12 | # that su-exec, despite its name, does not replicate the functionality
 13 | # of exec, so we need to use both
 14 | if running_as_root; then
 15 |   userid="neo4j"
 16 |   groupid="neo4j"
 17 |   exec_cmd="exec su-exec neo4j"
 18 | else
 19 |   userid="$(id -u)"
 20 |   groupid="$(id -g)"
 21 |   exec_cmd="exec"
 22 | fi
 23 | readonly userid
 24 | readonly groupid
 25 | readonly exec_cmd
 26 | 
 27 | # Need to chown the home directory - but a user might have mounted a
 28 | # volume here (notably a conf volume). So take care not to chown
 29 | # volumes (stuff not owned by neo4j)
 30 | if running_as_root; then
 31 |   # Non-recursive chown for the base directory
 32 |   chown "${userid}":"${groupid}" "${NEO4J_HOME}"
 33 |   chmod 700 "${NEO4J_HOME}"
 34 | fi
 35 | 
 36 | while IFS= read -r -d '' dir
 37 | do
 38 |   if running_as_root && [[ "$(stat -c %U "${dir}")" = "neo4j" ]]; then
 39 |     # Using mindepth 1 to avoid the base directory here so recursive is OK
 40 |     chown -R "${userid}":"${groupid}" "${dir}"
 41 |     chmod -R 700 "${dir}"
 42 |   fi
 43 | done <   <(find "${NEO4J_HOME}" -type d -mindepth 1 -maxdepth 1 -print0)
 44 | 
 45 | # Data dir is chowned later
 46 | 
 47 | if [ "${cmd}" == "dump-config" ]; then
 48 |   if [ -d /conf ]; then
 49 |     ${exec_cmd} cp --recursive "${NEO4J_HOME}"/conf/* /conf
 50 |     exit 0
 51 |   else
 52 |     echo >&2 "You must provide a /conf volume"
 53 |     exit 1
 54 |   fi
 55 | fi
 56 | 
 57 | # Env variable naming convention:
 58 | # - prefix NEO4J_
 59 | # - double underscore char '__' instead of single underscore '_' char in the setting name
 60 | # - underscore char '_' instead of dot '.' char in the setting name
 61 | # Example:
 62 | # NEO4J_dbms_tx__log_rotation_retention__policy env variable to set
 63 | #       dbms.tx_log.rotation.retention_policy setting
 64 | 
 65 | # Backward compatibility - map old hardcoded env variables into new naming convention (if they aren't set already)
 66 | # Set some to default values if unset
 67 | : ${NEO4J_dbms_tx__log_rotation_retention__policy:=${NEO4J_dbms_txLog_rotation_retentionPolicy:-"100M size"}}
 68 | : ${NEO4J_wrapper_java_additional:=${NEO4J_UDC_SOURCE:-"-Dneo4j.ext.udc.source=docker"}}
 69 | : ${NEO4J_dbms_memory_heap_initial__size:=${NEO4J_dbms_memory_heap_maxSize:-"512M"}}
 70 | : ${NEO4J_dbms_memory_heap_max__size:=${NEO4J_dbms_memory_heap_maxSize:-"512M"}}
 71 | : ${NEO4J_dbms_unmanaged__extension__classes:=${NEO4J_dbms_unmanagedExtensionClasses:-}}
 72 | : ${NEO4J_dbms_allow__format__migration:=${NEO4J_dbms_allowFormatMigration:-}}
 73 | : ${NEO4J_dbms_connectors_default__advertised__address:=${NEO4J_dbms_connectors_defaultAdvertisedAddress:-}}
 74 | : ${NEO4J_ha_server__id:=${NEO4J_ha_serverId:-}}
 75 | : ${NEO4J_ha_initial__hosts:=${NEO4J_ha_initialHosts:-}}
 76 | : ${NEO4J_causal__clustering_expected__core__cluster__size:=${NEO4J_causalClustering_expectedCoreClusterSize:-}}
 77 | : ${NEO4J_causal__clustering_initial__discovery__members:=${NEO4J_causalClustering_initialDiscoveryMembers:-}}
 78 | : ${NEO4J_causal__clustering_discovery__listen__address:=${NEO4J_causalClustering_discoveryListenAddress:-"0.0.0.0:5000"}}
 79 | : ${NEO4J_causal__clustering_discovery__advertised__address:=${NEO4J_causalClustering_discoveryAdvertisedAddress:-"$(hostname):5000"}}
 80 | : ${NEO4J_causal__clustering_transaction__listen__address:=${NEO4J_causalClustering_transactionListenAddress:-"0.0.0.0:6000"}}
 81 | : ${NEO4J_causal__clustering_transaction__advertised__address:=${NEO4J_causalClustering_transactionAdvertisedAddress:-"$(hostname):6000"}}
 82 | : ${NEO4J_causal__clustering_raft__listen__address:=${NEO4J_causalClustering_raftListenAddress:-"0.0.0.0:7000"}}
 83 | : ${NEO4J_causal__clustering_raft__advertised__address:=${NEO4J_causalClustering_raftAdvertisedAddress:-"$(hostname):7000"}}
 84 | 
 85 | : ${NEO4J_dbms_connectors_default__listen__address:="0.0.0.0"}
 86 | : ${NEO4J_dbms_connector_http_listen__address:="0.0.0.0:7474"}
 87 | : ${NEO4J_dbms_connector_https_listen__address:="0.0.0.0:7473"}
 88 | : ${NEO4J_dbms_connector_bolt_listen__address:="0.0.0.0:7687"}
 89 | : ${NEO4J_ha_host_coordination:="$(hostname):5001"}
 90 | : ${NEO4J_ha_host_data:="$(hostname):6001"}
 91 | 
 92 | # unset old hardcoded unsupported env variables
 93 | unset NEO4J_dbms_txLog_rotation_retentionPolicy NEO4J_UDC_SOURCE \
 94 |     NEO4J_dbms_memory_heap_maxSize NEO4J_dbms_memory_heap_maxSize \
 95 |     NEO4J_dbms_unmanagedExtensionClasses NEO4J_dbms_allowFormatMigration \
 96 |     NEO4J_dbms_connectors_defaultAdvertisedAddress NEO4J_ha_serverId \
 97 |     NEO4J_ha_initialHosts NEO4J_causalClustering_expectedCoreClusterSize \
 98 |     NEO4J_causalClustering_initialDiscoveryMembers \
 99 |     NEO4J_causalClustering_discoveryListenAddress \
100 |     NEO4J_causalClustering_discoveryAdvertisedAddress \
101 |     NEO4J_causalClustering_transactionListenAddress \
102 |     NEO4J_causalClustering_transactionAdvertisedAddress \
103 |     NEO4J_causalClustering_raftListenAddress \
104 |     NEO4J_causalClustering_raftAdvertisedAddress
105 | 
106 | if [ -d /conf ]; then
107 |     find /conf -type f -exec cp {} "${NEO4J_HOME}"/conf \;
108 | fi
109 | 
110 | if [ -d /ssl ]; then
111 |     NEO4J_dbms_directories_certificates="/ssl"
112 | fi
113 | 
114 | if [ -d /plugins ]; then
115 |     NEO4J_dbms_directories_plugins="/plugins"
116 | fi
117 | 
118 | if [ -d /logs ]; then
119 |     NEO4J_dbms_directories_logs="/logs"
120 | fi
121 | 
122 | if [ -d /import ]; then
123 |     NEO4J_dbms_directories_import="/import"
124 | fi
125 | 
126 | if [ -d /metrics ]; then
127 |     NEO4J_dbms_directories_metrics="/metrics"
128 | fi
129 | 
130 | # set the neo4j initial password only if you run the database server
131 | if [ "${cmd}" == "neo4j" ]; then
132 |     if [ "${NEO4J_AUTH:-}" == "none" ]; then
133 |         NEO4J_dbms_security_auth__enabled=false
134 |     elif [[ "${NEO4J_AUTH:-}" == neo4j/* ]]; then
135 |         password="${NEO4J_AUTH#neo4j/}"
136 |         if [ "${password}" == "neo4j" ]; then
137 |             echo >&2 "Invalid value for password. It cannot be 'neo4j', which is the default."
138 |             exit 1
139 |         fi
140 |         # Will exit with error if users already exist (and print a message explaining that)
141 |         bin/neo4j-admin set-initial-password "${password}" || true
142 |     elif [ -n "${NEO4J_AUTH:-}" ]; then
143 |         echo >&2 "Invalid value for NEO4J_AUTH: '${NEO4J_AUTH}'"
144 |         exit 1
145 |     fi
146 | fi
147 | 
148 | # list env variables with prefix NEO4J_ and create settings from them
149 | unset NEO4J_AUTH NEO4J_SHA256 NEO4J_TARBALL
150 | for i in $( set | grep ^NEO4J_ | awk -F'=' '{print $1}' | sort -rn ); do
151 |     setting=$(echo ${i} | sed 's|^NEO4J_||' | sed 's|_|.|g' | sed 's|\.\.|_|g')
152 |     value=$(echo ${!i})
153 |     # Don't allow settings with no value or settings that start with a number (neo4j converts settings to env variables and you cannot have an env variable that starts with a number)
154 |     if [[ -n ${value} ]]; then
155 |         if [[ ! "${setting}" =~ ^[0-9]+.*$ ]]; then
156 |             if grep -q -F "${setting}=" "${NEO4J_HOME}"/conf/neo4j.conf; then
157 |                 # Remove any lines containing the setting already
158 |                 sed --in-place "/^${setting}=.*/d" "${NEO4J_HOME}"/conf/neo4j.conf
159 |             fi
160 |             # Then always append setting to file
161 |             echo "${setting}=${value}" >> "${NEO4J_HOME}"/conf/neo4j.conf
162 |         else
163 |             echo >&2 "WARNING: ${setting} not written to conf file because settings that start with a number are not permitted"
164 |         fi
165 |     fi
166 | done
167 | 
168 | # Chown the data dir now that (maybe) an initial password has been
169 | # set (this is a file in the data dir)
170 | if running_as_root; then
171 |   chmod -R 777 /data
172 |   chown -R "${userid}":"${groupid}" /data
173 | fi
174 | 
175 | # if we're running as root and the logs directory is not writable by the neo4j user, then chown it.
176 | # this situation happens if no user is passed to docker run and the /logs directory is mounted.
177 | if running_as_root && [[ "$(stat -c %U /logs)" != "neo4j" ]]; then
178 | #if [[ $(stat -c %u /logs) != $(id -u "${userid}") ]]; then
179 |     echo "/logs directory is not writable. Changing the directory owner to ${userid}:${groupid}"
180 |     # chown the log dir if it's not writable
181 |     chmod -R 777 /logs
182 |     chown -R "${userid}":"${groupid}" /logs
183 | fi
184 | 
185 | # If we're running as a non-default user and we can't write to the logs directory then user needs to change directory permissions manually.
186 | # This happens if a user is passed to docker run and an unwritable log directory is mounted.
187 | if ! running_as_root && [[ ! -w /logs ]]; then
188 |     echo "User does not have write permissions to mounted log directory."
189 |     echo "Manually grant write permissions for the directory and try again."
190 |     exit 1
191 | fi
192 | 
193 | [ -f "${EXTENSION_SCRIPT:-}" ] && . ${EXTENSION_SCRIPT}
194 | 
195 | # Use su-exec to drop privileges to neo4j user
196 | # Note that su-exec, despite its name, does not replicate the
197 | # functionality of exec, so we need to use both
198 | if [ "${cmd}" == "neo4j" ]; then
199 |   ${exec_cmd} neo4j console
200 | else
201 |   ${exec_cmd} "$@"
202 | fi
203 | 
```
Page 2/7FirstPrevNextLast