diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-18 20:28:09 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-18 20:28:09 +0200 |
| commit | fe4ba63c0a12d9c914acbb0332d96924810b393b (patch) | |
| tree | 4f889e79106689245884b34a0c82a44c89dd58a7 /docker/Dockerfile | |
| parent | 8b0e632526d9504c5c0e09bab72ab83db1c46f9b (diff) | |
build(docker): add pinned dev and docs images
garmin-otp/dev: Ubuntu 22.04 (pinned by digest; the simulator needs
WebKitGTK 4.0), apt packages from a dated snapshot.ubuntu.com mirror,
OpenJDK 17, Xvfb/openbox/noVNC for the headless simulator, the
connect-iq-sdk-manager CLI v0.8.4 checked against its release SHA-256,
and Python tools installed from a hash-locked requirements file.
garmin-otp/docs: Node 22 (pinned by digest), Debian snapshot packages,
markdownlint-cli2 and mermaid-cli from package-lock.json, and the
headless Chrome build pinned by Puppeteer.
Locks only use releases published before 2026-10-01. The Garmin SDK,
device files and the developer key are never baked into an image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docker/Dockerfile')
| -rw-r--r-- | docker/Dockerfile | 109 |
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 |
