Files
kimai2/.docker/entrypoint.sh
Kevin Papst 31a8f887a5 Release 2.58 (#5952)
* bump version
* fix formatting locale reset after embedded controller sub-requests (#5944)
* fix GHSA-c6w6-57jj-62vh
* fix GHSA-m492-gv72-xvxj
* fix GHSA-jr9p-4h4j-6c58
* make sure to only use JS logic to call API endpoints
* fixes GHSA-r8vr-m544-qh4h
* make sure to only use JS logic to call API endpoints
* fix GHSA-rw46-qg69-vg6h
* fix GHSA-pj8j-p4g4-4vw8 - prevent kimai from rendering images via markdown
* fix GHSA-pj8j-p4g4-4vw8 - use a safe network client to prevent SSRF via images
* fix GHSA-xv4r-4885-gwpg
* fix GHSA-pgcc-vfmc-7cw5 - move GET routes to API with POST method to prevent CSRF
* fix tooltip survives page reload
* updated wizard images
* split wizard and password reset subscriber into two classes
* relax upper php limit
* added zizmor workflow scans and apply findings
* user permissions <name>_other_profile  now respect teams
* move all linting steps to new job
* updated docker image version names
* use .env.local for storing APP_SECRET
* improve build order and use given tag as ref for checkout, not default main branch
* improved APP_SECRET handling, see entrypoint.sh
* use local code for building the image for more flexibility, added dockerignore
2026-05-25 15:39:47 +02:00

159 lines
5.4 KiB
Bash
Executable File

#!/bin/bash -x
KIMAI=$(cat /opt/kimai/version.txt)
echo $KIMAI
function waitForDB() {
# Parse sql connection data
DATABASE_USER=$(awk -F '[/:@]' '{print $4}' <<< "$DATABASE_URL")
DATABASE_PASS=$(awk -F '[/:@]' '{print $5}' <<< "$DATABASE_URL")
DATABASE_HOST=$(awk -F '[/:@]' '{print $6}' <<< "$DATABASE_URL")
DATABASE_PORT=$(awk -F '[/:@]' '{print $7}' <<< "$DATABASE_URL")
DATABASE_BASE=$(awk -F '[/?]' '{print $4}' <<< "$DATABASE_URL")
re='^[0-9]+$'
if ! [[ $DATABASE_PORT =~ $re ]] ; then
DATABASE_PORT=3306
fi
echo "Wait for database connection ..."
until php /dbtest.php "$DATABASE_HOST" "$DATABASE_BASE" "$DATABASE_PORT" "$DATABASE_USER" "$DATABASE_PASS"; do
echo Checking DB: $?
sleep 3
done
echo "Connection established"
}
function handleStartup() {
# set mem limits and copy in custom logger config
if [ -z "$memory_limit" ]; then
memory_limit=512M
fi
sed -i "s/memory_limit.*/memory_limit=$memory_limit/g" /usr/local/etc/php/php.ini
cp /assets/monolog.yaml /opt/kimai/config/packages/monolog.yaml
if [ -z "$USER_ID" ]; then
USER_ID=$(id -u www-data)
fi
if [ -z "$GROUP_ID" ]; then
GROUP_ID=$(id -g www-data)
fi
# if group doesn't exist
if grep -w "$GROUP_ID" /etc/group &>/dev/null; then
echo Group already exists
else
echo www-kimai:x:"$GROUP_ID": >> /etc/group
grpconv
fi
# if user doesn't exist
if id "$USER_ID" &>/dev/null; then
echo User already exists
else
echo www-kimai:x:"$USER_ID":"$GROUP_ID":www-kimai:/var/www:/usr/sbin/nologin >> /etc/passwd
pwconv
fi
if [ -e /use_apache ]; then
export APACHE_RUN_USER=$(id -nu "$USER_ID")
# This doesn't _exactly_ run as the specified GID, it runs as the GID of the specified user but WTF
export APACHE_RUN_GROUP=$(id -ng "$USER_ID")
export APACHE_PID_FILE=/var/run/apache2/apache2.pid
export APACHE_RUN_DIR=/var/run/apache2
export APACHE_LOCK_DIR=/var/lock/apache2
export APACHE_LOG_DIR=/var/log/apache2
export LANG=C
elif [ -e /use_fpm ]; then
sed -i "s/user = .*/user = $USER_ID/g" /usr/local/etc/php-fpm.d/www.conf
sed -i "s/group = .*/group = $GROUP_ID/g" /usr/local/etc/php-fpm.d/www.conf
echo "Setting fpm to run as ${USER_ID}:${GROUP_ID}"
else
echo "Error, unknown server type"
fi
}
function prepareKimai() {
# These are idempotent, so we can run them on every start-up
/opt/kimai/bin/console -n kimai:install
if [ ! -z "$ADMINPASS" ] && [ ! -a "$ADMINMAIL" ]; then
/opt/kimai/bin/console kimai:user:create admin "$ADMINMAIL" ROLE_SUPER_ADMIN "$ADMINPASS"
fi
echo "$KIMAI" > /opt/kimai/var/installed
echo "Kimai is ready"
}
function ensureAppSecret() {
# GHSA-jr9p-4h4j-6c58
# Make sure the container never runs with the publicly-known default APP_SECRET.
# If the user provided their own value (via -e APP_SECRET=...) it is kept untouched.
# Otherwise a unique secret is generated once and persisted below var/data, which
# is the directory mounted as a named volume in the documented Docker setup, so it
# stays stable across container restarts and re-creations.
#
# Disable xtrace around all reads/writes of APP_SECRET so the secret never appears
# in container logs. The braces around `set +x` keep the disable command itself
# from being traced.
{ set +x; } 2>/dev/null
local SECRET_FILE=/opt/kimai/var/data/.appsecret
local ENV_LOCAL=/opt/kimai/.env.local
# Always remove any prior .env.local before deciding which secret applies.
# This prevents a stale auto-generated value from lingering after a user
# later sets APP_SECRET via docker env / compose. It is regenerated below
# in the auto-secret path; in the user-provided path it stays absent so
# the real env var remains the single source of truth.
rm -f "$ENV_LOCAL"
if [ -n "$APP_SECRET" ] && [ "$APP_SECRET" != "change_this_to_something_unique" ]; then
set -x
return
fi
if [ -s "$SECRET_FILE" ]; then
APP_SECRET=$(cat "$SECRET_FILE")
echo "APP_SECRET: using persisted auto-generated secret"
else
mkdir -p "$(dirname "$SECRET_FILE")"
APP_SECRET=$(php -r 'echo bin2hex(random_bytes(32));')
( umask 077 && echo "$APP_SECRET" > "$SECRET_FILE" )
chown "$USER_ID:$GROUP_ID" "$SECRET_FILE"
echo "APP_SECRET: generated a new unique secret, persisted to var/data volume"
fi
export APP_SECRET
# Mirror the resolved secret into .env.local so Symfony's Dotenv picks up
# the right value when commands are run via `docker exec` (which does not
# inherit the entrypoint's exported env). .env.local is Symfony's official
# override file and is loaded before .env. Rewritten on every container
# start; the source of truth is the persisted SECRET_FILE above.
( umask 077 && echo "APP_SECRET=$APP_SECRET" > "$ENV_LOCAL" )
# The PHP runtime (apache/php-fpm) runs as $USER_ID:$GROUP_ID and must be
# able to read .env.local; the entrypoint itself runs as root, so the file
# would otherwise be 0600 root:root and unreadable to the web user, causing
# Symfony's Dotenv to throw PathException at boot.
chown "$USER_ID:$GROUP_ID" "$ENV_LOCAL"
set -x
}
function runServer() {
# Just while I'm fixing things
/opt/kimai/bin/console kimai:reload --env="$APP_ENV"
chown -R $USER_ID:$GROUP_ID /opt/kimai/var
if [ -e /use_apache ]; then
exec /usr/sbin/apache2 -D FOREGROUND
elif [ -e /use_fpm ]; then
exec php-fpm
else
echo "Error, unknown server type"
fi
}
waitForDB
handleStartup
ensureAppSecret
prepareKimai
runServer