diff --git a/Dockerfile b/Dockerfile index 446a290..f2e1718 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,7 @@ FROM ubuntu:24.04 RUN apt-get update && apt-get install -y \ curl \ git \ + gosu \ python3 \ python3-pip \ python3-venv \ @@ -18,15 +19,6 @@ RUN wget -q -O google-chrome.deb https://dl.google.com/linux/direct/google-chrom && apt-get install -y ./google-chrome.deb \ && rm google-chrome.deb -# Create a new non-root user and group. -# NOTE: It is important that a non-root user is used because otherwise the -# Chrome Driver fails with: "User data directory is already in use" -# https://github.com/SeleniumHQ/selenium/issues/15327#issuecomment-2688613182 -RUN groupadd -r html2print && useradd -r -m -g html2print html2print - -# Grant the new user sudo privileges. -RUN echo "html2print ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/html2print - # Create a virtual environment in the user's home directory. RUN python3 -m venv /opt/venv @@ -47,9 +39,14 @@ RUN if [ "$HTML2PRINT_SOURCE" = "pypi" ]; then \ fi; \ chmod -R 777 /opt/venv; -USER html2print +# Remove the default 'ubuntu' user. +RUN userdel -r ubuntu 2>/dev/null || true + +# Allow updating the UID/GID dynamically at runtime +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh # Set the working directory to the user's home directory. WORKDIR /data -ENTRYPOINT ["/bin/bash"] +ENTRYPOINT ["/entrypoint.sh"] diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..86b2ddf --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +# This custom entrypoint script is needed for creating a container user with +# a host's UID/GUI which enables sharing of the files between the container +# and the host. +# NOTE: It is important that a non-root user is used because otherwise the +# Chrome Driver fails with: "User data directory is already in use" +# https://github.com/SeleniumHQ/selenium/issues/15327#issuecomment-2688613182 + +set -e + +# Ensure we have the environment variables +if [ -z "$HOST_UID" ] || [ -z "$HOST_GID" ]; then + echo "HOST_UID and HOST_GID must be set!" + exit 1 +fi + +echo "html2print/docker: running a Docker container entrypoint." +echo "html2print/docker: ensuring html2print user with UID=$HOST_UID and GID=$HOST_GID exists" + +# Check if a user with this UID already exists (e.g., "ubuntu") +EXISTING_USER=$(getent passwd "$HOST_UID" | cut -d: -f1) + +if [ -n "$EXISTING_USER" ]; then + echo "error: html2print/docker: detected a wrong user: '$EXISTING_USER'. Ensure that any default users are removed from the Dockerfile. This entrypoint script is supposed to create a new user 'html2print'." + exit 1 +else + # Ensure the group exists. + EXISTING_GROUP=$(getent group "$HOST_GID" | cut -d: -f1) + if [ -z "$EXISTING_GROUP" ]; then + echo "html2print/docker: creating new group html2print with GID=$HOST_GID" + groupadd -g "$HOST_GID" html2print + else + echo "html2print/docker: group with GID=$HOST_GID already exists: $EXISTING_GROUP, reusing it." + fi + + # Create the user. + echo "html2print/docker: creating new user html2print with UID=$HOST_UID" + useradd -m -u "$HOST_UID" -g "$HOST_GID" -s /bin/bash html2print + + # Give the user root privileges. Useful for debugging. + echo "html2print ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/html2print +fi + +echo "html2print/docker: show created user info:" +id html2print + +# Run as the correct user. If no command is provided, run a shell. +if [ $# -eq 0 ]; then + echo "html2print/docker: no command provided, opening an interactive shell." + exec gosu html2print /bin/bash +else + # Otherwise, run the provided command. + exec gosu html2print "$@" +fi diff --git a/tasks.py b/tasks.py index 4aff1a3..86a6162 100644 --- a/tasks.py +++ b/tasks.py @@ -296,7 +296,6 @@ def run_docker( command_argument = ( f'/bin/bash -c "{command}"' if command is not None else "" ) - entry_point_argument = '--entrypoint=""' if command_argument else "" run_invoke( context, @@ -305,8 +304,8 @@ def run_docker( --name html2print --rm -it - -v "$(pwd):/data" - {entry_point_argument} + -e HOST_UID=$(id -u) -e HOST_GID=$(id -g) + -v "$(pwd):/data:rw" {image} {command_argument} """, @@ -326,6 +325,6 @@ def test_docker(context, image: str = "html2print:latest"): context, image=image, command=( - "cd tests/integration/01_hello_world && html2print print --debug index.html /data/output/index.pdf && cat /tmp/chromedriver.log" + "cd tests/integration/01_hello_world && html2print print index.html /data/output/index.pdf" ), )