diff --git a/ToolboxStack/output/toolbox-base/Dockerfile b/ToolboxStack/output/toolbox-base/Dockerfile index a78283e..4c4d233 100644 --- a/ToolboxStack/output/toolbox-base/Dockerfile +++ b/ToolboxStack/output/toolbox-base/Dockerfile @@ -57,6 +57,7 @@ RUN ln -sf /usr/bin/fdfind /usr/local/bin/fd \ && ln -sf /usr/bin/batcat /usr/local/bin/bat # ROOT: Install Gitea tea CLI (system-wide) +SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN curl -fsSL "https://dl.gitea.io/tea/${TEA_VERSION}/tea-${TEA_VERSION}-linux-amd64" -o /tmp/tea \ && curl -fsSL "https://dl.gitea.io/tea/${TEA_VERSION}/tea-${TEA_VERSION}-linux-amd64.sha256" -o /tmp/tea.sha256 \ && sed -n 's/ .*//p' /tmp/tea.sha256 | awk '{print $1 " /tmp/tea"}' | sha256sum -c - \ @@ -70,27 +71,32 @@ ENV LANG=en_US.UTF-8 \ LC_ALL=en_US.UTF-8 # ROOT: Install Starship prompt (system-wide) +SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN curl -fsSL https://starship.rs/install.sh | sh -s -- -y -b /usr/local/bin # Install aqua package manager (manages additional CLI tooling) +SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN curl -sSfL https://raw.githubusercontent.com/aquaproj/aqua-installer/v2.3.1/aqua-installer | AQUA_ROOT_DIR=/usr/local/share/aquaproj-aqua bash \ && ln -sf /usr/local/share/aquaproj-aqua/bin/aqua /usr/local/bin/aqua # Install mise for runtime management (no global toolchains pre-installed) +SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN curl -sSfL https://mise.jdx.dev/install.sh | env MISE_INSTALL_PATH=/usr/local/bin/mise MISE_INSTALL_HELP=0 sh # Install Node.js via mise to enable npm package installation +SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN mise install node@22.13.0 && mise global node@22.13.0 # Create non-root user with matching UID/GID for host mapping # Check if user/group already exists and handle appropriately -RUN if getent passwd "${USER_ID}" >/dev/null; then \ +RUN set -eux; \ + if getent passwd "${USER_ID}" >/dev/null; then \ existing_user="$(getent passwd "${USER_ID}" | cut -d: -f1)"; \ echo "User with UID ${USER_ID} already exists: ${existing_user}" >&2; \ + elif ! getent group "${GROUP_ID}" >/dev/null; then \ + groupadd --gid "${GROUP_ID}" "${USERNAME}"; \ + useradd --uid "${USER_ID}" --gid "${GROUP_ID}" --shell /usr/bin/zsh --create-home "${USERNAME}"; \ else \ - if ! getent group "${GROUP_ID}" >/dev/null; then \ - groupadd --gid "${GROUP_ID}" "${USERNAME}"; \ - fi \ useradd --uid "${USER_ID}" --gid "${GROUP_ID}" --shell /usr/bin/zsh --create-home "${USERNAME}"; \ fi @@ -101,6 +107,9 @@ RUN chown -R "${USER_ID}:${GROUP_ID}" "/home/${USERNAME}" USER ${USERNAME} WORKDIR /home/${USERNAME} +# Ensure the workspace directory exists with proper permissions +RUN mkdir -p /workspace && chmod 755 /workspace + # NON-ROOT: Install mise runtime manager for toolbox user RUN curl -sSfL https://mise.jdx.dev/install.sh | sh @@ -166,9 +175,8 @@ RUN mise exec -- npm install -g bats@1.11.0 && mise reshim # NON-ROOT: Install BATS testing framework from source (baked into image) RUN git clone https://github.com/bats-core/bats-core.git /tmp/bats-core \ - && cd /tmp/bats-core \ - && git checkout v1.11.0 \ - && ./install.sh "$HOME/.local" \ + && git -C /tmp/bats-core checkout v1.11.0 \ + && /tmp/bats-core/install.sh "$HOME/.local" \ && rm -rf /tmp/bats-core # Prepare workspace directory with appropriate ownership @@ -178,6 +186,8 @@ RUN mkdir -p /workspace \ # Remove sudo to ensure no root escalation is possible at runtime RUN apt-get remove -y sudo 2>/dev/null || true && apt-get autoremove -y 2>/dev/null || true && rm -rf /var/lib/apt/lists/* 2>/dev/null || true +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + ENV SHELL=/usr/bin/zsh \ AQUA_GLOBAL_CONFIG=/home/${USERNAME}/.config/aquaproj-aqua/aqua.yaml \ PATH=/home/${USERNAME}/.local/share/aquaproj-aqua/bin:/home/${USERNAME}/.local/share/mise/shims:/home/${USERNAME}/.local/bin:${PATH} @@ -244,19 +254,21 @@ ENV LANG=en_US.UTF-8 \ LC_ALL=en_US.UTF-8 # ROOT: Create user/group structure +SHELL ["/bin/bash", "-o", "pipefail", "-c"] # First clean up any existing user/group with the same ID -RUN if getent passwd "${USER_ID}" >/dev/null; then \ +RUN set -eux; \ + if getent passwd "${USER_ID}" >/dev/null; then \ existing_user="$(getent passwd "${USER_ID}" | cut -d: -f1)"; \ userdel --remove "${existing_user}"; \ - fi \ - && if getent group "${GROUP_ID}" >/dev/null; then \ + fi; \ + if getent group "${GROUP_ID}" >/dev/null; then \ groupdel "$(getent group "${GROUP_ID}" | cut -d: -f1)"; \ - fi \ + fi; \ # Create the group and user - && groupadd --gid "${GROUP_ID}" "${USERNAME}" \ - && useradd --uid "${USER_ID}" --gid "${GROUP_ID}" --shell /usr/bin/zsh --create-home "${USERNAME}" \ + groupadd --gid "${GROUP_ID}" "${USERNAME}"; \ + useradd --uid "${USER_ID}" --gid "${GROUP_ID}" --shell /usr/bin/zsh --create-home "${USERNAME}"; \ # Ensure proper ownership of home directory - && chown -R "${USER_ID}:${GROUP_ID}" "/home/${USERNAME}" + chown -R "${USER_ID}:${GROUP_ID}" "/home/${USERNAME}" # ROOT: Copy the complete user environment from the installer stage COPY --from=installer --chown=${USER_ID}:${GROUP_ID} /home/${USERNAME} /home/${USERNAME} @@ -265,6 +277,7 @@ COPY --from=installer --chown=${USER_ID}:${GROUP_ID} /home/${USERNAME} /home/${U RUN mkdir -p /workspace && chown "${USER_ID}:${GROUP_ID}" /workspace # ROOT: Install system-wide tools (tea and starship) which were in the source image +SHELL ["/bin/bash", "-o", "pipefail", "-c"] RUN curl -fsSL "https://dl.gitea.io/tea/${TEA_VERSION}/tea-${TEA_VERSION}-linux-amd64" -o /tmp/tea \ && curl -fsSL "https://dl.gitea.io/tea/${TEA_VERSION}/tea-${TEA_VERSION}-linux-amd64.sha256" -o /tmp/tea.sha256 \ && sed -n 's/ .*//p' /tmp/tea.sha256 | awk '{print $1 " /tmp/tea"}' | sha256sum -c - \ @@ -281,6 +294,8 @@ ENV PATH=/home/${USERNAME}/.local/share/aquaproj-aqua/bin:/home/${USERNAME}/.loc ENV SHELL=/usr/bin/zsh \ AQUA_GLOBAL_CONFIG=/home/${USERNAME}/.config/aquaproj-aqua/aqua.yaml +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + # FINAL USER: Switch to toolbox user for runtime USER ${USERNAME} WORKDIR /workspace