From bb06e3a3f256bd1c73ab9784f4ab7bf2b8193b41 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Sat, 6 Sep 2025 00:57:22 -0700 Subject: [PATCH 01/15] [FEATURE] include a copy of musl libc in the final image Changes in file .github/workflows/Build-Bootstraper.yaml: * pass musl version to docker Changes in file dockerfile: * build musl from source * copy musl to final image Changes in file mkroot.bash: * minor tweaks --- .github/workflows/Build-Bootstraper.yaml | 2 + dockerfile | 96 ++++++++++++++++++++++-- mkroot.bash | 2 +- 3 files changed, 94 insertions(+), 6 deletions(-) diff --git a/.github/workflows/Build-Bootstraper.yaml b/.github/workflows/Build-Bootstraper.yaml index d74b8e2..b91762c 100644 --- a/.github/workflows/Build-Bootstraper.yaml +++ b/.github/workflows/Build-Bootstraper.yaml @@ -116,6 +116,7 @@ jobs: build-args: | TOYBOX_VERSION=0.8.12 TARGETARCH=${{ matrix.architecture }} + MUSL_VER=1.2.6 cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max attests: | @@ -133,6 +134,7 @@ jobs: env: SOURCE_DATE_EPOCH: ${{ needs.seed.outputs.timestamp }} TOYBOX_VERSION: "0.8.12" + TOYBOX_VERSION: "1.2.6" TARGETARCH: ${{ matrix.architecture }} - name: Export digest run: | diff --git a/dockerfile b/dockerfile index aee566a..7fc6aa9 100644 --- a/dockerfile +++ b/dockerfile @@ -3,6 +3,68 @@ ARG TOYBOX_VERSION=${TOYBOX_VERSION:-"0.8.12"} # version is passed through by Docker. # shellcheck disable=SC2154 +ARG MUSL_VER=${MUSL_VER:-"1.2.6"} +ARG MUSL_PREFIX=/usr/local/musl-llvm-staging + +# Stage 1: Build Musl +# Use MIT licensed Alpine as the base image for the build environment +# shellcheck disable=SC2154 +FROM --platform="linux/${TARGETARCH}" alpine:latest AS musl-builder + +ENV MUSL_VER=${MUSL_VER:-"1.2.6"} +ENV MUSL_PREFIX=${MUSL_PREFIX} + +RUN set -eux \ + && apk add --no-cache \ + clang \ + llvm \ + lld \ + make \ + binutils \ + curl \ + ca-certificates \ + build-base \ + gzip \ + perl \ + paxctl \ + && mkdir -p /build + +WORKDIR /build + +# Download musl +RUN set -eux \ + && curl -fsSLO https://musl.libc.org/releases/musl-${MUSL_VER}.tar.gz \ + && tar xf musl-${MUSL_VER}.tar.gz \ + && mv musl-${MUSL_VER} musl + +WORKDIR /build/musl + +# Configure, build, and install musl with shared enabled (default) using LLVM tools +RUN set -eux \ + && export CC=clang \ + && export AR=llvm-ar \ + && export RANLIB=llvm-ranlib \ + && export LD=ld.lld \ + && export LDFLAGS="-fuse-ld=lld" \ + && mkdir -p ${MUSL_PREFIX} \ + && ./configure --prefix=${MUSL_PREFIX} \ + && make -j"$(nproc)" \ + && make install + +# Ensure we have the dynamic loader and libs present (example paths) +RUN set -eux \ + && ls -l ${MUSL_PREFIX}/lib || true \ + && file ${MUSL_PREFIX}/lib/* || true + +# Strip unneeded symbols from shared objects to save space (optional) +RUN set -eux \ + && if command -v llvm-strip >/dev/null 2>&1; then \ + find ${MUSL_PREFIX}/lib -type f -name "*.so*" -exec llvm-strip --strip-unneeded {} + || true; \ + else \ + find ${MUSL_PREFIX}/lib -type f -name "*.so*" -exec strip --strip-unneeded {} + || true; \ + fi + +# Stage 2: Build toybox based filesystem # Use MIT licensed Alpine as the base image for the build environment # shellcheck disable=SC2154 FROM --platform="linux/${TARGETARCH}" alpine:latest AS builder @@ -17,6 +79,8 @@ ENV RANLIB=llvm-ranlib ENV LDFLAGS="-fuse-ld=lld" ENV BSD=/usr/include/bsd ENV LINUX=/usr/include/linux +ENV MUSL_VER=${MUSL_VER:-"1.2.6"} +ENV MUSL_PREFIX=${MUSL_PREFIX} # Install necessary packages # llvm - LLVM-apache-2 @@ -114,12 +178,34 @@ RUN /usr/bin/mkroot.bash && \ printf "root:x:0:0:root:/root:/bin/sh\n" > /output/fs/etc/passwd && \ printf "/dev/sda / ext4 defaults 0 1\n" > /output/fs/etc/fstab -# Stage 2: Create the final image +# Copy musl runtime artifacts from builder: +# - dynamic loader (ld-musl-*.so.1) +# - libmusl shared object(s) (libc.so.*) +# - crt*.o (for static linking if needed) +# - headers +COPY --from=musl-builder ${MUSL_PREFIX}/lib/ld-musl-*.so.* /output/fs/lib/ +COPY --from=musl-builder ${MUSL_PREFIX}/lib/libc.so* /output/fs/usr/lib/ +COPY --from=musl-builder ${MUSL_PREFIX}/lib/crt1.o ${MUSL_PREFIX}/lib/crti.o ${MUSL_PREFIX}/lib/crtn.o /output/fs/lib/ || true +COPY --from=musl-builder ${MUSL_PREFIX}/include /output/fs/usr/include + +# Some systems expect /lib64 -> /lib for x86_64. Create symlink if appropriate. +RUN set -eux; \ + if [ "$(uname -m)" = "x86_64" ]; then \ + [ -d /output/fs/lib64 ] || ln -s /output/fs/lib /lib64; \ + fi + +# Ensure loader has canonical name (example: /lib/ld-musl-x86_64.so.1) +RUN set -eux \ + && for f in /output/fs/lib/ld-musl-*; do \ + ln -fns "$f" /output/fs/lib/ld-musl.so.1 || true; \ + done || true + +# Stage 3: Create the final image # shellcheck disable=SC2154 FROM --platform="linux/${TARGETARCH}" scratch AS mitl-bootstrap # set inherited values -LABEL version="0.7" +LABEL version="0.8" LABEL org.opencontainers.image.title="MITL-bootstrap" LABEL org.opencontainers.image.description="Custom Bootstrap MITL image with toybox installed." LABEL org.opencontainers.image.vendor="individual" @@ -133,10 +219,10 @@ COPY --from=builder /output/fs / # Ensure toybox is reachable at /bin/toybox (symlink if needed) COPY --from=builder /output/fs/usr/bin/toybox /bin/toybox -SHELL [ "/bin/bash", "--norc", "-l", "-c" ] +SHELL [ "/bin/bash", "--norc", "-c" ] # Set the entry point to Toybox ENTRYPOINT ["/usr/bin/toybox"] ENV BASH='/bin/bash' -ENV HOSTNAME="base-builder" -CMD [ "/bin/bash", "--norc", "-l", "-c", "'exec -a bash /bin/bash -il'" ] +ENV HOSTNAME="MITL-bootstrap" +CMD [ "/bin/bash", "--norc", "-c", "'exec -a bash /bin/bash -i'" ] diff --git a/mkroot.bash b/mkroot.bash index 7ffaf23..b596d52 100755 --- a/mkroot.bash +++ b/mkroot.bash @@ -118,7 +118,7 @@ fn_host_do_cmd() { #export -f fn_host_do_cmd ; -for FILE in bin lib sbin tmp usr usr/bin usr/libexec usr/local usr/share var Users ; do +for FILE in bin lib sbin tmp usr usr/bin usr/libexec usr/local usr/share usr/include var Users ; do fn_host_do_cmd mkdir -p "${DESTDIR}/${FILE}" ; fn_host_do_cmd chmod 755 "${DESTDIR}/${FILE}" || true ; done ; From 72828a623b2b6129a73892cba53f2a9b8ae04cb9 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Sat, 6 Sep 2025 01:00:50 -0700 Subject: [PATCH 02/15] [PATCH] Oops! Fixed duplicate var name Changes in file .github/workflows/Build-Bootstraper.yaml * refactored duplicate TOYBOX_VERSION -> MUSL_VER --- .github/workflows/Build-Bootstraper.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Build-Bootstraper.yaml b/.github/workflows/Build-Bootstraper.yaml index b91762c..363bc02 100644 --- a/.github/workflows/Build-Bootstraper.yaml +++ b/.github/workflows/Build-Bootstraper.yaml @@ -134,7 +134,7 @@ jobs: env: SOURCE_DATE_EPOCH: ${{ needs.seed.outputs.timestamp }} TOYBOX_VERSION: "0.8.12" - TOYBOX_VERSION: "1.2.6" + MUSL_VER: "1.2.6" TARGETARCH: ${{ matrix.architecture }} - name: Export digest run: | From cab5c254eb36a89882bf6ebe75711912c25aa233 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Sat, 6 Sep 2025 01:06:57 -0700 Subject: [PATCH 03/15] [REVERT] downgrade to LGV musl 1.2.5 until next version is out. Changes in file .github/workflows/Build-Bootstraper.yaml: * downgrade to 1.2.5 Changes in file dockerfile: * downgrade to 1.2.5 --- .github/workflows/Build-Bootstraper.yaml | 4 ++-- dockerfile | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/Build-Bootstraper.yaml b/.github/workflows/Build-Bootstraper.yaml index 363bc02..a8b0850 100644 --- a/.github/workflows/Build-Bootstraper.yaml +++ b/.github/workflows/Build-Bootstraper.yaml @@ -116,7 +116,7 @@ jobs: build-args: | TOYBOX_VERSION=0.8.12 TARGETARCH=${{ matrix.architecture }} - MUSL_VER=1.2.6 + MUSL_VER=1.2.5 cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max attests: | @@ -134,7 +134,7 @@ jobs: env: SOURCE_DATE_EPOCH: ${{ needs.seed.outputs.timestamp }} TOYBOX_VERSION: "0.8.12" - MUSL_VER: "1.2.6" + MUSL_VER: "1.2.5" TARGETARCH: ${{ matrix.architecture }} - name: Export digest run: | diff --git a/dockerfile b/dockerfile index 7fc6aa9..e75db23 100644 --- a/dockerfile +++ b/dockerfile @@ -3,7 +3,7 @@ ARG TOYBOX_VERSION=${TOYBOX_VERSION:-"0.8.12"} # version is passed through by Docker. # shellcheck disable=SC2154 -ARG MUSL_VER=${MUSL_VER:-"1.2.6"} +ARG MUSL_VER=${MUSL_VER:-"1.2.5"} ARG MUSL_PREFIX=/usr/local/musl-llvm-staging # Stage 1: Build Musl @@ -11,7 +11,7 @@ ARG MUSL_PREFIX=/usr/local/musl-llvm-staging # shellcheck disable=SC2154 FROM --platform="linux/${TARGETARCH}" alpine:latest AS musl-builder -ENV MUSL_VER=${MUSL_VER:-"1.2.6"} +ENV MUSL_VER=${MUSL_VER:-"1.2.5"} ENV MUSL_PREFIX=${MUSL_PREFIX} RUN set -eux \ @@ -79,7 +79,7 @@ ENV RANLIB=llvm-ranlib ENV LDFLAGS="-fuse-ld=lld" ENV BSD=/usr/include/bsd ENV LINUX=/usr/include/linux -ENV MUSL_VER=${MUSL_VER:-"1.2.6"} +ENV MUSL_VER=${MUSL_VER:-"1.2.5"} ENV MUSL_PREFIX=${MUSL_PREFIX} # Install necessary packages From c29ea23fe19f9ee0edc2e85db85728ca9b3a9f86 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Sat, 6 Sep 2025 01:19:52 -0700 Subject: [PATCH 04/15] [PATCH] stability fixes Changes in file dockerfile: * improved style for stability --- dockerfile | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/dockerfile b/dockerfile index e75db23..49743a1 100644 --- a/dockerfile +++ b/dockerfile @@ -30,6 +30,11 @@ RUN set -eux \ && mkdir -p /build WORKDIR /build +ENV export CC=clang +ENV export AR=llvm-ar +ENV export RANLIB=llvm-ranlib +ENV export LD=ld.lld +ENV LDFLAGS="-fuse-ld=lld" # Download musl RUN set -eux \ @@ -40,20 +45,13 @@ RUN set -eux \ WORKDIR /build/musl # Configure, build, and install musl with shared enabled (default) using LLVM tools -RUN set -eux \ - && export CC=clang \ - && export AR=llvm-ar \ - && export RANLIB=llvm-ranlib \ - && export LD=ld.lld \ - && export LDFLAGS="-fuse-ld=lld" \ - && mkdir -p ${MUSL_PREFIX} \ - && ./configure --prefix=${MUSL_PREFIX} \ - && make -j"$(nproc)" \ - && make install +RUN mkdir -p ${MUSL_PREFIX} && \ + ./configure --prefix=${MUSL_PREFIX} && \ + make -j"$(nproc)" && \ + make install # Ensure we have the dynamic loader and libs present (example paths) -RUN set -eux \ - && ls -l ${MUSL_PREFIX}/lib || true \ +RUN ls -l ${MUSL_PREFIX}/lib || true \ && file ${MUSL_PREFIX}/lib/* || true # Strip unneeded symbols from shared objects to save space (optional) @@ -64,6 +62,7 @@ RUN set -eux \ find ${MUSL_PREFIX}/lib -type f -name "*.so*" -exec strip --strip-unneeded {} + || true; \ fi + # Stage 2: Build toybox based filesystem # Use MIT licensed Alpine as the base image for the build environment # shellcheck disable=SC2154 From 181f6a0ebdcecf3365c448873428810dbd7fcec7 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Sat, 6 Sep 2025 01:26:09 -0700 Subject: [PATCH 05/15] [PATCH] added default staging path Changes in file dockerfile: * set default of MUSL_PREFIX to /usr/local/musl-llvm-staging --- dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dockerfile b/dockerfile index 49743a1..0a656d5 100644 --- a/dockerfile +++ b/dockerfile @@ -12,7 +12,7 @@ ARG MUSL_PREFIX=/usr/local/musl-llvm-staging FROM --platform="linux/${TARGETARCH}" alpine:latest AS musl-builder ENV MUSL_VER=${MUSL_VER:-"1.2.5"} -ENV MUSL_PREFIX=${MUSL_PREFIX} +ENV MUSL_PREFIX=${MUSL_PREFIX:-"/usr/local/musl-llvm-staging"} RUN set -eux \ && apk add --no-cache \ @@ -79,7 +79,7 @@ ENV LDFLAGS="-fuse-ld=lld" ENV BSD=/usr/include/bsd ENV LINUX=/usr/include/linux ENV MUSL_VER=${MUSL_VER:-"1.2.5"} -ENV MUSL_PREFIX=${MUSL_PREFIX} +ENV MUSL_PREFIX=${MUSL_PREFIX:-"/usr/local/musl-llvm-staging"} # Install necessary packages # llvm - LLVM-apache-2 From 1c4d92003ad22e8f0825fc5729c05f002e7d633b Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Sat, 6 Sep 2025 01:33:13 -0700 Subject: [PATCH 06/15] [PATCH] minor fixes Changes in file dockerfile: * minor fixes --- dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dockerfile b/dockerfile index 0a656d5..4a4492c 100644 --- a/dockerfile +++ b/dockerfile @@ -183,14 +183,14 @@ RUN /usr/bin/mkroot.bash && \ # - crt*.o (for static linking if needed) # - headers COPY --from=musl-builder ${MUSL_PREFIX}/lib/ld-musl-*.so.* /output/fs/lib/ +COPY --from=musl-builder ${MUSL_PREFIX}/lib/crt*.o /output/fs/lib/ COPY --from=musl-builder ${MUSL_PREFIX}/lib/libc.so* /output/fs/usr/lib/ -COPY --from=musl-builder ${MUSL_PREFIX}/lib/crt1.o ${MUSL_PREFIX}/lib/crti.o ${MUSL_PREFIX}/lib/crtn.o /output/fs/lib/ || true COPY --from=musl-builder ${MUSL_PREFIX}/include /output/fs/usr/include # Some systems expect /lib64 -> /lib for x86_64. Create symlink if appropriate. RUN set -eux; \ if [ "$(uname -m)" = "x86_64" ]; then \ - [ -d /output/fs/lib64 ] || ln -s /output/fs/lib /lib64; \ + [ -d /output/fs/lib64 ] || ln -s /lib /output/fs/lib64; \ fi # Ensure loader has canonical name (example: /lib/ld-musl-x86_64.so.1) From 395bb1096aa759b668cab4bc4a2ab2da694e545d Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Sat, 6 Sep 2025 21:17:33 -0700 Subject: [PATCH 07/15] [FEATURE] attempt to force clang compile of musl Changes in file dockerfile: * try enumerate clang vars when building musl --- dockerfile | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dockerfile b/dockerfile index 4a4492c..dbe9774 100644 --- a/dockerfile +++ b/dockerfile @@ -18,6 +18,7 @@ RUN set -eux \ && apk add --no-cache \ clang \ llvm \ + cmd:llvm-ar \ lld \ make \ binutils \ @@ -30,10 +31,10 @@ RUN set -eux \ && mkdir -p /build WORKDIR /build -ENV export CC=clang -ENV export AR=llvm-ar -ENV export RANLIB=llvm-ranlib -ENV export LD=ld.lld +ENV CC=clang +ENV AR=llvm-ar +ENV RANLIB=llvm-ranlib +ENV LD=ld.lld ENV LDFLAGS="-fuse-ld=lld" # Download musl @@ -47,7 +48,7 @@ WORKDIR /build/musl # Configure, build, and install musl with shared enabled (default) using LLVM tools RUN mkdir -p ${MUSL_PREFIX} && \ ./configure --prefix=${MUSL_PREFIX} && \ - make -j"$(nproc)" && \ + make CC=clang CFLAGS="${CFLAGS} -fno-math-errno -fPIC -fno-common" AR=llvm-ar LDFLAGS="${LDFLAGS}" -j"$(nproc)" && \ make install # Ensure we have the dynamic loader and libs present (example paths) From aa9a0dafeab0a5e9c73d1ef18586ce7ab7afa7a1 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Sat, 6 Sep 2025 22:46:29 -0700 Subject: [PATCH 08/15] [FEATRUE] improve reproducability by fixing timestamps at build time Changes in file .github/workflows/Build-Bootstraper.yaml: * pre-calculate mitl-timestamp Changes in file dockerfile: * add touch -d timestamp steps Changes in file mkroot.bash: * add touch -d timestamp steps --- .github/workflows/Build-Bootstraper.yaml | 7 ++++++- dockerfile | 12 +++++++++++- mkroot.bash | 18 ++++++++++++++++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Build-Bootstraper.yaml b/.github/workflows/Build-Bootstraper.yaml index a8b0850..59a795d 100644 --- a/.github/workflows/Build-Bootstraper.yaml +++ b/.github/workflows/Build-Bootstraper.yaml @@ -30,6 +30,7 @@ jobs: runs-on: ubuntu-latest outputs: timestamp: ${{ steps.output_time.outputs.bootstrap-timestamp }} + mitl-timestamp: ${{ steps.output_time.outputs.mitl-timestamp }} steps: - name: Checkout code uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -44,7 +45,8 @@ jobs: printf "%s\n" "::group::bootstrap-MITL-env" printf "bootstrap-timestamp=%s\n" $(git log -1 --pretty=%ct) >> "$GITHUB_OUTPUT" printf "TIMESTAMP=%s\n" $(git log -1 --pretty=%ct) >> "$GITHUB_ENV" - printf "%s %s\n" "MITL-Bootstrap will be synced at time of:" $(git log -1 --pretty=%ct) + printf "mitl-timestamp=%s %s\n" $(date -j -f "%s" "$(git log -1 --pretty=%ct)" "+%C%y-%d-%m %H:%M:%S") >> "$GITHUB_OUTPUT" + printf "%s %s\n" "MITL-Bootstrap will be synced at time of:" $(date -j -f "%s" "$(git log -1 --pretty=%ct)" "+%C%y-%d-%m %H:%M:%S") printf "%s\n" "::endgroup::" build: @@ -117,6 +119,7 @@ jobs: TOYBOX_VERSION=0.8.12 TARGETARCH=${{ matrix.architecture }} MUSL_VER=1.2.5 + MITL_DATE_EPOCH=${{ needs.seed.outputs.mitl-timestamp }} cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max attests: | @@ -130,9 +133,11 @@ jobs: index.org.opencontainers.image.authors=mitl-maintainers@users.noreply.github.com index.org.opencontainers.image.description=Multi-arch MITL Bootstrap image index.org.opencontainers.image.vendor=individual + index.org.opencontainers.image.licenses="MIT" outputs: type=image,push-by-digest=true,name-canonical=true,push=true,annotation-index.org.opencontainers.image.description=Multi-arch MITL Bootstrap image ${{ matrix.architecture }} env: SOURCE_DATE_EPOCH: ${{ needs.seed.outputs.timestamp }} + MITL_DATE_EPOCH: ${{ needs.seed.outputs.mitl-timestamp }} TOYBOX_VERSION: "0.8.12" MUSL_VER: "1.2.5" TARGETARCH: ${{ matrix.architecture }} diff --git a/dockerfile b/dockerfile index dbe9774..20c8232 100644 --- a/dockerfile +++ b/dockerfile @@ -36,6 +36,7 @@ ENV AR=llvm-ar ENV RANLIB=llvm-ranlib ENV LD=ld.lld ENV LDFLAGS="-fuse-ld=lld" +ENV MITL_DATE_EPOCH=${MITL_DATE_EPOCH} # Download musl RUN set -eux \ @@ -63,6 +64,9 @@ RUN set -eux \ find ${MUSL_PREFIX}/lib -type f -name "*.so*" -exec strip --strip-unneeded {} + || true; \ fi +RUN touch -d ${MITL_DATE_EPOCH} ${MUSL_PREFIX}/lib/* || true \ + && touch -d ${MITL_DATE_EPOCH} ${MUSL_PREFIX}/include/* || true + # Stage 2: Build toybox based filesystem # Use MIT licensed Alpine as the base image for the build environment @@ -70,6 +74,7 @@ RUN set -eux \ FROM --platform="linux/${TARGETARCH}" alpine:latest AS builder # Set environment variables +ENV MITL_DATE_EPOCH=${MITL_DATE_EPOCH} ENV TOYBOX_VERSION=${TOYBOX_VERSION:-"0.8.12"} ENV PATH="/usr/local/bin:$PATH" ENV CC=clang @@ -176,7 +181,8 @@ ENV DESTDIR="/output/fs" # Minimal etc RUN /usr/bin/mkroot.bash && \ printf "root:x:0:0:root:/root:/bin/sh\n" > /output/fs/etc/passwd && \ - printf "/dev/sda / ext4 defaults 0 1\n" > /output/fs/etc/fstab + printf "/dev/sda / ext4 defaults 0 1\n" > /output/fs/etc/fstab && \ + touch -d ${MITL_DATE_EPOCH} /output/fs/etc/* || true; # Copy musl runtime artifacts from builder: # - dynamic loader (ld-musl-*.so.1) @@ -188,6 +194,10 @@ COPY --from=musl-builder ${MUSL_PREFIX}/lib/crt*.o /output/fs/lib/ COPY --from=musl-builder ${MUSL_PREFIX}/lib/libc.so* /output/fs/usr/lib/ COPY --from=musl-builder ${MUSL_PREFIX}/include /output/fs/usr/include +RUN touch -d ${MITL_DATE_EPOCH} /output/fs/* || true \ + && touch -d ${MITL_DATE_EPOCH} /output/fs/usr/include/* || true \ + && touch -d ${MITL_DATE_EPOCH} /output/fs/usr/lib/* || true + # Some systems expect /lib64 -> /lib for x86_64. Create symlink if appropriate. RUN set -eux; \ if [ "$(uname -m)" = "x86_64" ]; then \ diff --git a/mkroot.bash b/mkroot.bash index b596d52..23b4de8 100755 --- a/mkroot.bash +++ b/mkroot.bash @@ -68,8 +68,11 @@ HOST_TOOLCHAIN_PATH=${HOST_TOOLCHAIN_PATH} # MacOS/Darwin host might be different like: # HOST_TOOLCHAIN_PATH=$(xcode-select --print-path) +# allow reproducable builds based on EPOCH + +MITL_DATE_EPOCH=${MITL_DATE_EPOCH} + # primitive stage0 make root script -PREFIX_STUB=${HOST_TOOLCHAIN_PATH}${PREFIX:-/usr} BASH_CMD=$(which bash) test -x "${BASH_CMD}" || exit 126 ; # need host bash @@ -121,6 +124,8 @@ fn_host_do_cmd() { for FILE in bin lib sbin tmp usr usr/bin usr/libexec usr/local usr/share usr/include var Users ; do fn_host_do_cmd mkdir -p "${DESTDIR}/${FILE}" ; fn_host_do_cmd chmod 755 "${DESTDIR}/${FILE}" || true ; + fn_host_do_cmd touch -d ${MITL_DATE_EPOCH} "${DESTDIR}/${FILE}" || true ; + fn_host_do_cmd touch -mad ${MITL_DATE_EPOCH} "${DESTDIR}/${FILE}" 2>/dev/null || true ; done ; # basic sym-links @@ -135,9 +140,13 @@ fn_host_do_cmd rm "${HOST_TOOLCHAIN_PATH}/etc/os-release" 2>/dev/null || true ; for FILE in dev etc init usr/lib mnt ; do fn_host_do_cmd mv "${HOST_TOOLCHAIN_PATH}/${FILE}" "${DESTDIR}/${FILE}" ; + fn_host_do_cmd touch -d ${MITL_DATE_EPOCH} "${DESTDIR}/${FILE}" || true ; + fn_host_do_cmd touch -mad ${MITL_DATE_EPOCH} "${DESTDIR}/${FILE}" 2>/dev/null || true ; done ; -fn_host_do_cmd cp -vf "${HOST_TOOLCHAIN_PATH}/usr/bin/toybox" "${DESTDIR}/usr/bin/toybox" 2>/dev/null || true ; +fn_host_do_cmd cp -f "${HOST_TOOLCHAIN_PATH}/usr/bin/toybox" "${DESTDIR}/usr/bin/toybox" 2>/dev/null || true ; +fn_host_do_cmd touch -d ${MITL_DATE_EPOCH} "${DESTDIR}/usr/bin/toybox" || true ; +fn_host_do_cmd touch -mad ${MITL_DATE_EPOCH} "${DESTDIR}/usr/bin/toybox" 2>/dev/null || true ; for FILE in "bash" "basename" "cat" "chgrp" "chmod" "chown" "cp" "date" "dirname" "find" "grep" "head" "halt" "ls" "ln" "mkdir" "mv" "printf" "rm" "sed" ; do fn_host_do_cmd ln -s "toybox" "${DESTDIR}/usr/bin/${FILE}" 2>/dev/null || true ; @@ -146,6 +155,11 @@ done ; fn_host_do_cmd ln -s "../usr/bin/toybox" "${DESTDIR}/bin/sh" 2>/dev/null || true ; fn_host_do_cmd ln -s "../usr/bin/toybox" "${DESTDIR}/bin/bash" 2>/dev/null || true ; +for FILE in bin lib sbin tmp usr usr/bin usr/libexec usr/local usr/share usr/include var Users ; do + fn_host_do_cmd touch -d ${MITL_DATE_EPOCH} "${DESTDIR}/${FILE}"/* || true ; + fn_host_do_cmd touch -mad ${MITL_DATE_EPOCH} "${DESTDIR}/${FILE}"/* 2>/dev/null || true ; +done ; + # fn_host_do_cmd sha256sum "${DESTDIR}/${FILE}" || true ; exit 0 ; From 5361f53ec65435da33e0798816ac128695e16160 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Mon, 8 Sep 2025 13:36:33 -0700 Subject: [PATCH 09/15] [UPDATE] Version 0.9 (prototype) Changes in file dockerfile: * cleanup of ARGs * refactor some for maintainability --- dockerfile | 71 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/dockerfile b/dockerfile index 20c8232..094da55 100644 --- a/dockerfile +++ b/dockerfile @@ -1,21 +1,20 @@ # syntax=docker/dockerfile:1 -ARG TOYBOX_VERSION=${TOYBOX_VERSION:-"0.8.12"} - -# version is passed through by Docker. -# shellcheck disable=SC2154 -ARG MUSL_VER=${MUSL_VER:-"1.2.5"} -ARG MUSL_PREFIX=/usr/local/musl-llvm-staging # Stage 1: Build Musl # Use MIT licensed Alpine as the base image for the build environment # shellcheck disable=SC2154 FROM --platform="linux/${TARGETARCH}" alpine:latest AS musl-builder -ENV MUSL_VER=${MUSL_VER:-"1.2.5"} +# version is passed through by Docker. +# shellcheck disable=SC2154 +ARG MUSL_VER=${MUSL_VER:-"1.2.5"} +ENV MUSL_VER=${MUSL_VER} +ARG MUSL_PREFIX=/usr/local/musl-llvm-staging ENV MUSL_PREFIX=${MUSL_PREFIX:-"/usr/local/musl-llvm-staging"} RUN set -eux \ && apk add --no-cache \ + cmd:bsdtar \ clang \ llvm \ cmd:llvm-ar \ @@ -36,12 +35,15 @@ ENV AR=llvm-ar ENV RANLIB=llvm-ranlib ENV LD=ld.lld ENV LDFLAGS="-fuse-ld=lld" +# epoch is passed through by Docker. +# shellcheck disable=SC2154 +ARG MITL_DATE_EPOCH ENV MITL_DATE_EPOCH=${MITL_DATE_EPOCH} # Download musl RUN set -eux \ && curl -fsSLO https://musl.libc.org/releases/musl-${MUSL_VER}.tar.gz \ - && tar xf musl-${MUSL_VER}.tar.gz \ + && bsdtar xf musl-${MUSL_VER}.tar.gz \ && mv musl-${MUSL_VER} musl WORKDIR /build/musl @@ -74,8 +76,15 @@ RUN touch -d ${MITL_DATE_EPOCH} ${MUSL_PREFIX}/lib/* || true \ FROM --platform="linux/${TARGETARCH}" alpine:latest AS builder # Set environment variables + +# epoch is passed through by Docker. +# shellcheck disable=SC2154 +ARG MITL_DATE_EPOCH ENV MITL_DATE_EPOCH=${MITL_DATE_EPOCH} -ENV TOYBOX_VERSION=${TOYBOX_VERSION:-"0.8.12"} +# version is passed through by Docker. +# shellcheck disable=SC2154 +ARG TOYBOX_VERSION=${TOYBOX_VERSION:-"0.8.12"} +ENV TOYBOX_VERSION=${TOYBOX_VERSION} ENV PATH="/usr/local/bin:$PATH" ENV CC=clang ENV CXX=clang++ @@ -84,7 +93,10 @@ ENV RANLIB=llvm-ranlib ENV LDFLAGS="-fuse-ld=lld" ENV BSD=/usr/include/bsd ENV LINUX=/usr/include/linux -ENV MUSL_VER=${MUSL_VER:-"1.2.5"} +# version is passed through by Docker. +# shellcheck disable=SC2154 +ARG MUSL_VER=${MUSL_VER:-"1.2.5"} +ENV MUSL_VER=${MUSL_VER} ENV MUSL_PREFIX=${MUSL_PREFIX:-"/usr/local/musl-llvm-staging"} # Install necessary packages @@ -98,7 +110,7 @@ ENV MUSL_PREFIX=${MUSL_PREFIX:-"/usr/local/musl-llvm-staging"} # libbsd-dev - BSD-3-Clause # bash - GPL-3.0 - do not bundle - only until toolbox bash is compiled to run bootstrap scripts # curl - curl License / MIT -# tar - GPL-3.0-or-later - do not bundle - used to unarchive during bootstrap +# bsdtar - BSD-2 - used to unarchive during bootstrap (transient) # openssl-dev - Apache-2.0 # zlib-dev - zlib license @@ -113,7 +125,7 @@ RUN --mount=type=cache,target=/var/cache/apk,sharing=locked --network=default \ linux-headers \ bash \ curl \ - tar \ + cmd:bsdtar \ openssl-dev \ libbsd-dev \ lld \ @@ -125,7 +137,7 @@ RUN mkdir -p /opt && \ curl -fsSL \ --url "https://github.com/landley/toybox/archive/refs/tags/${TOYBOX_VERSION}.tar.gz" \ -o toybox-${TOYBOX_VERSION}.tar.gz && \ - tar -xzf toybox-${TOYBOX_VERSION}.tar.gz && \ + bsdtar -xzf toybox-${TOYBOX_VERSION}.tar.gz && \ rm toybox-${TOYBOX_VERSION}.tar.gz && \ mv /opt/toybox-${TOYBOX_VERSION} /opt/toybox @@ -180,34 +192,34 @@ ENV DESTDIR="/output/fs" # Minimal etc RUN /usr/bin/mkroot.bash && \ - printf "root:x:0:0:root:/root:/bin/sh\n" > /output/fs/etc/passwd && \ - printf "/dev/sda / ext4 defaults 0 1\n" > /output/fs/etc/fstab && \ - touch -d ${MITL_DATE_EPOCH} /output/fs/etc/* || true; + printf "root:x:0:0:root:/root:/bin/sh\n" > "${DESTDIR}"/etc/passwd && \ + printf "/dev/sda / ext4 defaults 0 1\n" > "${DESTDIR}"/etc/fstab && \ + touch -d ${MITL_DATE_EPOCH} "${DESTDIR}"/etc/* || true; # Copy musl runtime artifacts from builder: # - dynamic loader (ld-musl-*.so.1) # - libmusl shared object(s) (libc.so.*) # - crt*.o (for static linking if needed) # - headers -COPY --from=musl-builder ${MUSL_PREFIX}/lib/ld-musl-*.so.* /output/fs/lib/ -COPY --from=musl-builder ${MUSL_PREFIX}/lib/crt*.o /output/fs/lib/ -COPY --from=musl-builder ${MUSL_PREFIX}/lib/libc.so* /output/fs/usr/lib/ -COPY --from=musl-builder ${MUSL_PREFIX}/include /output/fs/usr/include +COPY --from=musl-builder ${MUSL_PREFIX}/lib/ld-musl-*.so.* "${DESTDIR}"/lib/ +COPY --from=musl-builder ${MUSL_PREFIX}/lib/crt*.o "${DESTDIR}"/lib/ +COPY --from=musl-builder ${MUSL_PREFIX}/lib/libc.so* "${DESTDIR}"/usr/lib/ +COPY --from=musl-builder ${MUSL_PREFIX}/include "${DESTDIR}"/usr/include -RUN touch -d ${MITL_DATE_EPOCH} /output/fs/* || true \ - && touch -d ${MITL_DATE_EPOCH} /output/fs/usr/include/* || true \ - && touch -d ${MITL_DATE_EPOCH} /output/fs/usr/lib/* || true +RUN touch -d ${MITL_DATE_EPOCH} "${DESTDIR}"/* || true \ + && touch -d ${MITL_DATE_EPOCH} "${DESTDIR}"/usr/include/* || true \ + && touch -d ${MITL_DATE_EPOCH} "${DESTDIR}"/usr/lib/* || true -# Some systems expect /lib64 -> /lib for x86_64. Create symlink if appropriate. +# Some systems expect /lib64 -> /lib for x86_64. Create symlink if appropriate (unsupported by musl). RUN set -eux; \ if [ "$(uname -m)" = "x86_64" ]; then \ - [ -d /output/fs/lib64 ] || ln -s /lib /output/fs/lib64; \ + [ -d "${DESTDIR}"/lib64 ] || ln -s /lib "${DESTDIR}"/lib64; \ fi # Ensure loader has canonical name (example: /lib/ld-musl-x86_64.so.1) RUN set -eux \ - && for f in /output/fs/lib/ld-musl-*; do \ - ln -fns "$f" /output/fs/lib/ld-musl.so.1 || true; \ + && for f in "${DESTDIR}"/lib/ld-musl-*; do \ + ln -fns "$f" "${DESTDIR}"/lib/ld-musl.so.1 || true; \ done || true # Stage 3: Create the final image @@ -215,13 +227,14 @@ RUN set -eux \ FROM --platform="linux/${TARGETARCH}" scratch AS mitl-bootstrap # set inherited values -LABEL version="0.8" +LABEL version="0.9" +LABEL maintainer="mitl-maintainers@users.noreply.github.com" LABEL org.opencontainers.image.title="MITL-bootstrap" LABEL org.opencontainers.image.description="Custom Bootstrap MITL image with toybox installed." LABEL org.opencontainers.image.vendor="individual" LABEL org.opencontainers.image.licenses="MIT" LABEL org.opencontainers.image.authors="mitl-maintainers@users.noreply.github.com" -LABEL maintainer="mitl-maintainers@users.noreply.github.com" + # Copy built files COPY --from=builder /output/fs / From 3dc78b7653a8fbaa716db2fefa9e15323686b595 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Mon, 8 Sep 2025 14:59:10 -0700 Subject: [PATCH 10/15] [FEATURE] Set some default ENV values on final image Changes in file dockerfile: * set PATH and TZ defaults --- dockerfile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dockerfile b/dockerfile index 094da55..9ff4262 100644 --- a/dockerfile +++ b/dockerfile @@ -246,6 +246,16 @@ SHELL [ "/bin/bash", "--norc", "-c" ] # Set the entry point to Toybox ENTRYPOINT ["/usr/bin/toybox"] +# Set the default path to a reasonable value +ENV PATH='/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/libexec' +# musl libc checks TZ +# format is +# [SUS/POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03) +# Set TZ to UTC +ENV TZ='UTC+0' +# Set PS1 to something +ENV PS1="(\A \u@\h \W) > " +# Set bash to toybox bash ENV BASH='/bin/bash' ENV HOSTNAME="MITL-bootstrap" CMD [ "/bin/bash", "--norc", "-c", "'exec -a bash /bin/bash -i'" ] From dd28d67fd69b94be96e910518edff76db3cb2c53 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Mon, 8 Sep 2025 16:13:06 -0700 Subject: [PATCH 11/15] [FEATURE] added /etc/shells stub to mitl-bootstrap Changes in file dockerfile: * removed prefix arg * added /etc/shells stub from scratch --- dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dockerfile b/dockerfile index 9ff4262..50bb891 100644 --- a/dockerfile +++ b/dockerfile @@ -9,8 +9,7 @@ FROM --platform="linux/${TARGETARCH}" alpine:latest AS musl-builder # shellcheck disable=SC2154 ARG MUSL_VER=${MUSL_VER:-"1.2.5"} ENV MUSL_VER=${MUSL_VER} -ARG MUSL_PREFIX=/usr/local/musl-llvm-staging -ENV MUSL_PREFIX=${MUSL_PREFIX:-"/usr/local/musl-llvm-staging"} +ENV MUSL_PREFIX="/usr/local/musl-llvm-staging" RUN set -eux \ && apk add --no-cache \ @@ -97,7 +96,7 @@ ENV LINUX=/usr/include/linux # shellcheck disable=SC2154 ARG MUSL_VER=${MUSL_VER:-"1.2.5"} ENV MUSL_VER=${MUSL_VER} -ENV MUSL_PREFIX=${MUSL_PREFIX:-"/usr/local/musl-llvm-staging"} +ENV MUSL_PREFIX="/usr/local/musl-llvm-staging" # Install necessary packages # llvm - LLVM-apache-2 @@ -194,6 +193,7 @@ ENV DESTDIR="/output/fs" RUN /usr/bin/mkroot.bash && \ printf "root:x:0:0:root:/root:/bin/sh\n" > "${DESTDIR}"/etc/passwd && \ printf "/dev/sda / ext4 defaults 0 1\n" > "${DESTDIR}"/etc/fstab && \ + printf "# List of acceptable shells for chpass(1).\n\n/bin/sh\n/bin/bash\n" > "${DESTDIR}"/etc/shells && \ touch -d ${MITL_DATE_EPOCH} "${DESTDIR}"/etc/* || true; # Copy musl runtime artifacts from builder: From f6a43de82941680cf5b86cd076131e25b5fc9058 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Tue, 16 Sep 2025 23:05:51 -0700 Subject: [PATCH 12/15] [FEATURE] use native builds Changes in file .github/workflows/Build-Bootstraper.yaml: * use native builds instead of just QEMU --- .github/workflows/Build-Bootstraper.yaml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Build-Bootstraper.yaml b/.github/workflows/Build-Bootstraper.yaml index 59a795d..9e4d489 100644 --- a/.github/workflows/Build-Bootstraper.yaml +++ b/.github/workflows/Build-Bootstraper.yaml @@ -57,11 +57,17 @@ jobs: packages: write pull-requests: read security-events: none - runs-on: ubuntu-latest needs: seed strategy: matrix: - architecture: [amd64, arm64, arm] + include: + - architecture: amd64 + runner: ubuntu-latest + - architecture: arm64 + runner: ubuntu-24.04-arm64 + - architecture: arm + runner: ubuntu-24.04-arm64 + runs-on: ${{ matrix.runner }} steps: - name: Checkout code @@ -76,7 +82,9 @@ jobs: platform=linux/${{ matrix.architecture }} echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV - - name: Set up QEMU for multi-architecture builds + # QEMU setup only for armv7 emulation + - name: Set up QEMU (for armv7) + if: ${{ matrix.architecture == 'arm' }} uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 - name: Set up Docker Buildx From 9ec82bbb20166777ffa5d8a771ab477a36702dbb Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Wed, 17 Sep 2025 14:03:35 -0700 Subject: [PATCH 13/15] [FIX] use correct runner lable Changes in file .github/workflows/Build-Bootstraper.yaml: * ubuntu-24.04-arm64 should just be ubuntu-24.04-arm --- .github/workflows/Build-Bootstraper.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Build-Bootstraper.yaml b/.github/workflows/Build-Bootstraper.yaml index 9e4d489..c582e8e 100644 --- a/.github/workflows/Build-Bootstraper.yaml +++ b/.github/workflows/Build-Bootstraper.yaml @@ -64,9 +64,9 @@ jobs: - architecture: amd64 runner: ubuntu-latest - architecture: arm64 - runner: ubuntu-24.04-arm64 + runner: ubuntu-24.04-arm - architecture: arm - runner: ubuntu-24.04-arm64 + runner: ubuntu-24.04-arm runs-on: ${{ matrix.runner }} steps: From a3fdb697f99c98c5d312421a98d2d1c20176151b Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Wed, 17 Sep 2025 14:46:27 -0700 Subject: [PATCH 14/15] [PATCH] use FreeBSD date util for timestamp check in seed step Changes in file .github/workflows/Build-Bootstraper.yaml: * use freebsd date util on mac runner instead --- .github/workflows/Build-Bootstraper.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Build-Bootstraper.yaml b/.github/workflows/Build-Bootstraper.yaml index c582e8e..3d5c862 100644 --- a/.github/workflows/Build-Bootstraper.yaml +++ b/.github/workflows/Build-Bootstraper.yaml @@ -27,7 +27,7 @@ jobs: contents: read packages: none pull-requests: read - runs-on: ubuntu-latest + runs-on: macos-latest # Has FreeBSD date (with -j and -f [format] options) outputs: timestamp: ${{ steps.output_time.outputs.bootstrap-timestamp }} mitl-timestamp: ${{ steps.output_time.outputs.mitl-timestamp }} From 954c57a88b7b8e55147a98b4bb062bdbd086fd71 Mon Sep 17 00:00:00 2001 From: "Mr. Walls" Date: Wed, 17 Sep 2025 15:39:46 -0700 Subject: [PATCH 15/15] [FIX] refactor how musl is fetched slightly Changes in file dockerfile: * refactor how musl is fetched --- dockerfile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dockerfile b/dockerfile index 50bb891..44700c0 100644 --- a/dockerfile +++ b/dockerfile @@ -40,10 +40,11 @@ ARG MITL_DATE_EPOCH ENV MITL_DATE_EPOCH=${MITL_DATE_EPOCH} # Download musl -RUN set -eux \ - && curl -fsSLO https://musl.libc.org/releases/musl-${MUSL_VER}.tar.gz \ - && bsdtar xf musl-${MUSL_VER}.tar.gz \ - && mv musl-${MUSL_VER} musl +RUN curl -fsSL \ + --url "https://musl.libc.org/releases/musl-${MUSL_VER}.tar.gz" \ + -o musl-${MUSL_VER}.tar.gz && \ + bsdtar xf musl-${MUSL_VER}.tar.gz && \ + mv musl-${MUSL_VER} musl WORKDIR /build/musl