From 598e8d335f281a6d84ec568c958743deffecdaab Mon Sep 17 00:00:00 2001 From: mhoennig Date: Tue, 1 Sep 2026 08:02:08 +0200 Subject: [PATCH] rootfs build: anchor the tar excludes to the archive root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --exclude=sys matched every path component named sys anywhere in the tree — GNU tar applies slash-less patterns to all components — and so silently dropped usr/share/go-1.24/src/internal/runtime/sys from the archive, breaking every go build in the sandbox with 'package internal/runtime/sys is not in std'. The excludes are now anchored (./proc, ./sys, ./dev), so only the top-level mountpoints stay out. Co-Authored-By: Claude Fable 5 --- tools/build-bwrap-rootfs.sh | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/build-bwrap-rootfs.sh b/tools/build-bwrap-rootfs.sh index 5b1a5fe..264cb3a 100755 --- a/tools/build-bwrap-rootfs.sh +++ b/tools/build-bwrap-rootfs.sh @@ -25,10 +25,15 @@ # - Only the final `tar --zstd` writes to stdout; every build step is # redirected to stderr, so the archive coming out of `docker run` is pure. # -# Usage: build-bwrap-rootfs.sh [--release trixie] [--mirror URL] [--out path] -# --release Debian release/architecture tail, default "trixie" -# --mirror apt mirror for debootstrap, default http://deb.debian.org/debian -# --out output archive path, default ./werkator-buildenv-.tar.zst +# Usage: build-bwrap-rootfs.sh [--release trixie] [--mirror URL] [--out path] [--pkgs-extra "PKG..."] +# --release Debian release/architecture tail, default "trixie" +# --mirror apt mirror for debootstrap, default http://deb.debian.org/debian +# --out output archive path, default ./werkator-buildenv-.tar.zst +# --pkgs-extra additional apt packages on top of the base list, e.g. +# "golang-go nodejs npm" for Go and Node builds. Name the +# archive after its content (--out): the bwrap runtime keys the +# unpacked environment by the archive SOURCE PATH, so a changed +# content needs a changed name to take effect. # set -euo pipefail @@ -45,11 +50,13 @@ usage() { release="trixie" out="" +pkgs_extra="" while [ $# -gt 0 ]; do case "$1" in --release) release="${2:?missing value for --release}"; shift 2 ;; --mirror) mirror="${2:?missing value for --mirror}"; shift 2 ;; --out) out="${2:?missing value for --out}"; shift 2 ;; + --pkgs-extra) pkgs_extra="${2:?missing value for --pkgs-extra}"; shift 2 ;; -*) die "unknown option: $1" ;; *) usage ;; esac @@ -64,6 +71,7 @@ command -v docker >/dev/null 2>&1 || die "docker is required to build the rootfs # curl/unzip/xz-utils/zstd for the Gradle wrapper and general build hygiene. # Keep this list additive — project-specific tooling goes on top of this base. PKGS="openjdk-21-jdk git ca-certificates locales procps file curl unzip xz-utils zstd" +[ -z "$pkgs_extra" ] || PKGS="$PKGS $pkgs_extra" # The chroot step runs inside the freshly debootstrapped rootfs; passed into # the container as base64 so no nested heredoc corrupts the piped script. @@ -98,7 +106,7 @@ chmod +x /b/rootfs/inner.sh chroot /b/rootfs /bin/bash /inner.sh umount /b/rootfs/proc; umount /b/rootfs/sys; umount /b/rootfs/dev exec 1>&3 -tar --zstd --exclude=proc --exclude=sys --exclude=dev -C /b/rootfs -cf - . +tar --zstd --anchored --exclude=./proc --exclude=./sys --exclude=./dev -C /b/rootfs -cf - . ' | base64 -w0)" echo "building ${release} rootfs (downloads packages, takes a while; log below)..."