From 4957de3b799026c1777178f1c5393cbd7e3a2043 Mon Sep 17 00:00:00 2001 From: bkellam Date: Wed, 5 Nov 2025 16:10:40 -0800 Subject: [PATCH] make non-root optional and configurable via the --user param --- Dockerfile | 46 +++++++++++++++++++++++---------------------- entrypoint.sh | 52 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 62 insertions(+), 36 deletions(-) diff --git a/Dockerfile b/Dockerfile index 80514f1a..ce01bd4d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -188,24 +188,24 @@ RUN apk add --no-cache git ca-certificates bind-tools tini jansson wget supervis ARG UID=1500 ARG GID=1500 -# To run as non-root, the user must be part of postgres, redis and node groups +# 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 && \ - chown -R sourcebot /app && \ mkdir /var/log/sourcebot && \ chown sourcebot /var/log/sourcebot -COPY --chown=sourcebot:sourcebot package.json yarn.lock* .yarnrc.yml public.pem ./ -COPY --chown=sourcebot:sourcebot .yarn ./.yarn +COPY package.json yarn.lock* .yarnrc.yml public.pem ./ +COPY .yarn ./.yarn # Configure zoekt -COPY --chown=sourcebot:sourcebot vendor/zoekt/install-ctags-alpine.sh . +COPY vendor/zoekt/install-ctags-alpine.sh . RUN ./install-ctags-alpine.sh && rm install-ctags-alpine.sh -RUN mkdir -p ${DATA_CACHE_DIR} && chown -R sourcebot ${DATA_CACHE_DIR} -COPY --chown=sourcebot:sourcebot --from=zoekt-builder \ +RUN mkdir -p ${DATA_CACHE_DIR} +COPY --from=zoekt-builder \ /cmd/zoekt-git-index \ /cmd/zoekt-indexserver \ /cmd/zoekt-mirror-github \ @@ -218,18 +218,17 @@ COPY --chown=sourcebot:sourcebot --from=zoekt-builder \ /usr/local/bin/ # Copy all of the things -COPY --chown=sourcebot:sourcebot --from=web-builder /app/packages/web/public ./packages/web/public -COPY --chown=sourcebot:sourcebot --from=web-builder /app/packages/web/.next/standalone ./ -COPY --chown=sourcebot:sourcebot --from=web-builder /app/packages/web/.next/static ./packages/web/.next/static +COPY --from=web-builder /app/packages/web/public ./packages/web/public +COPY --from=web-builder /app/packages/web/.next/standalone ./ +COPY --from=web-builder /app/packages/web/.next/static ./packages/web/.next/static -COPY --chown=sourcebot:sourcebot --from=backend-builder /app/node_modules ./node_modules -COPY --chown=sourcebot:sourcebot --from=backend-builder /app/packages/backend ./packages/backend - -COPY --chown=sourcebot:sourcebot --from=shared-libs-builder /app/node_modules ./node_modules -COPY --chown=sourcebot:sourcebot --from=shared-libs-builder /app/packages/db ./packages/db -COPY --chown=sourcebot:sourcebot --from=shared-libs-builder /app/packages/schemas ./packages/schemas -COPY --chown=sourcebot:sourcebot --from=shared-libs-builder /app/packages/shared ./packages/shared +COPY --from=backend-builder /app/node_modules ./node_modules +COPY --from=backend-builder /app/packages/backend ./packages/backend +COPY --from=shared-libs-builder /app/node_modules ./node_modules +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 # Fixes git "dubious ownership" issues when the volume is mounted with different permissions to the container. RUN git config --global safe.directory "*" @@ -239,14 +238,17 @@ RUN mkdir -p /run/postgresql && \ chown -R postgres:postgres /run/postgresql && \ chmod 775 /run/postgresql -COPY --chown=sourcebot:sourcebot supervisord.conf /etc/supervisor/conf.d/supervisord.conf -COPY --chown=sourcebot:sourcebot prefix-output.sh ./prefix-output.sh +# 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 --chown=sourcebot:sourcebot entrypoint.sh ./entrypoint.sh +COPY entrypoint.sh ./entrypoint.sh RUN chmod +x ./entrypoint.sh - -USER sourcebot +# Default to root user, but can be overridden at runtime with --user flag +# No USER directive = runs as root by default EXPOSE 3000 ENV PORT=3000 diff --git a/entrypoint.sh b/entrypoint.sh index 14fdb908..0f8ec7ed 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., @@ -82,10 +94,14 @@ 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_D\ATA_DIR...\e[0m" + echo -e "\e[34m[Info] Initializing database at $DATABASE_DATA_DIR...\e[0m" mkdir -m 0750 -p $DATABASE_DATA_DIR - - initdb -D "$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" + fi fi # Create the redis data directory if it doesn't exist @@ -181,8 +197,13 @@ 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 - postgres -D "$DATABASE_DATA_DIR" & - until pg_isready -h localhost -p 5432 -d sourcebot -U postgres; do + 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 @@ -191,13 +212,14 @@ if [ "$DATABASE_EMBEDDED" = "true" ]; then if ! pgrep -x "postgres" > /dev/null; then echo "postgres failed to run" exit 1 - break - fi + fi done - - # 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 + + 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 doesn't EXISTING_DB=$(psql -U postgres -tAc "SELECT 1 FROM pg_database WHERE datname = 'sourcebot'") @@ -214,8 +236,10 @@ 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 -mkdir -p /var/log/sourcebot +# Create the log directory if it doesn't exist +if [ ! -d "/var/log/sourcebot" ]; then + mkdir -m 0750 -p /var/log/sourcebot +fi # Run supervisord -exec supervisord -c /etc/supervisor/conf.d/supervisord.conf +exec supervisord -c /etc/supervisor/conf.d/supervisord.conf \ No newline at end of file