fix: make recovery packages reproducible #47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |