diff --git a/Dockerfile b/Dockerfile index ae90c8c7..ddfb2925 100644 --- a/Dockerfile +++ b/Dockerfile @@ -182,6 +182,22 @@ ENV SOURCEBOT_LOG_LEVEL=info # Sourcebot collects anonymous usage data using [PostHog](https://posthog.com/). Uncomment this line to disable. # ENV SOURCEBOT_TELEMETRY_DISABLED=1 +# Configure dependencies +RUN apk add --no-cache git ca-certificates bind-tools tini jansson wget supervisor uuidgen curl perl jq redis postgresql postgresql-contrib openssl util-linux unzip + +ARG UID=1500 +ARG GID=1500 + +# Always create the non-root user to support runtime user switching +# The container can be run as root (default) or as sourcebot user using docker run --user +RUN addgroup -g $GID sourcebot && \ + adduser -D -u $UID -h /app -S sourcebot && \ + adduser sourcebot postgres && \ + adduser sourcebot redis && \ + adduser sourcebot node && \ + mkdir /var/log/sourcebot && \ + chown sourcebot /var/log/sourcebot + COPY package.json yarn.lock* .yarnrc.yml public.pem ./ COPY .yarn ./.yarn @@ -214,9 +230,6 @@ COPY --from=shared-libs-builder /app/packages/db ./packages/db COPY --from=shared-libs-builder /app/packages/schemas ./packages/schemas COPY --from=shared-libs-builder /app/packages/shared ./packages/shared -# Configure dependencies -RUN apk add --no-cache git ca-certificates bind-tools tini jansson wget supervisor uuidgen curl perl jq redis postgresql postgresql-contrib openssl util-linux unzip - # Fixes git "dubious ownership" issues when the volume is mounted with different permissions to the container. RUN git config --global safe.directory "*" @@ -225,12 +238,19 @@ RUN mkdir -p /run/postgresql && \ chown -R postgres:postgres /run/postgresql && \ chmod 775 /run/postgresql +# Make app directory accessible to both root and sourcebot user +RUN chown -R sourcebot:sourcebot /app + COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY prefix-output.sh ./prefix-output.sh RUN chmod +x ./prefix-output.sh COPY entrypoint.sh ./entrypoint.sh RUN chmod +x ./entrypoint.sh +# Note: for back-compat cases, we do _not_ set the USER directive here. +# Instead, the user can be overridden at runtime with --user flag. +# USER sourcebot + EXPOSE 3000 ENV PORT=3000 ENV HOSTNAME="0.0.0.0" diff --git a/entrypoint.sh b/entrypoint.sh index cf90a377..22a733e3 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -5,6 +5,18 @@ set -e # Disable auto-exporting of variables set +a +# Detect if running as root +IS_ROOT=false +if [ "$(id -u)" -eq 0 ]; then + IS_ROOT=true +fi + +if [ "$IS_ROOT" = "true" ]; then + echo -e "\e[34m[Info] Running as root user.\e[0m" +else + echo -e "\e[34m[Info] Running as non-root user.\e[0m" +fi + # If a CONFIG_PATH is set, resolve the environment overrides from the config file. # The overrides will be written into variables scopped to the current shell. This is # required in case one of the variables used in this entrypoint is overriden (e.g., @@ -83,8 +95,13 @@ fi # Check if DATABASE_DATA_DIR exists, if not initialize it if [ "$DATABASE_EMBEDDED" = "true" ] && [ ! -d "$DATABASE_DATA_DIR" ]; then echo -e "\e[34m[Info] Initializing database at $DATABASE_DATA_DIR...\e[0m" - mkdir -p $DATABASE_DATA_DIR && chown -R postgres:postgres "$DATABASE_DATA_DIR" - su postgres -c "initdb -D $DATABASE_DATA_DIR" + mkdir -p $DATABASE_DATA_DIR + if [ "$IS_ROOT" = "true" ]; then + chown -R postgres:postgres "$DATABASE_DATA_DIR" + su postgres -c "initdb -D $DATABASE_DATA_DIR" + else + initdb -D "$DATABASE_DATA_DIR" -U postgres + fi fi # Create the redis data directory if it doesn't exist @@ -180,13 +197,31 @@ echo "{\"version\": \"$NEXT_PUBLIC_SOURCEBOT_VERSION\", \"install_id\": \"$SOURC # Start the database and wait for it to be ready before starting any other service if [ "$DATABASE_EMBEDDED" = "true" ]; then - su postgres -c "postgres -D $DATABASE_DATA_DIR" & + if [ "$IS_ROOT" = "true" ]; then + su postgres -c "postgres -D $DATABASE_DATA_DIR" & + else + postgres -D "$DATABASE_DATA_DIR" & + fi + until pg_isready -h localhost -p 5432 -U postgres; do echo -e "\e[34m[Info] Waiting for the database to be ready...\e[0m" sleep 1 + + # As postgres runs in the background, we must check if it is still + # running, otherwise the "until" loop will be running indefinitely. + if ! pgrep -x "postgres" > /dev/null; then + echo "postgres failed to run" + exit 1 + fi done + + if [ "$IS_ROOT" = "false" ]; then + # Running as non-root we need to ensure the postgres account is created. + psql -U postgres -tc "SELECT 1 FROM pg_roles WHERE rolname='postgres'" | grep -q 1 \ + || createuser postgres -s + fi - # Check if the database already exists, and create it if it dne + # Check if the database already exists, and create it if it doesn't exist EXISTING_DB=$(psql -U postgres -tAc "SELECT 1 FROM pg_database WHERE datname = 'sourcebot'") if [ "$EXISTING_DB" = "1" ]; then @@ -201,7 +236,7 @@ fi echo -e "\e[34m[Info] Running database migration...\e[0m" DATABASE_URL="$DATABASE_URL" yarn workspace @sourcebot/db prisma:migrate:prod -# Create the log directory +# Create the log directory if it doesn't exist mkdir -p /var/log/sourcebot # Run supervisord