From 1034ee33df3089b4f3ec46ec68cfc773d4bb6833 Mon Sep 17 00:00:00 2001 From: Jon Bartels Date: Thu, 2 Jul 2026 14:06:49 -0400 Subject: [PATCH 1/3] When passwords are read from env vars, they are handled by the entrypoint to update the application properties file. This handling was not correctly escaping the strings and interactions with sed and control characters for sed were breaking deployments with complex passwords. This introduces a function to DRY up the code and uses awk instead of sed to avoid control character issues. Signed-off-by: Jon Bartels --- deploy/entrypoint.sh | 167 +++++++++++++------------------------------ 1 file changed, 49 insertions(+), 118 deletions(-) diff --git a/deploy/entrypoint.sh b/deploy/entrypoint.sh index 285d501..f2f1cc9 100755 --- a/deploy/entrypoint.sh +++ b/deploy/entrypoint.sh @@ -7,84 +7,97 @@ set -e -APP_DIR=/opt/engine - -custom_extension_count=`ls -1 "$APP_DIR"/custom-extensions/*.zip 2>/dev/null | wc -l` -if [ $custom_extension_count != 0 ]; then - echo "Found ${custom_extension_count} custom extensions." - for extension in $(ls -1 "$APP_DIR"/custom-extensions/*.zip); do - unzip -o -q $extension -d "$APP_DIR/extensions" - done -fi +APP_DIR=/opt/oie + +# Set (or append) a property in a Java .properties file. +# +# set_property +# +# The value is passed through the environment and read via awk's ENVIRON, so it +# is treated as a literal string. This avoids the sed replacement pitfalls where +# '&', '\' and '/' are special (e.g. a DATABASE_PASSWORD containing '&' would +# otherwise be expanded to the matched text and corrupt the file). +set_property() { + local key=$1 + local value=$2 + local file=$3 + # Escape regex metacharacters in the key so it matches literally. + local ekey + # shellcheck disable=SC2016 # single quotes are intentional; this is a sed program, not shell + ekey=$(printf '%s' "$key" | sed -e 's/[][\.*^$(){}?+|/-]/\\&/g') + + VALUE="$value" awk -v pattern="^${ekey}[[:space:]]*=" -v name="$key" ' + $0 ~ pattern { print name " = " ENVIRON["VALUE"]; found=1; next } + { print } + END { if (!found) print name " = " ENVIRON["VALUE"] } + ' "$file" > "$file.tmp" && mv "$file.tmp" "$file" +} + +MIRTH_PROPERTIES="$APP_DIR/conf/mirth.properties" # set storepass and keypass to 'changeme' so they aren't overwritten later KEYSTORE_PASS=changeme -sed -i "s/^keystore\.storepass\s*=\s*.*\$/keystore.storepass = ${KEYSTORE_PASS//\//\\/}/" "$APP_DIR/conf/mirth.properties" -sed -i "s/^keystore\.keypass\s*=\s*.*\$/keystore.keypass = ${KEYSTORE_PASS//\//\\/}/" "$APP_DIR/conf/mirth.properties" +set_property "keystore.storepass" "$KEYSTORE_PASS" "$MIRTH_PROPERTIES" +set_property "keystore.keypass" "$KEYSTORE_PASS" "$MIRTH_PROPERTIES" -# merge the environment variables into /opt/engine/conf/mirth.properties +# merge the environment variables into mirth.properties # db type if ! [ -z "${DATABASE+x}" ]; then - sed -i "s/^database\s*=\s*.*\$/database = ${DATABASE//\//\\/}/" "$APP_DIR/conf/mirth.properties" + set_property "database" "$DATABASE" "$MIRTH_PROPERTIES" fi # db username if ! [ -z "${DATABASE_USERNAME+x}" ]; then - sed -i "s/^database\.username\s*=\s*.*\$/database.username = ${DATABASE_USERNAME//\//\\/}/" "$APP_DIR/conf/mirth.properties" + set_property "database.username" "$DATABASE_USERNAME" "$MIRTH_PROPERTIES" fi # db password if ! [ -z "${DATABASE_PASSWORD+x}" ]; then - sed -i "s/^database\.password\s*=\s*.*\$/database.password = ${DATABASE_PASSWORD//\//\\/}/" "$APP_DIR/conf/mirth.properties" + set_property "database.password" "$DATABASE_PASSWORD" "$MIRTH_PROPERTIES" fi # db url if ! [ -z "${DATABASE_URL+x}" ]; then - sed -i "s/^database\.url\s*=\s*.*\$/database.url = ${DATABASE_URL//\//\\/}/" "$APP_DIR/conf/mirth.properties" + set_property "database.url" "$DATABASE_URL" "$MIRTH_PROPERTIES" fi # database max connections if ! [ -z "${DATABASE_MAX_CONNECTIONS+x}" ]; then - sed -i "s/^database\.max-connections\s*=\s*.*\$/database.max-connections = ${DATABASE_MAX_CONNECTIONS//\//\\/}/" "$APP_DIR/conf/mirth.properties" + set_property "database.max-connections" "$DATABASE_MAX_CONNECTIONS" "$MIRTH_PROPERTIES" fi # database max retries if ! [ -z "${DATABASE_MAX_RETRY+x}" ]; then - sed -i "s/^database\.connection\.maxretry\s*=\s*.*\$/database.connection.maxretry = ${DATABASE_MAX_RETRY//\//\\/}/" "$APP_DIR/conf/mirth.properties" + set_property "database.connection.maxretry" "$DATABASE_MAX_RETRY" "$MIRTH_PROPERTIES" fi # database retry wait time if ! [ -z "${DATABASE_RETRY_WAIT+x}" ]; then - sed -i "s/^database\.connection\.retrywaitinmilliseconds\s*=\s*.*\$/database.connection.retrywaitinmilliseconds = ${DATABASE_RETRY_WAIT//\//\\/}/" "$APP_DIR/conf/mirth.properties" + set_property "database.connection.retrywaitinmilliseconds" "$DATABASE_RETRY_WAIT" "$MIRTH_PROPERTIES" fi # keystore storepass if ! [ -z "${KEYSTORE_STOREPASS+x}" ]; then - sed -i "s/^keystore\.storepass\s*=\s*.*\$/keystore.storepass = ${KEYSTORE_STOREPASS//\//\\/}/" "$APP_DIR/conf/mirth.properties" + set_property "keystore.storepass" "$KEYSTORE_STOREPASS" "$MIRTH_PROPERTIES" fi # keystore keypass if ! [ -z "${KEYSTORE_KEYPASS+x}" ]; then - sed -i "s/^keystore\.keypass\s*=\s*.*\$/keystore.keypass = ${KEYSTORE_KEYPASS//\//\\/}/" "$APP_DIR/conf/mirth.properties" + set_property "keystore.keypass" "$KEYSTORE_KEYPASS" "$MIRTH_PROPERTIES" fi if ! [ -z "${KEYSTORE_TYPE+x}" ]; then - sed -i "s/^keystore\.type\s*=\s*.*\$/keystore.type = ${KEYSTORE_TYPE//\//\\/}/" "$APP_DIR/conf/mirth.properties" + set_property "keystore.type" "$KEYSTORE_TYPE" "$MIRTH_PROPERTIES" fi # session store if ! [ -z "${SESSION_STORE+x}" ]; then - LINE_COUNT=`grep "server.api.sessionstore" "$APP_DIR/conf/mirth.properties" | wc -l` - if [ $LINE_COUNT -lt 1 ]; then - echo -e "\nserver.api.sessionstore = ${SESSION_STORE//\//\\/}" >> "$APP_DIR/conf/mirth.properties" - else - sed -i "s/^server\.api\.sessionstore\s*=\s*.*\$/server.api.sessionstore = ${SESSION_STORE//\//\\/}/" "$APP_DIR/conf/mirth.properties" - fi + set_property "server.api.sessionstore" "$SESSION_STORE" "$MIRTH_PROPERTIES" fi #server ID if ! [ -z "${SERVER_ID+x}" ]; then - echo -e "server.id = ${SERVER_ID//\//\\/}" > "$APP_DIR/appdata/server.id" + printf 'server.id = %s\n' "$SERVER_ID" > "$APP_DIR/appdata/server.id" fi # merge extra environment variables starting with _MP_ into mirth.properties @@ -118,21 +131,12 @@ while read -r keyvalue; do # example: database.max-connections ACTUAL_KEY="${ACTUAL_KEY,,}" - # if key does not exist in mirth.properties append it at bottom - LINE_COUNT=`grep "^${ACTUAL_KEY}" "$APP_DIR/conf/mirth.properties" | wc -l` - if [ $LINE_COUNT -lt 1 ]; then - # echo "key ${ACTUAL_KEY} not found in mirth.properties, appending. Value = ${VALUE}" - echo -e "\n${ACTUAL_KEY} = ${VALUE//\//\\/}" >> "$APP_DIR/conf/mirth.properties" - else # otherwise key exists, overwrite it - # echo "key ${ACTUAL_KEY} exists, overwriting. Value = ${VALUE}" - ESCAPED_KEY="${ACTUAL_KEY//./\\.}" - sed -i "s/^${ESCAPED_KEY}\s*=\s*.*\$/${ACTUAL_KEY} = ${VALUE//\//\\/}/" "$APP_DIR/conf/mirth.properties" - fi + set_property "${ACTUAL_KEY}" "${VALUE}" "$MIRTH_PROPERTIES" fi fi -done <<< "`printenv`" +done <<< "$(printenv)" -# merge vmoptions into /opt/engine/oieserver.vmoptions +# merge vmoptions into oieserver.vmoptions if ! [ -z "${VMOPTIONS+x}" ]; then PREV_IFS="$IFS" IFS="," @@ -146,12 +150,9 @@ if ! [ -z "${VMOPTIONS+x}" ]; then fi # merge the user's secret mirth.properties -# takes a whole mirth.properties file and merges line by line with /opt/engine/conf/mirth.properties +# takes a whole mirth.properties file and merges line by line with mirth.properties if [ -f /run/secrets/mirth_properties ]; then - # add new line in case /opt/engine/conf/mirth.properties doesn't end with one - echo "" >> "$APP_DIR/conf/mirth.properties" - while read -r keyvalue; do KEY="${keyvalue%%=*}" VALUE="${keyvalue#*=}" @@ -161,85 +162,15 @@ if [ -f /run/secrets/mirth_properties ]; then VALUE="$(echo -e "${VALUE}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" if ! [ -z "${KEY}" ] && ! [ -z "${VALUE}" ] && ! [[ ${VALUE} =~ ^\ +$ ]]; then - # if key does not exist in mirth.properties append it at bottom - LINE_COUNT=`grep "^${KEY}" "$APP_DIR/conf/mirth.properties" | wc -l` - if [ $LINE_COUNT -lt 1 ]; then - # echo "key ${KEY} not found in mirth.properties, appending. Value = ${VALUE}" - echo -e "${KEY} = ${VALUE//\//\\/}" >> "$APP_DIR/conf/mirth.properties" - else # otherwise key exists, overwrite it - # echo "key ${KEY} exists, overwriting. Value = ${VALUE}" - ESCAPED_KEY="${KEY//./\\.}" - sed -i "s/^${ESCAPED_KEY}\s*=\s*.*\$/${KEY} = ${VALUE//\//\\/}/" "$APP_DIR/conf/mirth.properties" - fi + set_property "${KEY}" "${VALUE}" "$MIRTH_PROPERTIES" fi - done <<< "`cat /run/secrets/mirth_properties`" + done <<< "$(cat /run/secrets/mirth_properties)" fi # merge the user's secret vmoptions -# takes a whole oieserver.vmoptions file and merges line by line with /opt/engine/oieserver.vmoptions +# takes a whole oieserver.vmoptions file and merges line by line with oieserver.vmoptions if [ -f /run/secrets/oieserver_vmoptions ]; then (cat /run/secrets/oieserver_vmoptions ; echo "") >> "$APP_DIR/oieserver.vmoptions" fi -# download jars from this url "$CUSTOM_JARS_DOWNLOAD", set by user -if ! [ -z "${CUSTOM_JARS_DOWNLOAD+x}" ]; then - echo "Downloading Jars at ${CUSTOM_JARS_DOWNLOAD}" - if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then - curl -ksSLf "${CUSTOM_JARS_DOWNLOAD}" -o userJars.zip || echo "problem with custom jars download" - else - curl -sSLf "${CUSTOM_JARS_DOWNLOAD}" -o userJars.zip || echo "problem with custom jars download" - fi - - # Unzipping contents of userJars.zip into /opt/engine/server-launcher-lib folder - if [ -e "userJars.zip" ]; then - echo "Unzipping contents of userJars.zip into $APP_DIR/server-launcher-lib" - unzip userJars.zip -d "$APP_DIR/server-launcher-lib" - # removing the downloaded zip file - rm userJars.zip - fi -fi - -# download extensions from this url "$EXTENSIONS_DOWNLOAD", set by user -if ! [ -z "${EXTENSIONS_DOWNLOAD+x}" ]; then - echo "Downloading extensions at ${EXTENSIONS_DOWNLOAD}" - if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then - curl -ksSLf "${EXTENSIONS_DOWNLOAD}" -o userExtensions.zip || echo "problem with extensions download" - else - curl -sSLf "${EXTENSIONS_DOWNLOAD}" -o userExtensions.zip || echo "problem with extensions download" - fi - - # Unzipping contents of userExtensions.zip - if [ -e "userExtensions.zip" ]; then - echo "Unzipping contents of userExtensions.zip" - mkdir /tmp/userextensions - unzip userExtensions.zip -d /tmp/userextensions - # removing the downloaded zip file - rm userExtensions.zip - - # Unzipping contents of individual extension zip files into /opt/engine/extensions folder - zipFileCount=`ls -1 /tmp/userextensions/*.zip 2>/dev/null | wc -l` - if [ $zipFileCount != 0 ]; then - echo "Unzipping contents of /tmp/userextensions/ zips into $APP_DIR/extensions" - for f in /tmp/userextensions/*.zip; do unzip "$f" -d "$APP_DIR/extensions"; done - fi - # removing the tmp folder - rm -rf /tmp/userextensions - fi -fi - -# download keystore -if ! [ -z "${KEYSTORE_DOWNLOAD+x}" ]; then - echo "Downloading keystore at ${KEYSTORE_DOWNLOAD}" - if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then - curl -ksSLf "${KEYSTORE_DOWNLOAD}" -o "$APP_DIR/appdata/keystore.jks" || echo "problem with keystore download" - else - curl -sSLf "${KEYSTORE_DOWNLOAD}" -o "$APP_DIR/appdata/keystore.jks" || echo "problem with keystore download" - fi -fi - -# if delay is set as an environment variable then wait that long in seconds -if ! [ -z "${DELAY+x}" ]; then - sleep $DELAY -fi - exec "$@" From 5655eb78c6d277dd2b4a15f6683ee4121b9263ce Mon Sep 17 00:00:00 2001 From: Jon Bartels Date: Thu, 2 Jul 2026 14:11:47 -0400 Subject: [PATCH 2/3] Restore custom downloads --- deploy/entrypoint.sh | 61 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/deploy/entrypoint.sh b/deploy/entrypoint.sh index f2f1cc9..63d609a 100755 --- a/deploy/entrypoint.sh +++ b/deploy/entrypoint.sh @@ -173,4 +173,65 @@ if [ -f /run/secrets/oieserver_vmoptions ]; then (cat /run/secrets/oieserver_vmoptions ; echo "") >> "$APP_DIR/oieserver.vmoptions" fi + download jars from this url "$CUSTOM_JARS_DOWNLOAD", set by user +if ! [ -z "${CUSTOM_JARS_DOWNLOAD+x}" ]; then + echo "Downloading Jars at ${CUSTOM_JARS_DOWNLOAD}" + if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then + curl -ksSLf "${CUSTOM_JARS_DOWNLOAD}" -o userJars.zip || echo "problem with custom jars download" + else + curl -sSLf "${CUSTOM_JARS_DOWNLOAD}" -o userJars.zip || echo "problem with custom jars download" + fi + + # Unzipping contents of userJars.zip into /opt/engine/server-launcher-lib folder + if [ -e "userJars.zip" ]; then + echo "Unzipping contents of userJars.zip into $APP_DIR/server-launcher-lib" + unzip userJars.zip -d "$APP_DIR/server-launcher-lib" + # removing the downloaded zip file + rm userJars.zip + fi +fi + +# download extensions from this url "$EXTENSIONS_DOWNLOAD", set by user +if ! [ -z "${EXTENSIONS_DOWNLOAD+x}" ]; then + echo "Downloading extensions at ${EXTENSIONS_DOWNLOAD}" + if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then + curl -ksSLf "${EXTENSIONS_DOWNLOAD}" -o userExtensions.zip || echo "problem with extensions download" + else + curl -sSLf "${EXTENSIONS_DOWNLOAD}" -o userExtensions.zip || echo "problem with extensions download" + fi + + # Unzipping contents of userExtensions.zip + if [ -e "userExtensions.zip" ]; then + echo "Unzipping contents of userExtensions.zip" + mkdir /tmp/userextensions + unzip userExtensions.zip -d /tmp/userextensions + # removing the downloaded zip file + rm userExtensions.zip + + # Unzipping contents of individual extension zip files into /opt/engine/extensions folder + zipFileCount=`ls -1 /tmp/userextensions/*.zip 2>/dev/null | wc -l` + if [ $zipFileCount != 0 ]; then + echo "Unzipping contents of /tmp/userextensions/ zips into $APP_DIR/extensions" + for f in /tmp/userextensions/*.zip; do unzip "$f" -d "$APP_DIR/extensions"; done + fi + # removing the tmp folder + rm -rf /tmp/userextensions + fi +fi + +# download keystore +if ! [ -z "${KEYSTORE_DOWNLOAD+x}" ]; then + echo "Downloading keystore at ${KEYSTORE_DOWNLOAD}" + if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then + curl -ksSLf "${KEYSTORE_DOWNLOAD}" -o "$APP_DIR/appdata/keystore.jks" || echo "problem with keystore download" + else + curl -sSLf "${KEYSTORE_DOWNLOAD}" -o "$APP_DIR/appdata/keystore.jks" || echo "problem with keystore download" + fi +fi + +# if delay is set as an environment variable then wait that long in seconds +if ! [ -z "${DELAY+x}" ]; then + sleep $DELAY +fi + exec "$@" From 3f2a878a986fc9d9a7bf4e1adb99fd5194c4c06e Mon Sep 17 00:00:00 2001 From: Jon Bartels Date: Thu, 2 Jul 2026 14:13:01 -0400 Subject: [PATCH 3/3] typo Signed-off-by: Jon Bartels --- deploy/entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/entrypoint.sh b/deploy/entrypoint.sh index 63d609a..a1d062d 100755 --- a/deploy/entrypoint.sh +++ b/deploy/entrypoint.sh @@ -173,7 +173,7 @@ if [ -f /run/secrets/oieserver_vmoptions ]; then (cat /run/secrets/oieserver_vmoptions ; echo "") >> "$APP_DIR/oieserver.vmoptions" fi - download jars from this url "$CUSTOM_JARS_DOWNLOAD", set by user +# download jars from this url "$CUSTOM_JARS_DOWNLOAD", set by user if ! [ -z "${CUSTOM_JARS_DOWNLOAD+x}" ]; then echo "Downloading Jars at ${CUSTOM_JARS_DOWNLOAD}" if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then