From a9b1dc8bd9354973eabd72f56d82b2eab6f48d56 Mon Sep 17 00:00:00 2001 From: cirakg Date: Sun, 18 Oct 2026 20:28:09 +0200 Subject: build: add Docker-only Makefile, SDK setup and product manifest - Makefile: every target runs in a container as your UID/GID, with no capabilities, a read-only root filesystem, only the project folder mounted and no network except for image builds and `make sdk`. Serial even under `make -j`. `make nuke` removes containers, images, the dedicated buildx builder and .cache/ after confirmation. - sdk-setup.sh: agreement acceptance pinned to the hash you read, password login (never stored), SDK 9.2.0 and device download, and the login token deleted afterwards. - gen-key.sh: RSA-4096 developer key into .cache/keys, never overwritten, with backup instructions. - manifest.xml: watch-app, minApiLevel 5.0.0, no permissions, and the 72 watches with API 5.0+ and at least 512 KB for apps. - .gitignore, lint configs and CHANGELOG. Co-Authored-By: Claude Opus 5.5 --- docker/scripts/ciq-env.sh | 49 +++++++++++++++++++++++++ docker/scripts/gen-key.sh | 39 ++++++++++++++++++++ docker/scripts/sdk-setup.sh | 88 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100755 docker/scripts/ciq-env.sh create mode 100755 docker/scripts/gen-key.sh create mode 100755 docker/scripts/sdk-setup.sh (limited to 'docker') diff --git a/docker/scripts/ciq-env.sh b/docker/scripts/ciq-env.sh new file mode 100755 index 0000000..945d59a --- /dev/null +++ b/docker/scripts/ciq-env.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Shared helpers for the container scripts. Source this file; don't run it. +# +# Paths, as seen inside the container: +# /work the project folder (bind mount) +# /home/dev the project's .cache/home folder (bind mount); the Garmin +# tools keep the SDK and device files under ~/.Garmin +# /work/.cache/keys the developer key (never baked into an image) + +CIQ_HOME="${HOME}/.Garmin/ConnectIQ" +KEY_DIR="/work/.cache/keys" +DEV_KEY="${KEY_DIR}/developer_key.der" +BUILD_DIR="/work/build" + +# Print an error and stop. Used for every user-facing failure, so the message +# says what to do next instead of leaving a bare stack trace. +die() { + echo "error: $*" >&2 + exit 1 +} + +# Progress line on stderr, so stdout stays clean for machine-readable output. +log() { + echo "==> $*" >&2 +} + +# Find the SDK selected by `make sdk` and put its bin/ folder on PATH. +# Sets CIQ_SDK to the SDK root folder. +ciq_require_sdk() { + local cfg="${CIQ_HOME}/current-sdk.cfg" + [[ -f "${cfg}" ]] || die "Connect IQ SDK not installed. Run 'make sdk' first (you accept Garmin's licence and log in there)." + CIQ_SDK="$(tr -d '\r\n' < "${cfg}")" + CIQ_SDK="${CIQ_SDK%/}" + [[ -x "${CIQ_SDK}/bin/monkeyc" ]] || die "SDK folder '${CIQ_SDK}' has no bin/monkeyc. Run 'make sdk' again." + export CIQ_SDK + export PATH="${CIQ_SDK}/bin:${PATH}" +} + +# The developer key signs every build, including test builds. +ciq_require_key() { + [[ -f "${DEV_KEY}" ]] || die "No developer key at .cache/keys/developer_key.der. Run 'make key' first." +} + +# Fail early, with a pointer to `make sdk`, when a device's files are missing. +ciq_require_device() { + local device="$1" + [[ -f "${CIQ_HOME}/Devices/${device}/compiler.json" ]] \ + || die "No device files for '${device}'. Is it in manifest.xml? Then run 'make sdk' to download them." +} diff --git a/docker/scripts/gen-key.sh b/docker/scripts/gen-key.sh new file mode 100755 index 0000000..7b99863 --- /dev/null +++ b/docker/scripts/gen-key.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Generate the developer key that signs every build (README section 15.6). +# +# Output: .cache/keys/developer_key.der (PKCS#8 DER, what monkeyc wants) and +# developer_key.pem, both mode 600 and git-ignored. An existing key is never +# overwritten: the Connect IQ Store rejects updates signed with a different +# key, so replacing it by accident would strand the published app. +set -euo pipefail +# shellcheck source=ciq-env.sh +source "$(dirname "${BASH_SOURCE[0]}")/ciq-env.sh" + +umask 077 +mkdir -p "${KEY_DIR}" + +if [[ -f "${DEV_KEY}" ]]; then + log "Developer key already exists at .cache/keys/developer_key.der; leaving it untouched." + exit 0 +fi + +log "Generating a 4096-bit RSA developer key (this takes a few seconds)..." +openssl genrsa -out "${KEY_DIR}/developer_key.pem" 4096 2>/dev/null +openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt \ + -in "${KEY_DIR}/developer_key.pem" -out "${DEV_KEY}" +chmod 600 "${KEY_DIR}/developer_key.pem" "${DEV_KEY}" + +# A short fingerprint of the public key, so a backup can be recognised later. +fingerprint="$(openssl pkey -in "${KEY_DIR}/developer_key.pem" -pubout -outform DER \ + | sha256sum | cut -c1-16)" + +cat >&2 </dev/null +echo " Accepted (version ${hash})." + +echo +echo "Step 2/5: Garmin login" +if [[ -f "${TOKEN}" ]]; then + echo " Reusing the login token kept from an earlier run (KEEP_LOGIN=1)." +else + echo " Email and password go only to Garmin's sign-in page and are not stored." + echo " Accounts with two-step verification can't log in this way (see README 15.3)." + read -r -p " Garmin account email: " GARMIN_USERNAME + read -r -s -p " Password (not shown): " GARMIN_PASSWORD + echo + export GARMIN_USERNAME GARMIN_PASSWORD + if ! ${SDKMGR} login; then + unset GARMIN_USERNAME GARMIN_PASSWORD + die "Login failed. Check email and password. Two-step verification isn't supported here; see README 15.3." + fi + unset GARMIN_USERNAME GARMIN_PASSWORD + echo " Logged in." +fi + +echo +echo "Step 3/5: Connect IQ SDK ${SDK_VERSION}" +${SDKMGR} sdk set "${SDK_VERSION}" +echo " Current SDK: $(${SDKMGR} sdk current-path)" + +echo +echo "Step 4/5: device files and fonts for the products in manifest.xml" +${SDKMGR} device download --manifest "${MANIFEST}" --include-fonts + +echo +echo "Step 5/5: log out" +if [[ "${KEEP_LOGIN:-0}" == 1 ]]; then + echo " KEEP_LOGIN=1: keeping the token at .cache/home/.Garmin/ConnectIQ/token.json" +else + rm -f "${TOKEN}" + echo " Login token deleted. Run 'make sdk' again whenever new device files are needed." +fi + +device_count="$(find "${CIQ_HOME}/Devices" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)" +echo +echo "Done: SDK ${SDK_VERSION}, ${device_count} device folders, $(du -sh "${CIQ_HOME}" | cut -f1) in .cache/home." +echo "Next: 'make key' (if you have no developer key yet), then 'make test'." -- cgit v1.2.3