Use Ubuntu arm64 static Qt builder

ober

da1a81c970ce58cf9cb50a3a940eb9fe7670a5d2

diff --git a/.dockerignore b/.dockerignore
index cfad2ad..bb9d3bf 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -6,7 +6,7 @@ build
 test-artifacts
 gui-snapshots.tar.gz
 jerboa-browser
-jerboa-browser-static-qt-linux-amd64.tar.gz
+jerboa-browser-static-qt-linux-*.tar.gz
 *.boot
 *.so
 *.dylib
diff --git a/.gitignore b/.gitignore
index 99a9dd8..4d41fb0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,7 @@ build/
 
 # Native binary + Jerboa build artifacts (see build-binary.ss / Makefile)
 /jerboa-browser
-jerboa-browser-static-qt-linux-amd64.tar.gz
+jerboa-browser-static-qt-linux-*.tar.gz
 .bcache/
 .jerboa/bin/
 dist/
diff --git a/Dockerfile.qt b/Dockerfile.qt
index 14a5afb..6e270d2 100644
--- a/Dockerfile.qt
+++ b/Dockerfile.qt
@@ -8,20 +8,27 @@
 # and WebEngine resource files.
 #
 # Usage:
-#   podman build -f Dockerfile.qt -t jerboa-browser-qt-builder .
+#   podman build --platform linux/arm64 -f Dockerfile.qt -t jerboa-browser-qt-builder .
 #   id=$(podman create jerboa-browser-qt-builder)
 #   podman cp $id:/out/jerboa-browser-static-qt.tar.gz . && podman rm $id
 
-ARG JERBOA_IMAGE=docker.io/jerboa21/jerboa
-FROM ${JERBOA_IMAGE} AS builder
+ARG BASE_IMAGE=docker.io/library/ubuntu:24.04
+FROM ${BASE_IMAGE} AS builder
+
+ARG JERBOA_VERSION=v0.2.3
 
 ENV DEBIAN_FRONTEND=noninteractive
+ENV PATH=/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
 
 RUN apt-get update && apt-get install -y --no-install-recommends \
+    bash \
     ca-certificates \
     cmake \
+    curl \
     file \
     g++ \
+    git \
+    gzip \
     libgl1-mesa-dev \
     libudev-dev \
     make \
@@ -29,28 +36,25 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
     pkg-config \
     qt6-base-dev \
     qt6-webengine-dev \
-    cargo \
-    rustc \
+    tar \
+    xz-utils \
     && rm -rf /var/lib/apt/lists/*
 
-RUN if ! command -v git >/dev/null 2>&1; then \
-      apt-get update && apt-get install -y --no-install-recommends git && \
-      rm -rf /var/lib/apt/lists/*; \
-    fi && \
-    if ! command -v jerbuild >/dev/null 2>&1; then \
-      git clone --depth 1 https://git.sr.ht/~lisp/jerboa /tmp/jerboa && \
-      cd /tmp/jerboa && \
-      JERBOA_HOME=/tmp/jerboa SCHEME="$(command -v scheme)" sh support/build-jerbuild.sh && \
-      install -m 0755 jerbuild /usr/local/bin/jerbuild; \
-    fi && \
-    command -v scheme && \
+RUN curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal && \
+    rustup default stable && \
+    cargo --version && \
+    rustc -vV
+
+COPY support/ensure-jerboa.sh /tmp/ensure-jerboa.sh
+RUN sh /tmp/ensure-jerboa.sh "$JERBOA_VERSION" /usr/local/bin && \
     command -v jerbuild && \
+    jerbuild --version && \
     jerbuild --jerboa-home >/dev/null
 
 COPY . /src
 WORKDIR /src
 
-RUN BUNDLE_QT=1 SCHEME="$(command -v scheme)" bash packaging/linux/build-tarball.sh && \
+RUN BUNDLE_QT=1 bash packaging/linux/build-tarball.sh && \
     mkdir -p /out && \
     cp qt-webengine/build/jerboa-browser-*-linux-*.tar.gz \
       /out/jerboa-browser-static-qt.tar.gz && \
@@ -70,7 +74,7 @@ RUN BUNDLE_QT=1 SCHEME="$(command -v scheme)" bash packaging/linux/build-tarball
     tar xzf "$tb" -O "$bin_path" > /tmp/jerboa-browser && \
     file /tmp/jerboa-browser
 
-FROM ubuntu:24.04
+FROM ${BASE_IMAGE}
 COPY --from=builder /out/jerboa-browser-static-qt.tar.gz /out/jerboa-browser-static-qt.tar.gz
 RUN set -eux; \
     mkdir -p /tmp/check; \
diff --git a/Makefile b/Makefile
index f2caf2c..4e3ca26 100644
--- a/Makefile
+++ b/Makefile
@@ -31,11 +31,11 @@ CC ?= cc
 CARGO ?= cargo
 CARGO_AUDIT ?= $(shell command -v cargo-audit 2>/dev/null || printf '%s/.cargo/bin/cargo-audit' "$$HOME")
 PODMAN ?= podman
-PODMAN_PLATFORM ?= linux/amd64
+PODMAN_PLATFORM ?= linux/arm64
 PODMAN_BUILD_FLAGS ?=
-JERBOA_IMAGE ?= docker.io/jerboa21/jerboa
+STATIC_QT_BASE_IMAGE ?= docker.io/library/ubuntu:24.04
 STATIC_QT_IMAGE ?= jerboa-browser-qt-builder
-STATIC_QT_TARBALL ?= jerboa-browser-static-qt-linux-amd64.tar.gz
+STATIC_QT_TARBALL ?= jerboa-browser-static-qt-linux-arm64.tar.gz
 
 # Modules that use (std crypto native-rust) need libjerboa_native dlopen-able at
 # runtime — in the interpreter (jerbuild exec: tests, repl) AND in the compiled
@@ -329,9 +329,10 @@ static-qt: podman-static-qt
 
 podman-static-qt: check-podman
 	@echo "=== Building jerboa-browser Linux Qt artifact with Podman ==="
-	$(PODMAN) pull --platform $(PODMAN_PLATFORM) $(JERBOA_IMAGE)
+	$(PODMAN) pull --platform $(PODMAN_PLATFORM) $(STATIC_QT_BASE_IMAGE)
 	$(PODMAN) build $(PODMAN_BUILD_FLAGS) --platform $(PODMAN_PLATFORM) \
-	  --build-arg JERBOA_IMAGE="$(JERBOA_IMAGE)" \
+	  --build-arg BASE_IMAGE="$(STATIC_QT_BASE_IMAGE)" \
+	  --build-arg JERBOA_VERSION="$(JERBOA_VERSION)" \
 	  -f Dockerfile.qt -t $(STATIC_QT_IMAGE) .
 	@id=$$($(PODMAN) create $(STATIC_QT_IMAGE)) && \
 	  trap '$(PODMAN) rm $$id >/dev/null 2>&1 || true' EXIT INT TERM && \
diff --git a/README.md b/README.md
index e0ccb6e..b62c645 100644
--- a/README.md
+++ b/README.md
@@ -143,7 +143,7 @@ default, a protected passphrase file, or the interactive prompt.
 
 ```sh
 make binary           # the self-contained native ./jerboa-browser
-make static-qt        # bundled Linux Qt/WebEngine tarball via Podman (linux/amd64)
+make static-qt        # bundled Linux Qt/WebEngine tarball via Podman (linux/arm64)
 make vendor-yubikey   # clone https://git.sr.ht/~lisp/jerboa-yubikey into vendor/
 make yubikey-native   # build lib/libyubikey_native for direct USB YubiKey access
 make test             # (browser) suite + secure-store unit tests; also test-{keymap,…,polish}
@@ -154,14 +154,14 @@ make test-gui         # offline Qt snapshot harness (offscreen, headless)
 ```
 
 `make static-qt` mirrors the jerboa-emacs container workflow through Podman and copies out
-`jerboa-browser-static-qt-linux-amd64.tar.gz`. Because this backend is Qt
+`jerboa-browser-static-qt-linux-arm64.tar.gz`. Because this backend is Qt
 WebEngine, the artifact is a bundled Linux tarball rather than a literal
 one-file static executable. It includes the native browser binary, the
 `libjerboa_browser.so` backend, the browser vault FUSE helper, Qt
 libraries/plugins, `QtWebEngineProcess`, and WebEngine resource files.
 
-SourceHut CI publishes the latest verified Linux amd64 tarball to
-`https://lisp.srht.site/jerboa-browser/latest/jerboa-browser-linux-amd64.tar.gz`.
+SourceHut CI publishes verified Linux tarballs under architecture-specific
+artifact names.
 
 The functional suites run offscreen (`QT_QPA_PLATFORM=offscreen`) and hermetic
 (`JWB_TEST_NO_NETWORK=1`), modeled on the jerboa-emacs Qt test harness.
diff --git a/packaging/README.md b/packaging/README.md
index 41c5ee3..44827b6 100644
--- a/packaging/README.md
+++ b/packaging/README.md
@@ -97,7 +97,7 @@ Total ≈ 299 MB (dominated by QtWebEngineCore + ICU).
 ```sh
 packaging/linux/build-tarball.sh      # → qt-webengine/build/jerboa-browser-<ver>-linux-<arch>.tar.gz
 BUNDLE_QT=1 packaging/linux/build-tarball.sh
-make static-qt                        # Podman build, copies ./jerboa-browser-static-qt-linux-amd64.tar.gz
+make static-qt                        # Podman build, copies ./jerboa-browser-static-qt-linux-arm64.tar.gz
 ```
 
 The tarball always bundles the backend `libjerboa_browser.so`, the
@@ -137,6 +137,7 @@ uses an interactive terminal prompt. The packaged browser does not accept
 profile-vault secrets through process environment variables and does not embed a
 build-local fallback secret.
 
-`make static-qt` always uses `BUNDLE_QT=1` inside Podman, with the
-`docker.io/jerboa21/jerboa` image plus Ubuntu Qt WebEngine packages, and validates the
+`make static-qt` always uses `BUNDLE_QT=1` inside Podman, with an
+Ubuntu 24.04 arm64 base, the pinned Jerboa release tools, and Ubuntu Qt WebEngine
+packages. It validates the
 tarball in a clean Ubuntu stage with no Qt package installed.
diff --git a/packaging/linux/build-tarball.sh b/packaging/linux/build-tarball.sh
index 3a895b0..1f8075c 100755
--- a/packaging/linux/build-tarball.sh
+++ b/packaging/linux/build-tarball.sh
@@ -277,12 +277,13 @@ cp -f "$FUSE_SHIM" "$STAGE/lib/"
 cp -f "$YUBIKEY_NATIVE" "$STAGE/lib/"
 
 # The native binary embeds Chez + the (browser) library; build it when the
-# Jerboa toolchain is present (e.g. a developer host). CI images without Chez
-# fall back to a source package that can run `make binary` after unpacking.
+# Jerboa toolchain is present (e.g. a developer host or the static-qt container).
+# CI images without jerbuild fall back to a source package that can run
+# `make binary` after unpacking.
 HAVE_BIN=0
 HAVE_NATIVE=0
-if [ -x "$SCHEME" ]; then
-    echo "==> building the native jerboa-browser binary ($SCHEME)"
+if ( cd "$REPO" && make check-jerbuild >/dev/null 2>&1 ); then
+    echo "==> building the native jerboa-browser binary (jerbuild)"
     ( cd "$REPO" && JERBOA_HOME="$JERBOA_HOME" SCHEME="$SCHEME" make binary )
     if [ -x "$REPO/jerboa-browser" ]; then
         # The binary re-execs its embedded program from a temp file and dlopens
@@ -334,7 +335,7 @@ WRAP
         fi
     fi
 else
-    echo "==> Chez/Jerboa not found at $SCHEME — skipping the native binary"
+    echo "==> Jerboa toolchain not found — skipping the native binary"
     echo "    (staging sources; unpack, then run 'make binary' with the Jerboa toolchain installed)"
 fi