ci / bun-nix (pull_request) Successful in 28s
ci / docs-drift (pull_request) Successful in 30s
ci / web (pull_request) Successful in 1m14s
ci / docs-site (pull_request) Successful in 1m15s
ci / rust-arm64 (pull_request) Successful in 2m11s
apple / swift (pull_request) Successful in 2m11s
apple / distribute (pull_request) Skipped
apple / screenshots (pull_request) Skipped
ci / rust (pull_request) Successful in 5m47s
android / android (pull_request) Successful in 6m31s
nix / flake (pull_request) Successful in 6m35s
windows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (pull_request) Successful in 2m52s
windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (pull_request) Successful in 6m15s
The workflow-level pins closed the bootstrap path only. On the normal path the bun that gets vendored into the published .deb/.rpm comes from the builder image, and every image still installed it with the upstream installer piped into bash — so the script still chose bytes that ship to users. rust-ci and fedora-rpm now take the same pinned, SHA-256-checked bun-v1.3.14 asset the workflows do; arch-ci takes bun from pacman, which verifies package signatures. Same class, found while sweeping and worse than the cited sites: five images fetched sccache over a version-pinned URL with no integrity check at all. sccache is RUSTC_WRAPPER for every binary we ship — it can serve poisoned object files straight into a signed package, which is the position the review called the highest-leverage in a build. Download, verify against upstream's published sum, then extract. packaging/flatpak/build-flatpak.sh took flatpak-cargo-generator.py from a mutable master, the same fetch flatpak.yml just pinned; both now name the same commit and sum, so the local build and CI agree. Arch note: bun rides the existing -Syu transaction rather than a later layer. A separate layer resolves against the DB baked into the CACHED -Syu layer, and Arch mirrors carry only current versions, so a cache-hit rebuild months on would fail to fetch a package the stale snapshot names. None of this takes effect until the images are rebuilt: docker.yml's `builders` job keys on the git tree hash of ci/, so this re-keys the whole family. Until then the workflow bun pins sit behind `command -v bun ||` and short-circuit against the image's baked bun. rustup's own installer is left piped, as apple.yml already does — pinning rustup-init is a separate decision, and the same argument reaches every image at once.
94 lines
6.6 KiB
Docker
94 lines
6.6 KiB
Docker
# Arch CI builder: base-devel + every dependency arch.yml's two makepkg legs used to
|
|
# pacman-install per run (~1 GB of mirror traffic each time) + bun + sccache + nodejs
|
|
# (JS actions exec node INSIDE the job container — the same lesson as android-ci).
|
|
# Content-keyed and rebuilt only when the ci/ tree changes (docker.yml `builders`).
|
|
#
|
|
# docker build -f ci/arch-ci.Dockerfile -t punktfunk-arch-ci ci
|
|
#
|
|
# ROLLING-RELEASE TRADEOFF, on purpose: packages now build against the Arch snapshot
|
|
# from the last image rebuild instead of a fresh -Syu per run. That is the same staleness
|
|
# the gamescope cache already embraces ("a stale binary against newer system libs is the
|
|
# same risk the distro's own package carries between rebuilds"), and any ci/ edit — or
|
|
# bumping the date in this line (refreshed: 2026-08-08) — re-keys and re-snapshots it.
|
|
#
|
|
# ⚠ That staleness has a sharp edge, and 2026-08-08 is why the date above moved: this snapshot is
|
|
# what decides which FFmpeg the HOST links, and arch.yml deliberately runs no -Syu, so the builder
|
|
# stayed frozen on ffmpeg 8 (libavcodec 62) even after Arch shipped 2:9.0-5 (libavcodec 63) to
|
|
# every user. A canary built from the old snapshot therefore CANNOT satisfy the soname dep that
|
|
# packaging/arch/PKGBUILD now derives from the link (libavcodec.so=62-64 against a box that has
|
|
# 63-64), so it would simply refuse to install rather than start. Re-keying this image is the step
|
|
# that makes the ffmpeg-9 bump actually reach the package — a Cargo.toml bump alone does nothing
|
|
# here. Whenever Arch moves to an FFmpeg major, bump the date in the same commit.
|
|
#
|
|
# ⚠ AND KNOW WHY THAT WAS NOT ENOUGH: bumping this date only helps once docker.yml has actually
|
|
# republished the image, and nothing sequences the two workflows. v0.25.0 was tagged four minutes
|
|
# after the ffmpeg-9 merge, so the release build still pulled the FFmpeg-8 `:latest` and published
|
|
# a punktfunk-host that no up-to-date Arch box could install — which blocks the user's ENTIRE
|
|
# `pacman -Syu`, not just our package. arch.yml therefore no longer trusts this image on that one
|
|
# axis: it compares the builder's libav sonames against the repos before building (and `-Syu`s
|
|
# itself if they differ), and refuses to publish anything a pristine-db `pacman -U --print` says
|
|
# is unsatisfiable. This file staying current is still the CHEAP path — those guards are the
|
|
# backstop, not the plan.
|
|
FROM docker.io/library/archlinux:base-devel
|
|
|
|
# One transaction: the main build/runtime deps (first list) + the gamescope companion's
|
|
# deps (second list) — both copied verbatim from what arch.yml installed in-job, where
|
|
# they now no-op as `--needed` guards.
|
|
# vulkan-headers rides the first list only because arch.yml's copy does; the package it actually
|
|
# serves is the gamescope companion (packaging/gamescope/PKGBUILD makedepends). punktfunk itself
|
|
# needs no system Vulkan headers — pyrowave-sys bindgens its own vendored copy and ash dlopens the
|
|
# loader — but arch.yml builds gamescope with `makepkg -d`, so an absent makedepend would not be
|
|
# reported as a missing dependency, only as a compile failure. Keep it.
|
|
RUN pacman -Syu --noconfirm --needed \
|
|
git nodejs rust clang cmake ninja nasm pkgconf python vulkan-headers \
|
|
gtk4 libadwaita sdl3 ffmpeg pipewire wayland libxkbcommon opus libei \
|
|
mesa libglvnd unzip libarchive \
|
|
glslang libcap libdrm libinput libx11 libxcomposite libxdamage libxext \
|
|
libxmu libxrender libxres libxtst libxxf86vm libavif libdecor \
|
|
hwdata luajit seatd sdl2-compat vulkan-icd-loader \
|
|
xcb-util-errors xcb-util-wm xorg-xwayland \
|
|
meson glm wayland-protocols benchmark libxcursor \
|
|
# mold: link-phase accelerator (sccache cannot cache linking). makepkg links the release
|
|
# host, client, worker and tray on every arch.yml run. Wired via cargo-config-mold.toml
|
|
# below. It does NOT affect the gamescope companion leg — that is meson + its own linker,
|
|
# and its `-static-libstdc++` link is untouched.
|
|
mold \
|
|
# bun builds the punktfunk-web console + the punktfunk-scripting runner AND is vendored as
|
|
# their runtime (PF_WITH_WEB=1 / PF_WITH_SCRIPTING=1) — so these bytes end up inside the
|
|
# package arch.yml signs and publishes. Arch ships bun in [extra], so take the
|
|
# pacman-signed package (pacman verifies package signatures by default) instead of piping
|
|
# bun.sh's installer into root's shell, which would be upstream code choosing them. Same
|
|
# call as arch.yml's bootstrap guard. It rides THIS transaction rather than a later layer
|
|
# on purpose: -Syu refreshes the db in the same step that installs, so a cache-hit rebuild
|
|
# can never resolve bun against a stale snapshot the mirrors no longer carry.
|
|
bun \
|
|
&& pacman -Scc --noconfirm \
|
|
&& bun --version
|
|
|
|
# Shared compile cache: jobs set RUSTC_WRAPPER=sccache (backend = RustFS S3 on the LAN,
|
|
# see .gitea/workflows — the env lives there so dev use of this image stays uncached).
|
|
# Checked by SHA-256, like the bun pin: sccache is RUSTC_WRAPPER, so it sits in front of every
|
|
# rustc invocation that produces a SHIPPED binary. Bump SCCACHE_VERSION and SCCACHE_SHA together —
|
|
# upstream publishes the sum as <asset>.tar.gz.sha256 next to the release asset.
|
|
ARG SCCACHE_VERSION=0.10.0
|
|
ARG SCCACHE_SHA=1fbb35e135660d04a2d5e42b59c7874d39b3deb17de56330b25b713ec59f849b
|
|
RUN curl -fsSL -o /tmp/sccache.tar.gz \
|
|
"https://github.com/mozilla/sccache/releases/download/v${SCCACHE_VERSION}/sccache-v${SCCACHE_VERSION}-x86_64-unknown-linux-musl.tar.gz" \
|
|
&& echo "${SCCACHE_SHA} /tmp/sccache.tar.gz" | sha256sum -c - \
|
|
&& tar -xzf /tmp/sccache.tar.gz --wildcards --strip-components=1 -C /usr/local/bin '*/sccache' \
|
|
&& rm -f /tmp/sccache.tar.gz \
|
|
&& sccache --version
|
|
|
|
# CARGO_HOME is declared here only so this image agrees with what arch.yml already sets at job
|
|
# level (and so `cargo` finds the config below when the image is used by hand). The workflow still
|
|
# passes CARGO_HOME explicitly across the `sudo -u builder env …` boundary, which strips ambient
|
|
# env — that is why the C/C++ sccache wiring has to be re-exported there by name while THIS file,
|
|
# being a file, crosses the boundary for free.
|
|
ENV CARGO_HOME=/usr/local/cargo
|
|
RUN mkdir -p /usr/local/cargo && chmod -R a+w /usr/local/cargo
|
|
|
|
# Link x86_64 with mold — see cargo-config-mold.toml's header for the rustflags traps, and
|
|
# rust-ci.Dockerfile for why the `mold --version` assertion sits next to the COPY.
|
|
COPY cargo-config-mold.toml /usr/local/cargo/config.toml
|
|
RUN mold --version && test -r /usr/local/cargo/config.toml
|