From 6c465f8496ac67bd706a1f37645ed43e3e0d7d2c Mon Sep 17 00:00:00 2001
From: Arthur Ulfeldt <arthur@ulfeldt.com>
Date: Tue, 18 Apr 2017 17:16:16 -0700
Subject: [PATCH] Safely set permissions when an H2 db is mounted in a shared
 volume

If the DB is using H2 and it's stores outside of docker, then we need
to be polite and safe about how we set permissions on the directory.
---
 bin/docker/run_metabase.sh | 75 ++++++++++++++++++++++++++++++++------
 1 file changed, 63 insertions(+), 12 deletions(-)

diff --git a/bin/docker/run_metabase.sh b/bin/docker/run_metabase.sh
index 7c8562e9931..93ef3fa8378 100755
--- a/bin/docker/run_metabase.sh
+++ b/bin/docker/run_metabase.sh
@@ -32,32 +32,83 @@ MGID=${MGID:-2000}
 MUID=${MUID:-2000}
 
 # create the group if it does not exist
+# TODO: edit an existing group if MGID has changed
 getent group metabase > /dev/null 2>&1
 group_exists=$?
-if [ $group_exists ]; then
+if [ $group_exists -ne 0 ]; then
     addgroup -g $MGID -S metabase
 fi
 
 # create the user if it does not exist
+# TODO: edit an existing user if MGID has changed
 id -u metabase > /dev/null 2>&1
 user_exists=$?
 if [[ $user_exists -ne 0 ]]; then
     adduser -D -u $MUID -G metabase metabase
 fi
 
-# this is to avoid running creating non-root DB files at the root of the filesystem
-# while still making them easy to find for DB export when migrating from H2 to other application DBs
-
-db_file=${MB_DB_FILE:-/app/metabase.db}
-db_alias=/metabase.db
-export MB_DB_FILE=$db_file
-chown metabase:metabase /app
-touch $db_file
-chown metabase:metabase $db_file
-if [[ ! -f $db_alias ]]; then
-    ln -s $db_file $db_alias
+db_file=${MB_DB_FILE:-/metabase.db}
+
+# In order to run metabase as a non-root user in docker, we need to handle various
+# cases where we where previously ran as root and have an existing database that
+# consists of a bunch of files, that are owned by root, sitting in a directory that
+# may only be writable by root. It's not safe to simply change the ownership or
+# permissions of an unknown directory that may be a volume mounted on the host, so
+# we will need to detect this and make a place that is going to be safe to set
+# permissions on.
+
+# So first some preliminary checks:
+
+# 1. Does this container have an existing H2 database file?
+# 2. or an existing H2 database in it's own directory,
+# 3. or neither?
+
+
+# is there a pre-existing files only database without a metabase specific directory?
+if ls $db_file\.* > /dev/null 2>&1; then
+    db_exists=true
+else
+    db_exists=false
+fi
+# is it an old style file
+if [[ -d "$db_file" ]]; then
+    db_directory=true
+else
+    db_directory=false
+fi
+
+# If the db exits, and it's just some files in a shared directory we could do
+# serious damage to peoples home or /tmp directories if we where to set the
+# permissions on that directory to allow metabase to create db-lock and db-part
+# file there. To keep them safe we make a new directory with the same name and
+# move the db file into the new directory. If we where passed the name of a
+# directory rather than a specific file, then we are safe to set permissions on
+# that directory so there is no need to move anything.
+
+# an example file would look like /tmp/metabase.db/metabase.db.mv.db
+new_db_dir=$(dirname $db_file)/$(basename $db_file)
+
+if [[ $db_exists = "true" && ! $db_directory = "true" ]]; then
+    mkdir $new_db_dir
+    mv $db_file\.* $new_db_dir/
+fi
+
+# and for the new install case we create the directory
+if [[ $db_exists = "false" && $db_directory = "false" ]]; then
+    mkdir $new_db_dir
 fi
 
+# the case where the DB exists and is a directory, there is nothing to do
+# so nothing happens here. This will be the normal case.
+
+# next we tell metabase use the files we just moved into the directory
+# or create the files in that directory if they don't exist.
+export MB_DB_FILE=$new_db_dir/$(basename $db_file)
+
+# TODO: print big scary warning if they are configuring an ephemeral instance
+
+chown metabase:metabase $new_db_dir $new_db_dir/* 2>/dev/null  # all that fussing makes this safe
+
 # Setup Java Options
 JAVA_OPTS="${JAVA_OPTS} -Dlogfile.path=target/log -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -server"
 
-- 
GitLab