Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
12 changes: 2 additions & 10 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,2 @@
.git/
cache/
out/
aports/
extra/
screenshots/
Dockerfile
.dockerignore
docker-env.sh
profile/repo/
# The checkout is mounted at run time, never copied: send no build context.
*
5 changes: 0 additions & 5 deletions .github/actions/container.yml

This file was deleted.

62 changes: 62 additions & 0 deletions .github/boot-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/sh

# Boots the freshly built ISO in QEMU and waits until OpenRC reaches the last
# service of the default runlevel ("Starting local"): the kernel, initrdbo's
# live boot from the squashfs and the whole init sequence all worked.
#
# The ISO's own menu has no serial console, so its kernel and initramfs are
# booted directly, with the ISO's command line plus console=ttyS0 and the ISO
# attached as a CD-ROM, which is where initrdbo finds the squashfs.
#
# usage: sh .github/boot-test.sh (from the checkout, after `./sigma build`)

set -eu

iso=out/sigma-linux.iso
boot=cache/boot
menu=cache/iso/boot/grub/grub.cfg
log=cache/logs/boot-test.log
marker="Starting local"
limit=${BOOT_TIMEOUT:-600}

for file in "$iso" "$boot/vmlinuz-sigma" "$boot/initramfs-sigma" "$menu"; do
[ -r "$file" ] || { echo "boot-test: $file is missing; build the ISO first" >&2; exit 1; }
done

# The first entry's parameters, exactly as the ISO boots them.
cmdline="$(sed -n 's|^[[:space:]]*linux /boot/vmlinuz-sigma ||p' "$menu" | head -n 1)"
[ -n "$cmdline" ] || { echo "boot-test: no vmlinuz-sigma entry in $menu" >&2; exit 1; }

accel=""
[ -w /dev/kvm ] && accel="-enable-kvm -cpu host"

mkdir -p "${log%/*}"
: > "$log"
# shellcheck disable=SC2086 # $accel is a list of options
qemu-system-x86_64 $accel -m 4096 -smp 2 -display none -no-reboot \
-cdrom "$iso" -kernel "$boot/vmlinuz-sigma" -initrd "$boot/initramfs-sigma" \
-append "$cmdline console=ttyS0" -serial "file:$log" &
qemu=$!

fail() {
kill "$qemu" 2>/dev/null || true
echo "boot-test: $*" >&2
echo "--- last lines of the serial console ($log):" >&2
tail -n 60 "$log" >&2
exit 1
}

echo "Booting ${iso} ($([ -n "$accel" ] && echo KVM || echo 'no KVM, slow')); waiting up to ${limit}s for \"$marker\""
waited=0
until grep -q "$marker" "$log"; do
grep -q "Kernel panic" "$log" && fail "kernel panic"
kill -0 "$qemu" 2>/dev/null || fail "QEMU exited before the system finished booting"
[ "$waited" -lt "$limit" ] || fail "no \"$marker\" after ${limit}s"
sleep 5
waited=$((waited + 5))
done

kill "$qemu" 2>/dev/null || true
echo "Booted in about ${waited}s:"
grep -m 1 "Linux version" "$log" || true
grep -m 1 "OpenRC" "$log" || true
168 changes: 152 additions & 16 deletions .github/workflows/build-iso.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,155 @@
name: Build ISO
name: CI

on: [workflow_dispatch]
# Every push and pull request runs the tests. The full ISO build (hours: the
# kernel alone is most of it) runs for master, for version tags, and on
# demand: Actions → CI → Run workflow, or `gh workflow run build-iso.yml --ref <branch>`.
# A version tag (git tag v1.2 && git push --tags) also publishes the ISO as a
# GitHub release, once it has booted in the boot test.
on:
push:
branches: ["**"]
tags: ["v*"]
pull_request:
workflow_dispatch:

permissions:
contents: read

# A newer push to the same branch supersedes a build in progress.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }}

jobs:
container-job:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Container Build Step
uses: ./
id: container
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: sigma-linux
path: ${{ github.workspace }}/cache/sigma-linux.iso
compression-level: 0
test:
name: Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

# In Alpine, like the build: the APKBUILD reader runs them through its sh.
- name: Unit tests and build plan
run: >
docker run --rm -v "$PWD:/app" -w /app alpine:edge
sh -c 'apk add --no-cache ruby ruby-minitest >/dev/null && ruby test/run.rb && ./sigma build --plan'

iso:
name: ISO
needs: test
if: >
github.event_name == 'workflow_dispatch' ||
github.ref == 'refs/heads/master' ||
startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
timeout-minutes: 355 # the hosted runner's hard limit is 360
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

# The kernel's build tree peaks at ~20 GB and the image adds ~10 GB; the
# runner starts with less free than that.
- name: Free disk space
run: |
df -h /
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /usr/local/.ghcup \
/opt/hostedtoolcache/CodeQL /usr/local/share/boost /usr/share/swift \
/usr/local/share/powershell /usr/local/share/chromium /usr/lib/jvm
sudo docker image prune --all --force > /dev/null
df -h /

- name: Ruby
run: command -v ruby || { sudo apt-get update -q && sudo apt-get install -y -q ruby; }

# Compiled objects from earlier runs, the kernel's especially. Saved
# under a new key every run; the restore takes the most recent one.
- name: Restore ccache
uses: actions/cache/restore@v6
with:
path: cache/ccache
key: ccache-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: ccache-

# Same command as on a workstation: sigma builds its container image and
# runs the pipeline in it. All cores are ours here, and the ccache cap
# keeps the saved cache within the repository's 10 GB of Actions cache.
# The signing key is made fresh for this run and never leaves it.
- name: Build
id: build
timeout-minutes: 320
run: ./sigma build --set jobs=$(nproc) --set packages.ccache_size=5G

# On a timeout the step's process dies but its container may not.
- name: Stop the build container
if: always()
run: docker ps -q | xargs -r docker kill

# Also after a failure or a timeout: the next run picks up where this one stopped.
- name: Save ccache
if: always() && steps.build.outcome != 'skipped'
uses: actions/cache/save@v6
with:
path: cache/ccache
key: ccache-${{ github.run_id }}-${{ github.run_attempt }}

- name: Checksum
run: cd out && sha256sum sigma-linux.iso | tee sigma-linux.iso.sha256

- name: Upload ISO
uses: actions/upload-artifact@v7
with:
name: sigma-linux
path: |
out/sigma-linux.iso
out/sigma-linux.iso.sha256
compression-level: 0
retention-days: 14

- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
sudo apt-get update -q && sudo apt-get install -y -q --no-install-recommends qemu-system-x86

- name: Boot test
timeout-minutes: 15
run: sh .github/boot-test.sh

- name: Upload logs
if: failure() || cancelled()
uses: actions/upload-artifact@v7
with:
name: logs
path: |
cache/logs/
!cache/logs/latest
if-no-files-found: ignore
retention-days: 7

release:
name: Release
needs: iso
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v8
with:
name: sigma-linux
path: out

- name: Publish
env:
GH_TOKEN: ${{ github.token }}
run: |
size=$(stat -c %s out/sigma-linux.iso)
if [ "$size" -ge 2147483648 ]; then
echo "::error::The ISO is $((size / 1048576)) MiB; GitHub release assets must be under 2 GiB."
exit 1
fi
gh release create "$GITHUB_REF_NAME" out/sigma-linux.iso out/sigma-linux.iso.sha256 \
--repo "$GITHUB_REPOSITORY" --title "Sigma Linux $GITHUB_REF_NAME" --generate-notes
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
*.swp
aports/
cache*/
out/
profile/repo
profile/apk/sigma-rootfs/rootfs.tar.gz
src/config.override.sh
config/local.yml
56 changes: 27 additions & 29 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
# Sigma Linux build environment.
#
# Nothing is copied in: `./sigma` mounts the checkout at /app and runs itself
# inside, and everything worth keeping (downloads, ccache, signing key, the
# local repository) lives in ./cache on the host, so this image stays a pure
# toolbox that is cheap to rebuild.
FROM alpine:edge

# Setup packages
RUN printf "http://dl-cdn.alpinelinux.org/alpine/edge/main\nhttp://dl-cdn.alpinelinux.org/alpine/edge/community\nhttp://dl-cdn.alpinelinux.org/alpine/edge/testing\n" > /etc/apk/repositories
RUN apk update
RUN apk add gcc openssl-dev elfutils-dev git gpg make musl-dev flex bison linux-headers perl mtools netpbm netpbm-extras bc diffutils findutils installkernel python3 sed xz gmp-dev mpc1-dev mpfr-dev # Kernel dependencies
RUN apk add doas alpine-sdk # Alpine SDK and build tools
RUN apk add squashfs-tools xorriso grub grub-efi grub-bios # ISO dependencies
RUN apk add shadow
RUN apk add ruby tar
RUN apk add umount
# RUN apk add clang llvm lld # For kernel built with clang
RUN apk add libx11-dev libxft-dev harfbuzz-dev fontconfig-dev freetype-dev gd-dev glib-dev # xorg/suckless dependencies
RUN apk add libxkbcommon-dev glib-dev wayland-dev pango-dev cairo-dev # wvkbd dependencies
RUN apk add ruby-dev ruby-full ruby-rdoc ruby-bundler
RUN printf '%s\n' \
https://dl-cdn.alpinelinux.org/alpine/edge/main \
https://dl-cdn.alpinelinux.org/alpine/edge/community \
https://dl-cdn.alpinelinux.org/alpine/edge/testing \
> /etc/apk/repositories

# Create build user
RUN adduser -D build -G abuild
RUN addgroup build wheel
# Package builds pull their own makedepends (abuild -r) from the APKBUILDs,
# so only the tools around them are listed here.
RUN apk add --no-cache \
ruby \
alpine-sdk ccache doas openssl \
coreutils tar shadow umount \
squashfs-tools xorriso mtools grub grub-bios grub-efi

# Setup abuild for build user
RUN echo "permit nopass keepenv :wheel" > /etc/doas.conf
USER build
RUN abuild-keygen -i -a -n
# Fix for building helix
RUN git config --global http.postBuffer 1048576000
RUN git config --global http.version HTTP/1.1
USER root
# The unprivileged user abuild runs as. Matching the host user's UID keeps
# files it writes into ./cache owned by that user on the host.
ARG BUILD_UID=1000
RUN adduser -D -u "$BUILD_UID" -G abuild build \
&& addgroup build wheel \
&& printf '%s\n' 'permit nopass root as build' 'permit nopass :wheel' > /etc/doas.conf

# Fix for building helix
RUN git config --global http.postBuffer 1048576000
RUN git config --global http.version HTTP/1.1

CMD ["/bin/sh", "./build.sh"]
ENV SIGMA_CONTAINER=1
WORKDIR /app
CMD ["./sigma", "build"]
Loading
Loading