Files
SilverMetal/linux/build/docker/Dockerfile.builder
SysAdmin 7058fb775c
Some checks failed
Build SilverMetal Linux ISO (reproducibility-gated) / build-and-verify (push) Failing after 2m20s
fix(linux/build): add systemctl no-op shim for the build container (M1.1)
Run #4257 cleared sanity-tests entirely (sq-git verification of every
submodule signature: ; tag/uncommitted relaxation: ) and reached
1200_prepare-build-machine, where it died:

    + sudo systemctl daemon-reload
    sudo: systemctl: command not found
    ERROR detected in script!: ././build-steps.d/1200_prepare-build-machine

derivative-maker assumes systemd is PID 1 on the build host. Upstream's
own container (linux/build/derivative-maker/docker/) runs
systemd-as-init via an entrypoint that masks irrelevant units and
declares its own. We don't want that surgery for M1.1 — it pulls in
cgroup mounts, --cgroupns=host, and a much bigger debugging surface.

Shim approach instead: install /usr/local/bin/systemctl that logs the
attempt to stderr and exits 0. /usr/local/bin precedes /usr/bin in
both default $PATH and sudo's secure_path, so it satisfies any
systemctl call regardless of whether the real binary later gets pulled
in by a package install. Standard pattern for systemd-aware Debian
build scripts in transient containers.

Risk if it doesn't suffice: the shim makes daemon-reload / restart /
mask calls succeed, but doesn't actually run any service. If a later
build step depends on (say) approx actually being up to serve cached
debs, we'll see the next failure and decide whether to escalate to
real systemd-in-container or skip the relevant build step.

Changes:
- Dockerfile.builder: add the shim with a brief log line to stderr;
  comment block documents the trade-off.
- build.sh: BUILDER_IMAGE digest re-pinned to sha256:70f160ab…5460
  (built natively on 10.0.0.51, shim verified working with
  `docker run … systemctl daemon-reload` returning 0).

Verified: shim emits "systemctl-shim: daemon-reload" to stderr and
exits 0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 11:45:13 +01:00

112 lines
4.9 KiB
Ruby

# SilverMetal Linux — reproducible-build runner image.
#
# This image is the "build host" for the ISO. Pinning it by digest is the
# only thing keeping host-toolchain drift out of the reproducibility gate, so
# do NOT replace the FROM line with a tag-only reference.
#
# Build & push (run from repo root):
# docker build \
# -f linux/build/docker/Dockerfile.builder \
# -t docker-registry:5000/silvermetal-builder:<commit> \
# -t docker-registry:5000/silvermetal-builder:latest \
# linux/build/docker
# docker push docker-registry:5000/silvermetal-builder:<commit>
#
# To bump the base image: replace the digest, rebuild, push, update
# BUILDER_IMAGE in linux/build/scripts/build.sh, run a full reproducibility
# check, commit all four changes together.
# debian:trixie-slim — pinned by digest.
# Resolved 2026-05-07 via `docker pull debian:trixie-slim` on the runner host.
# Trixie (Debian 13) is what the pinned derivative-maker tag expects; its
# 1100_sanity-tests reads /etc/os-release and exits if the codename is
# anything other than `trixie`. Upstream's own derivative-maker/docker/
# Dockerfile uses the same FROM. Bumping this requires rebuilding +
# pushing the silvermetal-builder image AND updating BUILDER_IMAGE in
# linux/build/scripts/build.sh in the same commit.
FROM debian:trixie-slim@sha256:cedb1ef40439206b673ee8b33a46a03a0c9fa90bf3732f54704f99cb061d2c5a
# Reproducibility-friendly apt configuration.
ENV DEBIAN_FRONTEND=noninteractive \
LC_ALL=C.UTF-8 \
LANG=C.UTF-8 \
SOURCE_DATE_EPOCH=0
# Pinned package versions. These come from the same snapshot.debian.org
# timestamp as the ISO build, so a Dockerfile rebuild against that snapshot
# produces the same toolchain bit-for-bit. The actual snapshot URL is
# substituted at build time via --build-arg APT_SNAPSHOT_URL=...
ARG APT_SNAPSHOT_URL="https://snapshot.debian.org/archive/debian/20260415T000000Z"
ARG APT_SECURITY_SNAPSHOT_URL="https://snapshot.debian.org/archive/debian-security/20260415T000000Z"
# Two-phase install:
# 1. Use the base image's default mirror to seed ca-certificates so HTTPS
# to snapshot.debian.org works. (slim images don't ship CA bundles.)
# 2. Pin sources.list to the snapshot and install the actual toolchain.
# The first phase touches deb.debian.org without a pin; that's fine because
# nothing it installs ends up in the final ISO — only the toolchain installed
# in phase 2 does, and that is fully snapshot-pinned.
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends ca-certificates; \
rm -f /etc/apt/sources.list.d/*; \
printf 'deb [check-valid-until=no] %s trixie main\n' "$APT_SNAPSHOT_URL" > /etc/apt/sources.list; \
printf 'deb [check-valid-until=no] %s trixie-security main\n' "$APT_SECURITY_SNAPSHOT_URL" >> /etc/apt/sources.list; \
apt-get -o Acquire::Check-Valid-Until=false update; \
apt-get install -y --no-install-recommends \
debootstrap \
diffoscope-minimal \
dosfstools \
fakeroot \
git \
gnupg \
gpg-agent \
isolinux \
live-build \
mtools \
reprepro \
rsync \
sequoia-chameleon-gnupg \
sequoia-git \
sq \
sqop \
sqv \
squashfs-tools \
sudo \
syslinux-common \
xorriso; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*
# systemctl no-op shim.
# derivative-maker's build steps call `sudo systemctl daemon-reload` /
# `systemctl restart approx` / etc. as part of host-machine preparation,
# assuming systemd is PID 1 on the build host. Upstream's own container
# image runs systemd-in-container; we don't, so any real systemctl call
# would fail. The shim returns success for every invocation and logs
# what was attempted, which is the standard pattern for running
# systemd-aware build scripts in transient containers without actual
# systemd. /usr/local/bin precedes /usr/bin in both default $PATH and
# sudo's secure_path, so this masks any real systemctl that might land
# later via package install.
RUN printf '%s\n' '#!/bin/sh' \
'# systemctl no-op shim for systemd-less build containers.' \
'# Logs the attempt to stderr and returns success.' \
'echo "systemctl-shim: $*" >&2' \
'exit 0' \
> /usr/local/bin/systemctl \
&& chmod 0755 /usr/local/bin/systemctl
# Non-root user for derivative-maker.
# Kicksecure's derivative-maker explicitly refuses to run as root and uses
# sudo internally for its privileged operations (debootstrap, mksquashfs,
# chroot mounts). build.sh chowns the workspace to this user inside the
# container, then runuser's to it before invoking derivative-maker.
# uid 1000 is conventional and plays nicely with bind mounts of files
# created by other Linux tools.
RUN useradd --uid 1000 --create-home --shell /bin/bash builder \
&& echo 'builder ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/builder \
&& chmod 440 /etc/sudoers.d/builder
WORKDIR /work