Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ RUN apk update && apk upgrade && \
tzdata \
libedit \
libldap \
libcap && \
libcap \
su-exec && \
rm -rf /var/cache/apk/*

# Copy in the Python packages
Expand Down Expand Up @@ -206,8 +207,6 @@ RUN /venv/bin/python3 -m pip install --no-cache-dir gunicorn==23.0.0 && \
echo "pgadmin ALL = NOPASSWD: /usr/sbin/postfix start" > /etc/sudoers.d/postfix && \
echo "pgadminr ALL = NOPASSWD: /usr/sbin/postfix start" >> /etc/sudoers.d/postfix

USER 5050

# Finish up
VOLUME /var/lib/pgadmin
EXPOSE 80 443
Expand Down
26 changes: 24 additions & 2 deletions pkg/docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
#!/usr/bin/env bash
PUID=${PUID:-5050}
PGID=${PGID:-0}

if [ "$(id -u)" = "0" ]; then
# Ensure a group with the target GID exists
if ! getent group "$PGID" > /dev/null 2>&1; then
addgroup -g "$PGID" pggroup
fi

# Reassign the pgadmin user to the desired UID/GID
usermod -o -u "$PUID" -g "$PGID" pgadmin 2>/dev/null || true

# Compose su-exec command
SU_EXEC="su-exec $PUID:$PGID"
echo "pgAdmin will run as UID=$PUID, GID=$PGID"
else
SU_EXEC=""
fi

# Fixup the passwd file, in case we're on OpenShift
if ! whoami > /dev/null 2>&1; then
Expand Down Expand Up @@ -178,6 +196,10 @@ fi
# to define the Gunicorn worker timeout
TIMEOUT=$(cd /pgadmin4 && /venv/bin/python3 -c 'import config; print(config.SESSION_EXPIRATION_TIME * 60 * 60 * 24)')

if [ "$(id -u)" = "0" ]; then
chown -R "$PUID:$PGID" /run/pgadmin /var/lib/pgadmin /pgadmin4/config_distro.py /certs
fi
Comment on lines +199 to +201
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Multiple issues with the chown block.

  1. /certs may not exist when TLS is not enabled, producing a noisy error on every startup for non-TLS users.

  2. chown -R on /var/lib/pgadmin runs on every start and can be extremely slow for volumes with many files (e.g., large session/storage directories). Consider guarding with an ownership check or limiting recursion depth.

  3. Hardcoded /pgadmin4/config_distro.py — Line 58 allows overriding the config distro path via PGADMIN_CUSTOM_CONFIG_DISTRO_FILE. If a custom path is used, this chown won't cover the actual config file.

🔧 Proposed fix addressing all three points
 if [ "$(id -u)" = "0" ]; then
-    chown -R "$PUID:$PGID" /run/pgadmin /var/lib/pgadmin /pgadmin4/config_distro.py /certs
+    chown -R "$PUID:$PGID" /run/pgadmin /var/lib/pgadmin
+    chown "$PUID:$PGID" "${CONFIG_DISTRO_FILE_PATH}"
+    if [ -d /certs ]; then
+        chown -R "$PUID:$PGID" /certs
+    fi
 fi

For the /var/lib/pgadmin performance concern, a common pattern is to only recurse when ownership doesn't match:

if [ "$(stat -c '%u:%g' /var/lib/pgadmin)" != "$PUID:$PGID" ]; then
    chown -R "$PUID:$PGID" /var/lib/pgadmin
fi
🤖 Prompt for AI Agents
In `@pkg/docker/entrypoint.sh` around lines 199 - 201, The chown block should
avoid errors for missing /certs, avoid always-recursing /var/lib/pgadmin, and
honor a custom config path; update the block to: check existence of /certs
before attempting chown, check current owner of /var/lib/pgadmin (using stat)
and only run chown -R if it differs from "$PUID:$PGID" to avoid costly repeated
recursion, and replace the hardcoded /pgadmin4/config_distro.py with the
PGADMIN_CUSTOM_CONFIG_DISTRO_FILE variable (if set and the file exists) and
chown that file non-recursively; ensure all chown commands still run only when
uid is 0.


# NOTE: currently pgadmin can run only with 1 worker due to sessions implementation
# Using --threads to have multi-threaded single-process worker

Expand All @@ -192,7 +214,7 @@ else
fi

if [ -n "${PGADMIN_ENABLE_TLS}" ]; then
exec /venv/bin/gunicorn --limit-request-line "${GUNICORN_LIMIT_REQUEST_LINE:-8190}" --timeout "${TIMEOUT}" --bind "${BIND_ADDRESS}" -w 1 --threads "${GUNICORN_THREADS:-25}" --access-logfile "${GUNICORN_ACCESS_LOGFILE:--}" --keyfile /certs/server.key --certfile /certs/server.cert -c gunicorn_config.py run_pgadmin:app
exec $SU_EXEC /venv/bin/gunicorn --limit-request-line "${GUNICORN_LIMIT_REQUEST_LINE:-8190}" --timeout "${TIMEOUT}" --bind "${BIND_ADDRESS}" -w 1 --threads "${GUNICORN_THREADS:-25}" --access-logfile "${GUNICORN_ACCESS_LOGFILE:--}" --keyfile /certs/server.key --certfile /certs/server.cert -c gunicorn_config.py run_pgadmin:app
else
exec /venv/bin/gunicorn --limit-request-line "${GUNICORN_LIMIT_REQUEST_LINE:-8190}" --limit-request-fields "${GUNICORN_LIMIT_REQUEST_FIELDS:-100}" --limit-request-field_size "${GUNICORN_LIMIT_REQUEST_FIELD_SIZE:-8190}" --timeout "${TIMEOUT}" --bind "${BIND_ADDRESS}" -w 1 --threads "${GUNICORN_THREADS:-25}" --access-logfile "${GUNICORN_ACCESS_LOGFILE:--}" -c gunicorn_config.py run_pgadmin:app
exec $SU_EXEC /venv/bin/gunicorn --limit-request-line "${GUNICORN_LIMIT_REQUEST_LINE:-8190}" --limit-request-fields "${GUNICORN_LIMIT_REQUEST_FIELDS:-100}" --limit-request-field_size "${GUNICORN_LIMIT_REQUEST_FIELD_SIZE:-8190}" --timeout "${TIMEOUT}" --bind "${BIND_ADDRESS}" -w 1 --threads "${GUNICORN_THREADS:-25}" --access-logfile "${GUNICORN_ACCESS_LOGFILE:--}" -c gunicorn_config.py run_pgadmin:app
fi