Skip to content

fix: make recovery packages reproducible #47

fix: make recovery packages reproducible

fix: make recovery packages reproducible #47

Workflow file for this run

name: sdk
# Builds the Singularity OS SDK image (Dockerfile.sdk) and publishes it to GHCR.
# Component repositories pull ghcr.io/singularityos-lab/sinty-os-sdk to
# cross-build their release binaries against the OS toolchain and sysroot.
#
# The buildroot `sdk` target builds `world`, which does not fit in a runner's 6h
# job limit from a cold tree -- building it inside the Dockerfile did exactly that
# and was killed at 6h01 with nothing cached, because buildx only exports its
# cache when the build finishes. So the toolchain is built HERE, on the runner,
# reusing the same buildroot caches the main build fills: that tree is already
# compiled, so `make sdk` only has to pack it. The Dockerfile then just wraps the
# resulting tarball.
#
# runs-on must match the main build's runner: the caches are keyed on the image,
# because a build tree configured against one image cannot reconfigure on another.
on:
workflow_dispatch:
push:
branches: [main]
paths:
- 'buildroot-config/**'
- 'Config.in'
- 'external.*'
- 'package/**'
- 'Dockerfile.sdk'
- '.github/workflows/sdk.yml'
concurrency:
group: sdk-${{ github.ref }}
cancel-in-progress: true
jobs:
build-sdk:
runs-on: ubuntu-24.04
timeout-minutes: 350
permissions:
contents: read
packages: write
steps:
- name: Free disk space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/usr/local/share/boost "$AGENT_TOOLSDIRECTORY" || true
df -h /
- uses: actions/checkout@v4
# Identical to the main build's list: this job builds the same tree, so it needs
# the same host tools. Trimming it only moves the failure to whichever package
# configures against a missing one (flatpak wants bwrap).
- name: Install host build dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential gcc g++ make \
bc bison flex \
libssl-dev libelf-dev \
libncurses-dev \
wget rsync cpio \
xz-utils gzip bzip2 zstd \
patch perl python3 \
git unzip curl \
erofs-utils \
cryptsetup-bin \
systemd-boot \
binutils sassc mtools dosfstools \
bubblewrap xdg-dbus-proxy
# $ImageVersion is a runner environment variable, not a workflow one, so
# ${{ env.ImageVersion }} expands to nothing in a cache key -- the keys read
# "-v10--<hash>" until this was noticed. Copy it into the workflow env so the
# keys really do change when GitHub bumps the image.
- name: Record the runner image
run: echo "IMAGE_VERSION=$ImageVersion" >> "$GITHUB_ENV"
- name: Restore Buildroot source tree
uses: actions/cache/restore@v4
with:
path: buildroot-src
key: buildroot-src-2026.02.2-${{ hashFiles('buildroot-source-patches/**', 'scripts/prepare.sh') }}
- name: Restore Buildroot downloads
uses: actions/cache/restore@v4
with:
path: buildroot-dl
key: buildroot-dl-${{ hashFiles('buildroot-config/singularity_defconfig') }}-${{ github.run_id }}
restore-keys: |
buildroot-dl-${{ hashFiles('buildroot-config/singularity_defconfig') }}-
buildroot-dl-
- name: Restore Buildroot host toolchain
uses: actions/cache/restore@v4
with:
path: buildroot-build/host
key: buildroot-host-v4-${{ env.IMAGE_VERSION }}-${{ hashFiles('buildroot-config/singularity_defconfig', 'buildroot-config/kernel.config', 'buildroot-source-patches/**') }}-${{ github.run_id }}
restore-keys: |
buildroot-host-v4-${{ env.IMAGE_VERSION }}-${{ hashFiles('buildroot-config/singularity_defconfig', 'buildroot-config/kernel.config', 'buildroot-source-patches/**') }}-
- name: Restore Buildroot package build tree
uses: actions/cache/restore@v4
with:
path: buildroot-build/build
key: buildroot-build-v10-${{ env.IMAGE_VERSION }}-${{ hashFiles('buildroot-config/singularity_defconfig', 'buildroot-config/kernel.config', 'buildroot-source-patches/**') }}-${{ github.run_id }}
restore-keys: |
buildroot-build-v10-${{ env.IMAGE_VERSION }}-${{ hashFiles('buildroot-config/singularity_defconfig', 'buildroot-config/kernel.config', 'buildroot-source-patches/**') }}-
- name: Prepare Buildroot
run: ./scripts/prepare.sh
- name: Build the SDK tarball
run: |
# Budgeted like the main build's Compile: if the restored tree was not far
# enough along, stop short of the job limit with the caches saved instead of
# being killed at 6h with nothing kept, and let the next run carry on.
set -o pipefail
timeout 300m make -C buildroot-src \
O="$PWD/buildroot-build" \
BR2_EXTERNAL="$PWD" \
BR2_DL_DIR="$PWD/buildroot-dl" \
-j"$(nproc)" sdk 2>&1 | tail -n 2000
ec=${PIPESTATUS[0]}
if [ "$ec" = "124" ]; then
echo "SDK_INCOMPLETE=1" >> "$GITHUB_ENV"
echo "::warning::make sdk hit the 300m budget; caches are saved and it resumes on the next run."
exit 0
fi
exit "$ec"
# Deliberately no cache save here. The two buildroot caches are ~9.4 GB together,
# against a 10 GB per-repo limit, so a second writer evicts the download cache --
# and some upstreams are unreachable from a runner, so a lost download cannot be
# re-fetched (libdbusmenu timed out on launchpad). The main build owns these
# caches; this job only reads them.
- name: Stage the tarball as the image build context
if: env.SDK_INCOMPLETE != '1'
run: |
mkdir -p sdk-context
# One tarball, named for the toolchain tuple; fail loudly rather than build an
# image around whichever file a glob happened to match.
n=$(ls buildroot-build/images/*_sdk-buildroot.tar.gz | wc -l)
[ "$n" = 1 ] || { echo "expected 1 SDK tarball, found $n"; exit 1; }
cp buildroot-build/images/*_sdk-buildroot.tar.gz sdk-context/sdk.tar.gz
ls -la sdk-context/
- uses: docker/setup-buildx-action@v3
if: env.SDK_INCOMPLETE != '1'
- name: Log in to GHCR
if: env.SDK_INCOMPLETE != '1'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push the SDK image
if: env.SDK_INCOMPLETE != '1'
uses: docker/build-push-action@v6
with:
context: sdk-context
file: Dockerfile.sdk
push: true
tags: ghcr.io/singularityos-lab/sinty-os-sdk:latest
cache-from: type=gha
cache-to: type=gha,mode=max