Skip to content

Commit ab5373e

Browse files
committed
Restructure Docker image from scratch
1 parent 58ad916 commit ab5373e

32 files changed

Lines changed: 1370 additions & 128 deletions

.dockleignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# [Enable Content trust for Docker] - We don't really need this much because only we both publish and pull
2+
# this image and pin the version so we can't accidentally pull unknown malicious image.
3+
CIS-DI-0005
4+
5+
# [Add HEALTHCHECK instruction to the container image] - Does not make sense for our CI image.
6+
CIS-DI-0006

.github/workflows/pull_request.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
uses: ./.github/actions/login
2222
with:
2323
user-name: ${{ vars.DOCKER_HUB_TEST_USERNAME }}
24+
# Test public repos read only token on a separate androidackee test account.
2425
token: ${{ vars.DOCKER_HUB_TEST_TOKEN }}
2526

2627
- name: Preflight checks

CHANGELOG.MD

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
11
# Changelog
22
All notable changes to this project will be documented in this file.
33

4-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
4+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [v3.0.0] - 2026-02-17
8+
### Changed
9+
- Complete rewrite of Dockerfile using multi-stage build architecture (separate stages for Java, Android SDK, Danger, Git LFS)
10+
- Danger JS installation now runs as `nonroot` user to reduce attack surface
11+
- Node.js installed from system apt packages instead of via nvm
12+
- Updated Android cmdline-tools to 14742923, platform to 36, build-tools to 36.1.0
13+
14+
### Added
15+
- Checksum verification for all downloaded artifacts (Java, Kotlin compiler, danger-kotlin)
16+
- Integration of shai-hulud supply chain attack detector for npm packages
17+
- npm scripts disabled globally to prevent supply chain attacks
18+
- Final image runs as `nonroot` user
19+
20+
### Removed
21+
- Flutter support
22+
- nvm and Node.js version management
23+
- Google Cloud CLI
24+
- Privilege escalation binaries from final image (`su`, `apt`, `apt-get`, `apt-cache`, `dpkg`, `unix_chkpwd`)
25+
726
## [v2.8.0] - 2025-12-04
827
### Changed
928
- Update danger kotlin to 1.3.4

Dockerfile

Lines changed: 225 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,238 @@
1-
FROM debian:trixie
1+
# === Global args ===
22

3-
LABEL tag="ackee-gitlab" \
4-
author="Ackee 🦄" \
5-
description="This Docker image serves as an environment for running Android builds on Gitlab CI in Ackee workspace"
3+
# == Versions ==
4+
5+
ARG ANDROID_CMDLINE_TOOLS_VERSION="14742923"
6+
ARG ANDROID_BUILD_TOOLS_VERSION="36.1.0"
7+
ARG ANDROID_PLATFORM_VERSION="36"
8+
9+
ARG DANGER_JS_VERSION="12.3.4"
10+
ARG DANGER_KOTLIN_VERSION="1.3.4"
11+
ARG DANGER_KOTLIN_CHECKSUM="sha256:232b11680cdfe50c64a6cef1d96d3cd09a857422da1e2dd0464f80c8ddb1afac"
12+
13+
# If you need to update major Java version, you will need to adjust the version in the download link as well
14+
ARG JAVA_VERSION="17.0.18_8"
15+
ARG JAVA_CHECKSUM="sha256:0c94cbb54325c40dcf026143eb621562017db5525727f2d9131a11250f72c450"
16+
17+
# Needed for danger-kotlin
18+
ARG KOTLINC_VERSION="2.2.21"
19+
ARG KOTLINC_CHECKSUM="sha256:a623871f1cd9c938946948b70ef9170879f0758043885bbd30c32f024e511714"
20+
21+
# == Others ==
22+
23+
ARG CMDLINE_TOOLS_DIR="cmdline-tools"
24+
ARG CMDLINE_TOOLS_VERSION_DIR="latest"
25+
26+
ARG DANGER_BASE_PATH="/usr/local"
27+
ARG KOTLINC_BASE_PATH="/usr/lib"
28+
29+
30+
31+
# === Stages ===
32+
33+
# == base ==
34+
35+
# Base stage that all stages inherit from. It contains common setup needed for both build and final stages.
36+
FROM dhi.io/debian-base:trixie-debian13-dev AS base
37+
38+
ARG CMDLINE_TOOLS_DIR
39+
ARG CMDLINE_TOOLS_VERSION_DIR
40+
ARG JAVA_VERSION
641

742
SHELL ["/bin/bash", "-c"]
843

9-
RUN apt update && apt install -y \
10-
curl \
11-
git \
12-
libgl1 \
13-
unzip \
14-
zip \
15-
python3 \
16-
wget \
17-
xz-utils \
18-
fontconfig \
19-
gnupg
20-
21-
RUN curl -s "https://get.sdkman.io" | bash && \
22-
source "$HOME/.sdkman/bin/sdkman-init.sh" && \
23-
sdk install java 17.0.7-oracle && \
24-
sdk use java 17.0.7-oracle
25-
26-
ENV JAVA_HOME=/root/.sdkman/candidates/java/current
27-
ENV ANDROID_HOME=/opt/android-sdk-linux
44+
ENV ANDROID_HOME="/opt/android-sdk-linux"
45+
ENV PATH="$PATH:$ANDROID_HOME/$CMDLINE_TOOLS_DIR/$CMDLINE_TOOLS_VERSION_DIR"
46+
ENV PATH="$PATH:$ANDROID_HOME/$CMDLINE_TOOLS_DIR/$CMDLINE_TOOLS_VERSION_DIR/bin"
47+
ENV PATH="$PATH:$ANDROID_HOME/platform-tools"
48+
49+
ENV JAVA_HOME="/usr/lib/jdk/$JAVA_VERSION"
2850
ENV PATH="$PATH:$JAVA_HOME/bin"
2951

30-
# Download Android SDK command line tools into $ANDROID_HOME
31-
RUN cd /opt && wget -q https://dl.google.com/android/repository/commandlinetools-linux-6858069_latest.zip -O android-sdk-tools.zip && \
32-
unzip -q android-sdk-tools.zip && mkdir -p "$ANDROID_HOME/cmdline-tools/" && mv cmdline-tools latest && mv latest/ "$ANDROID_HOME"/cmdline-tools/ && \
33-
rm android-sdk-tools.zip
52+
RUN apt update && apt install -y --no-install-recommends \
53+
git \
54+
&& rm -rf /var/lib/apt/lists/*
55+
56+
57+
58+
# == build ==
59+
60+
# Base stage for all build stages. These stages are used for building dependencies that are then
61+
# copied to the final image.
62+
FROM base AS build
63+
64+
RUN apt update && apt install -y --no-install-recommends \
65+
curl \
66+
# Needed for danger-js installation
67+
npm \
68+
unzip
69+
70+
# Disables npm preinstall, postintall and other scripts that might run when any npm package is installed,
71+
# which is usually exploited by supply chain attacks like shai-hulud
72+
RUN npm config set ignore-scripts true
73+
74+
75+
76+
# == java-installation ==
77+
78+
FROM build AS java-installation
79+
80+
ARG JAVA_CHECKSUM
81+
ARG JAVA_VERSION
82+
83+
ARG JAVA_TEMP_DIR="java"
84+
# Replace _ with + in version for download link
85+
ENV JAVA_VERSION_PLUS="${JAVA_VERSION/_/+}"
86+
ADD --checksum="$JAVA_CHECKSUM" --unpack=true \
87+
"https://github.com/adoptium/temurin17-binaries/releases/download/jdk-$JAVA_VERSION_PLUS/OpenJDK17U-jdk_x64_linux_hotspot_$JAVA_VERSION.tar.gz" \
88+
"$JAVA_TEMP_DIR"
89+
RUN mkdir -p "$JAVA_HOME" && \
90+
# Temp dir contains unpacked JDK folder, we want to move its contents to JAVA_HOME
91+
mv "$JAVA_TEMP_DIR"/*/* "$JAVA_HOME"
92+
93+
94+
95+
# == android-sdk-installation ==
96+
97+
# Installs Android SDK. Requires Java to be already installed.
98+
FROM java-installation AS android-sdk-installation
99+
100+
ARG ANDROID_BUILD_TOOLS_VERSION
101+
ARG ANDROID_CMDLINE_TOOLS_VERSION
102+
ARG ANDROID_PLATFORM_VERSION
103+
ARG CMDLINE_TOOLS_DIR
104+
ARG CMDLINE_TOOLS_VERSION_DIR
34105

35-
ENV PATH="$PATH:$ANDROID_HOME/cmdline-tools/latest:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools"
106+
WORKDIR /opt
107+
108+
ARG CMDLINE_TOOLS_ZIP="cmdline-tools.zip"
109+
ADD "https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_CMDLINE_TOOLS_VERSION}_latest.zip" \
110+
"./$CMDLINE_TOOLS_ZIP"
111+
112+
ARG CMDLINE_TOOLS_PATH="$ANDROID_HOME/$CMDLINE_TOOLS_DIR"
113+
RUN mkdir -p "$CMDLINE_TOOLS_PATH" && \
114+
unzip -q "$CMDLINE_TOOLS_ZIP" -d "$CMDLINE_TOOLS_PATH" && \
115+
mv "$CMDLINE_TOOLS_PATH/$CMDLINE_TOOLS_DIR" "$CMDLINE_TOOLS_PATH/$CMDLINE_TOOLS_VERSION_DIR"
36116

37117
# Accept licenses before installing components
38118
# License is valid for all the standard components in versions installed from this file
39119
# Non-standard components: MIPS system images, preview versions, GDK (Google Glass) and Android Google TV require separate licenses, not accepted there
40120
RUN yes | sdkmanager --licenses
41121

42-
RUN sdkmanager "platform-tools"
43-
44-
# list all platforms, sort them in descending order, take the newest 8 versions and install them
45-
RUN sdkmanager $(sdkmanager --list 2> /dev/null | grep platforms | awk -F' ' '{print $1}' | sort -nr -k2 -t- | head -8)
46-
# list all build-tools, sort them in descending order and install them
47-
RUN sdkmanager $(sdkmanager --list 2> /dev/null | grep build-tools | awk -F' ' '{print $1}' | sort -nr -k2 -t \; | uniq)
48-
49-
# setup gcloud
50-
RUN echo "deb https://packages.cloud.google.com/apt cloud-sdk main" >> /etc/apt/sources.list.d/google-cloud-sdk.list && \
51-
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor >> /etc/apt/trusted.gpg.d/cloud.google.gpg && \
52-
apt update && apt install -y google-cloud-cli && \
53-
gcloud config set component_manager/disable_update_check true
54-
55-
# nvm environment variables
56-
ENV NVM_DIR=/usr/local/nvm \
57-
NODE_VERSION=23.5.0
58-
59-
# install nvm
60-
# https://github.com/creationix/nvm#install-script
61-
RUN mkdir $NVM_DIR && \
62-
curl --silent -o- https://raw.githubusercontent.com/creationix/nvm/v0.39.7/install.sh | bash
63-
64-
RUN source $NVM_DIR/nvm.sh && \
65-
nvm install $NODE_VERSION && \
66-
nvm alias default $NODE_VERSION && \
67-
nvm use default
68-
69-
# add node and npm to path so the commands are available
70-
ENV NODE_PATH=$NVM_DIR/v$NODE_VERSION/lib/node_modules \
71-
PATH=$NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH
72-
73-
# install make which is needed in danger-kotlin install phase
74-
RUN apt update && apt install -y \
75-
make
76-
77-
# install danger-js which is needed for danger-kotlin to work
78-
RUN npm install -g danger@12.3.4
79-
80-
# install kotlin compiler
81-
RUN curl -o kotlin-compiler.zip -L https://github.com/JetBrains/kotlin/releases/download/v2.2.21/kotlin-compiler-2.2.21.zip && \
82-
unzip -d /usr/local/ kotlin-compiler.zip && \
83-
rm -rf kotlin-compiler.zip
84-
85-
# install danger-kotlin
86-
RUN git clone https://github.com/danger/kotlin.git _danger-kotlin && \
87-
cd _danger-kotlin && git checkout 1.3.4 && \
88-
make install && \
89-
cd .. && \
90-
rm -rf _danger-kotlin
91-
92-
# setup environment variables
93-
ENV PATH=$PATH:/usr/local/kotlinc/bin
94-
95-
# flutter
96-
ENV FLUTTER_CHANNEL="stable"
97-
ENV FLUTTER_VERSION="3.24.3"
98-
ENV FLUTTER_URL="https://storage.googleapis.com/flutter_infra_release/releases/$FLUTTER_CHANNEL/linux/flutter_linux_$FLUTTER_VERSION-$FLUTTER_CHANNEL.tar.xz"
99-
ENV FLUTTER_HOME="/opt/flutter"
100-
ENV FLUTTER_FILE="flutter.tar.xz"
101-
102-
RUN curl -o $FLUTTER_FILE $FLUTTER_URL \
103-
&& mkdir -p $FLUTTER_HOME \
104-
&& tar xf $FLUTTER_FILE -C /opt \
105-
&& git config --global --add safe.directory /opt/flutter \
106-
&& rm $FLUTTER_FILE
107-
108-
ENV PATH=$PATH:$FLUTTER_HOME/bin
109-
110-
RUN flutter config --no-analytics \
111-
&& flutter precache \
112-
&& yes "y" | flutter doctor --android-licenses \
113-
&& flutter doctor \
114-
&& flutter update-packages
115-
116-
# git LFS support
117-
RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash \
118-
&& apt install -y git-lfs \
119-
&& git lfs install
120-
121-
# add gitlab helper functions
122-
ENV GITLAB_CI_UTILS_VERSION=2.7.0
123-
RUN curl -o helper_functions.sh "https://raw.githubusercontent.com/AckeeDevOps/gitlab-ci-utils/$GITLAB_CI_UTILS_VERSION/scripts/helper_functions.sh" \
124-
&& curl -o android_ci_functions.sh "https://raw.githubusercontent.com/AckeeCZ/android-gitlab-ci-scripts/v1.0.0/android_ci_functions.sh" \
125-
&& echo "source helper_functions.sh" >> /etc/profile \
126-
&& echo "source android_ci_functions.sh" >> /etc/profile
127-
128-
VOLUME /root/.gradle
122+
123+
124+
# == danger-installation ==
125+
126+
FROM build AS danger-installation
127+
128+
ARG DANGER_BASE_PATH
129+
ARG DANGER_JS_VERSION
130+
ARG DANGER_KOTLIN_VERSION
131+
ARG DANGER_KOTLIN_CHECKSUM
132+
ARG KOTLINC_BASE_PATH
133+
ARG KOTLINC_CHECKSUM
134+
ARG KOTLINC_VERSION
135+
136+
# chown of directories where danger will be installed, so nonroot npm process can write there
137+
RUN chown -R nonroot:nonroot "$DANGER_BASE_PATH"
138+
# Change to nonroot user for npm install to reduce attack surface if compromised
139+
USER nonroot
140+
141+
# Install danger JS that is needed for danger-kotlin
142+
RUN npm install -g "danger@$DANGER_JS_VERSION"
143+
# Solves dockle's DKL-LI-0003 reported issue to remove unnecessary files
144+
RUN rm -f "$DANGER_BASE_PATH/lib/node_modules/danger/Dockerfile"
145+
146+
# Clone and run shai-hulud-detector script that checks for shai-hulud supply chain attacks
147+
WORKDIR /tmp
148+
RUN git clone https://github.com/Cobenian/shai-hulud-detect
149+
# Allows user to override shai-hulud detector mode. Useful for running --paranoid mode on CI, which
150+
# takes longer but is more secure and checks even for other malicious behaviour other than shai-hulud.
151+
ARG SHAI_HULUD_DETECTOR_MODE=""
152+
RUN ./shai-hulud-detect/shai-hulud-detector.sh "$SHAI_HULUD_DETECTOR_MODE" "$(npm root -g)"; \
153+
exit_code=$?; \
154+
case "$exit_code" in \
155+
# Succeed on medium-risk issues found (2)
156+
2) exit 0 ;; \
157+
# Fail on high-risk issues found (1), succeed (0) or fail with anything else
158+
*) exit "$exit_code" ;; \
159+
esac
160+
161+
# Switch back to root to finish Danger installation
162+
USER root
163+
164+
# Install Kotlin compiler
165+
ARG COMPILER_ZIP="kotlin-compiler.zip"
166+
ADD --checksum="$KOTLINC_CHECKSUM" \
167+
"https://github.com/JetBrains/kotlin/releases/download/v$KOTLINC_VERSION/kotlin-compiler-$KOTLINC_VERSION.zip" \
168+
"./$COMPILER_ZIP"
169+
RUN unzip "$COMPILER_ZIP" -d "$KOTLINC_BASE_PATH"
170+
171+
# Install danger-kotlin
172+
ADD --checksum="$DANGER_KOTLIN_CHECKSUM" --unpack=true \
173+
"https://github.com/danger/kotlin/releases/download/$DANGER_KOTLIN_VERSION/danger-kotlin-linuxX64.tar" \
174+
"$DANGER_BASE_PATH"
175+
176+
177+
178+
# == git-lfs-installation ==
179+
180+
FROM build AS git-lfs-installation
181+
182+
RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
183+
apt update && apt install -y --no-install-recommends git-lfs
184+
185+
186+
187+
# == final ==
188+
189+
# Final stage of the image build process. This is the only stage that is kept in the final image.
190+
# This should mainly copy prepared binaries from other stages.
191+
FROM base AS final
192+
193+
ARG DANGER_BASE_PATH
194+
ARG KOTLINC_BASE_PATH
195+
196+
LABEL tag="ackee-gitlab" \
197+
author="Ackee 🦄" \
198+
description="This Docker image serves as an environment for running Android builds on Gitlab CI in Ackee workspace"
199+
200+
RUN apt update && apt install -y --no-install-recommends \
201+
# Needed for danger-js
202+
nodejs \
203+
&& rm -rf /var/lib/apt/lists/*
204+
205+
COPY --from=java-installation "$JAVA_HOME" "$JAVA_HOME"
206+
207+
COPY --from=android-sdk-installation "$ANDROID_HOME" "$ANDROID_HOME"
208+
# Allows nonroot user to modify Android SDK folders, e.g. download new build tools/platforms
209+
RUN chown -R nonroot:nonroot "$ANDROID_HOME"
210+
211+
# Danger binaries
212+
ARG DANGER_BIN_PATH="$DANGER_BASE_PATH/bin"
213+
COPY --from=danger-installation "$DANGER_BIN_PATH" "$DANGER_BIN_PATH"
214+
215+
ARG DANGER_LIB_PATH="$DANGER_BASE_PATH/lib"
216+
217+
# Danger JS node_modules dependencies
218+
ARG DANGER_NODE_MODULES_PATH="$DANGER_LIB_PATH/node_modules"
219+
COPY --from=danger-installation "$DANGER_NODE_MODULES_PATH" "$DANGER_NODE_MODULES_PATH"
220+
221+
# danger-kotlin libs
222+
ARG DANGER_KOTLIN_LIB_PATH="$DANGER_LIB_PATH/danger"
223+
COPY --from=danger-installation "$DANGER_KOTLIN_LIB_PATH" "$DANGER_KOTLIN_LIB_PATH"
224+
225+
COPY --from=danger-installation "$KOTLINC_BASE_PATH" "$KOTLINC_BASE_PATH"
226+
ENV PATH="$PATH:$KOTLINC_BASE_PATH/kotlinc/bin"
227+
228+
ARG GIT_LFS_PATH="/usr/bin/git-lfs"
229+
COPY --from=git-lfs-installation "$GIT_LFS_PATH" "$GIT_LFS_PATH"
230+
RUN git lfs install
231+
232+
# Remove binaries that might allow privilege escalation
233+
RUN rm -f /bin/su
234+
RUN rm -f /usr/bin/apt /usr/bin/apt-get /usr/bin/apt-cache
235+
RUN rm -f /usr/bin/dpkg
236+
RUN rm -f /usr/sbin/unix_chkpwd
237+
238+
USER nonroot

0 commit comments

Comments
 (0)