aboutsummaryrefslogtreecommitdiff
path: root/docker/Dockerfile
diff options
context:
space:
mode:
Diffstat (limited to 'docker/Dockerfile')
-rw-r--r--docker/Dockerfile109
1 files changed, 109 insertions, 0 deletions
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..7d691d5
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,109 @@
+# syntax=docker/dockerfile:1
+#
+# garmin-otp/dev: the toolchain image for this project.
+#
+# Everything that builds, tests or runs the watch app happens in a container
+# made from this image (README section 15). The image deliberately does NOT
+# contain the Garmin Connect IQ SDK, the device files or your developer key:
+# * Garmin's licence does not allow redistributing the SDK, so `make sdk`
+# downloads it at runtime into the project's .cache/ folder, after you
+# accept the licence yourself.
+# * The developer key is generated by `make key` into .cache/keys/.
+#
+# Reproducibility: the base image is pinned by digest, Ubuntu packages come
+# from a dated snapshot of the archive, the SDK manager CLI is checked against
+# its release checksum, and Python packages install from a lock file with
+# hashes (docker/requirements.txt).
+
+ARG UBUNTU_IMAGE=ubuntu@sha256:0a9887931b0e38af2e3487ed39e29436b0535c4f3f52e57745baaf79d1898956
+FROM ${UBUNTU_IMAGE}
+
+# Dated snapshot of the Ubuntu archive (https://snapshot.ubuntu.com). Changing
+# this date is the only way the Ubuntu package versions change.
+ARG UBUNTU_SNAPSHOT=20261001T000000Z
+# connect-iq-sdk-manager-cli, Apache-2.0: https://github.com/lindell/connect-iq-sdk-manager-cli
+ARG SDKMGR_VERSION=0.8.4
+ARG SDKMGR_SHA256=5d57b8f9cfcd02d3b3f48e19d6daca0480e4c6f627926f15d8617ef8a6f57e0b
+# Your user and group IDs, so files written into the bind-mounted project
+# folder belong to you (see the user setup at the end).
+ARG UID=1000
+ARG GID=1000
+
+LABEL project=garmin-otp \
+ org.opencontainers.image.title="garmin-otp/dev" \
+ org.opencontainers.image.description="Connect IQ build, test and simulator toolchain (Garmin SDK not included)"
+
+ENV DEBIAN_FRONTEND=noninteractive \
+ LANG=C.UTF-8 \
+ LC_ALL=C.UTF-8 \
+ TZ=UTC
+
+# Step 1: CA certificates, so apt can reach the HTTPS-only snapshot mirror.
+# They come from the regular archive; apt verifies every package against the
+# archive's signing keys, so this bootstrap step is integrity-checked too.
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates \
+ && rm -rf /var/lib/apt/lists/*
+
+# Step 2: switch apt to the dated snapshot and install the toolchain.
+# openjdk-17-jre-headless monkeyc (the Monkey C compiler runs on Java)
+# libwebkit2gtk-4.0-37, libgtk-3-0, the Connect IQ simulator (GTK + WebKitGTK 4.0,
+# libusb-1.0-0, libsm6, libsecret, which is why the base is Ubuntu 22.04: 24.04
+# dbus-x11, fonts-dejavu-core no longer ships WebKitGTK 4.0)
+# xvfb, openbox virtual display and a window manager, so the
+# simulator runs headless and its window can be
+# found for screenshots
+# x11vnc, novnc, websockify optional live view in your browser (make sim)
+# xdotool, x11-utils, imagemagick scripted input and screenshots for UI tests
+# python3, python3-venv Python tools (test reports, reference encoders)
+# make, openssl, unzip, curl, jq, build helpers and developer-key generation
+# procps, file
+RUN printf '%s\n' \
+ "deb https://snapshot.ubuntu.com/ubuntu/${UBUNTU_SNAPSHOT} jammy main universe" \
+ "deb https://snapshot.ubuntu.com/ubuntu/${UBUNTU_SNAPSHOT} jammy-updates main universe" \
+ "deb https://snapshot.ubuntu.com/ubuntu/${UBUNTU_SNAPSHOT} jammy-security main universe" \
+ > /etc/apt/sources.list \
+ && apt-get update \
+ && apt-get install -y --no-install-recommends \
+ openjdk-17-jre-headless \
+ libwebkit2gtk-4.0-37 libgtk-3-0 libusb-1.0-0 libsm6 libsecret-1-0 dbus-x11 \
+ fonts-dejavu-core \
+ xvfb openbox x11vnc novnc websockify xdotool x11-utils imagemagick \
+ python3 python3-venv \
+ make openssl unzip curl jq procps file \
+ && rm -rf /var/lib/apt/lists/*
+
+# Step 3: the SDK manager CLI (downloads the SDK and device files for `make sdk`),
+# verified against the SHA-256 published with the release.
+RUN curl -fsSL -o /tmp/sdkmgr.tgz \
+ "https://github.com/lindell/connect-iq-sdk-manager-cli/releases/download/v${SDKMGR_VERSION}/connect-iq-sdk-manager-cli_${SDKMGR_VERSION}_Linux_x86_64.tar.gz" \
+ && echo "${SDKMGR_SHA256} /tmp/sdkmgr.tgz" | sha256sum --check --strict - \
+ && tar -xzf /tmp/sdkmgr.tgz -C /usr/local/bin connect-iq-sdk-manager \
+ && mkdir -p /usr/local/share/doc/connect-iq-sdk-manager \
+ && tar -xzf /tmp/sdkmgr.tgz -C /usr/local/share/doc/connect-iq-sdk-manager LICENSE \
+ && rm /tmp/sdkmgr.tgz
+
+# Step 4: Python tools in a virtual environment: exact versions, hashes, wheels only.
+COPY requirements.txt /opt/garmin-otp/requirements.txt
+RUN python3 -m venv /opt/venv \
+ && /opt/venv/bin/pip install --no-cache-dir --disable-pip-version-check \
+ --require-hashes --only-binary :all: -r /opt/garmin-otp/requirements.txt
+ENV PATH=/opt/venv/bin:${PATH}
+
+# Step 5: the container-side scripts are not baked in. They live in the
+# project (docker/scripts/, mounted at /work), so they are versioned with the
+# code and a script change never needs an image rebuild.
+ENV PATH=/work/docker/scripts:${PATH}
+
+# Step 6: an unprivileged user with your UID/GID. Containers also run with
+# `--user`, but Java takes its home directory from /etc/passwd, and the Garmin
+# tools keep the SDK and device files under ~/.Garmin. At runtime /home/dev is
+# replaced by the project's .cache/home folder, so all of that stays inside the
+# project and disappears with `make nuke`.
+RUN groupadd --non-unique --gid "${GID}" dev \
+ && useradd --non-unique --uid "${UID}" --gid "${GID}" --home-dir /home/dev \
+ --create-home --shell /bin/bash dev
+
+USER dev
+ENV HOME=/home/dev
+WORKDIR /work