fix(linux/build): run derivative-maker as unprivileged builder user (M1.1)
Some checks failed
Build SilverMetal Linux ISO (reproducibility-gated) / build-and-verify (push) Failing after 1m14s

Run #4251 advanced past checkout and into derivative-maker, then died
immediately:

    ERROR: This must NOT be run as root (sudo)!
    ERROR: Exiting ./derivative-maker with non-zero exit code 1.
           Errors Detected: 0. Execution Time: 00:00:00.

Kicksecure's derivative-maker explicitly refuses to run as root — it
expects a regular user with passwordless sudo and uses sudo internally
for the privileged operations (debootstrap, mksquashfs, chroot mounts).
Our minimal debian-slim builder image had a `builder` user (uid 1000)
but no sudo, no sudoers entry, and the container ran as root.

Aligns with the upstream Kicksecure container pattern at
linux/build/derivative-maker/docker/derivative-maker-docker-setup
(uses USER=user with `${USER} ALL=(ALL) NOPASSWD:ALL`).

Changes:
- Dockerfile.builder: install `sudo` (and `fakeroot` while we're here —
  upstream sanity-tests pulls this in via apt at build time, but having
  it baked avoids a snapshot.debian.org round-trip every run); add
  passwordless sudoers entry for builder; correct the misleading
  comment that claimed root was needed.
- New scripts/build-inner.sh: the inner derivative-maker invocation
  pulled out of build.sh's heredoc. Once we needed to drop privileges
  via runuser, the nested-heredoc / nested-quoting situation became
  unmaintainable; a regular script with normal quoting is far cleaner.
- build.sh: inner heredoc now just chowns the workspace to builder and
  runuser's into build-inner.sh. ${REPO_ROOT} and ${BUILD_DIR} continue
  to be forwarded into the container via -e.
- build.sh: BUILDER_IMAGE digest re-pinned to sha256:f8f0db37…1bedc
  (rebuilt and pushed natively on 10.0.0.51 — never on the WSL/aarch64
  dev box, see reference_silvermetal_runner.md memory).

Verified: bash -n on both scripts; image builds and pushes cleanly.
Pushing this commit triggers a fresh CI run that will exercise it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-07 11:09:42 +01:00
parent 1d0e58739c
commit b20e568b19
3 changed files with 68 additions and 30 deletions

View File

@@ -53,6 +53,7 @@ RUN set -eux; \
debootstrap \
diffoscope-minimal \
dosfstools \
fakeroot \
git \
gnupg \
isolinux \
@@ -61,15 +62,21 @@ RUN set -eux; \
reprepro \
rsync \
squashfs-tools \
sudo \
syslinux-common \
xorriso; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*
# Non-root user for the parts of the build that don't need privilege.
# live-build itself still needs root inside the container for chroot/mount,
# so build.sh runs the container as root; this user exists for diagnostic
# tooling and matches uid 1000 to play nicely with bind mounts.
RUN useradd --uid 1000 --create-home --shell /bin/bash builder
# 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